diff --git a/.gitignore b/.gitignore index fcd045d3..e6630c0ac 100644 --- a/.gitignore +++ b/.gitignore
@@ -163,6 +163,7 @@ /gpu/gles2_conform_test /gyp-mac-tool /internal_gyp +/ios/third_party/gcdwebserver/src /llvm /media/cast/logging/cast_logging_proto_lib.xml /media/cdm/ppapi/api
diff --git a/AUTHORS b/AUTHORS index 91d38d9..8ebdf85 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -109,6 +109,7 @@ Daniel Imms <daniimms@amazon.com> Daniel Johnson <danielj41@gmail.com> Daniel Nishi <dhnishi@gmail.com> +Daniel Platz <daplatz@googlemail.com> Daniel Shaulov <dshaulov@ptc.com> Daniel Trebbien <dtrebbien@gmail.com> Darshini KN <kn.darshini@samsung.com> @@ -450,6 +451,7 @@ Shiliu Wang <aofdwsl@gmail.com> Shiliu Wang <shiliu.wang@intel.com> Shilpa Shri <shilpa.shri@samsung.com> +Shivakumar JM <shiva.jm@samsung.com> Shouqun Liu <shouqun.liu@intel.com> Shreeram Kushwaha <shreeram.k@samsung.com> Shreyas Gopal <shreyas.g@samsung.com> @@ -502,6 +504,7 @@ Vipul Bhasin <vipul.bhasin@gmail.com> Visa Putkinen <v.putkinen@partner.samsung.com> Vivek Galatage <vivek.vg@samsung.com> +Wesley Lancel <wesleylancel@gmail.com> Will Hirsch <chromium@willhirsch.co.uk> William Xie <william.xie@intel.com> Xiang Long <xiang.long@intel.com>
diff --git a/BUILD.gn b/BUILD.gn index c2d5547..e06db5fb 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -63,6 +63,7 @@ "//mojo", "//mojo/common:mojo_common_unittests", "//net:net_unittests", + "//ppapi:ppapi_unittests", "//ppapi/examples", # TODO(GYP): What's the GYP equivalent? "//printing:printing_unittests", "//skia:skia_unittests", @@ -99,6 +100,10 @@ deps += [ "//extensions/shell:app_shell_unittests" ] } + if (!is_android) { + deps += [ "//remoting:remoting_unittests" ] + } + if (!is_win) { deps += [ "//breakpad:symupload" ] } @@ -276,8 +281,6 @@ # components_browsertests TODO(GYP) # device_unittests TODO(GYP) # nacl_loader_unittests TODO(GYP) - # ppapi_unittests TODO(GYP) - # remoting_unittests TODO(GYP) "//base:base_unittests", # PASSES (*) 2/25/2015 "//cc:cc_unittests", # PASSES 2/25/2015 @@ -301,10 +304,12 @@ "//ipc/mojo:ipc_mojo_unittests", # PASSES 2/25/2015 "//jingle:jingle_unittests", # PASSES 2/25/2015 "//media/cast:cast_unittests", # PASSES 2/25/2015 - "//media:media_unittests", # TODO(GYP) MidiManagerTest fails. + "//media:media_unittests", # PASSES 3/3/2015 "//mojo/common:mojo_common_unittests", # PASSES 2/25/2015 "//net:net_unittests", # PASSES 2/25/2015 + "//ppapi:ppapi_unittests", # PASSES 2/26/2015 "//printing:printing_unittests", # PASSES 2/25/2015 + "//remoting:remoting_unittests", # Some crashes. "//sandbox/linux:sandbox_linux_unittests", # PASSES 2/25/2015 "//skia:skia_unittests", # PASSES 2/25/2015 "//sql:sql_unittests", # PASSES 2/25/2015
diff --git a/DEPS b/DEPS index decc1898..cfa9046f 100644 --- a/DEPS +++ b/DEPS
@@ -34,7 +34,7 @@ 'llvm_url': 'http://src.chromium.org/llvm-project', 'llvm_git': 'https://llvm.googlesource.com', 'webkit_trunk': 'http://src.chromium.org/blink/trunk', - 'webkit_revision': 'ed228f8d2b2ef02da74b9fde69990da74643683c', # from svn revision 191074 + 'webkit_revision': '5c8353ceb607814ed0f5cd916599a5ee78b4744f', # from svn revision 191353 'chromium_git': 'https://chromium.googlesource.com', 'chromiumos_git': 'https://chromium.googlesource.com/chromiumos', 'pdfium_git': 'https://pdfium.googlesource.com', @@ -42,12 +42,12 @@ 'boringssl_git': 'https://boringssl.googlesource.com', 'libvpx_revision': '080710f043a2f85e100d508a53749cd321e4b57b', 'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac', - 'skia_revision': 'b675a73c1f3f4a433c4893199a0bd11126dfe130', + 'skia_revision': 'fa77eb1e51b9317ff993d1be504ada173b561e5f', # 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': '369eb13a86b0529acd80b3b73b6c2a796224f3a7', + 'v8_revision': '5308d720c19c1d0d4c59c7e7f9273f5e2e8159d2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling WebRTC # and V8 without interference from each other. @@ -58,12 +58,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '586465264b5d466f34fcac45aea95ae48f3bc27d', + 'angle_revision': '019304886ad8b985d67202edec431407bb1b5c53', # 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': '93b3d0af1b30db55ee42bd2e983f7753153217db', + 'buildtools_revision': 'd4dd4f79f60bf019625b3a1436979b0a42c892df', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -95,7 +94,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': 'f4113241ff6535697cbb8646aa0436f332c16779', + 'nacl_revision': '19f11aa481261f38f2a1e9a04e41a7e12aa70e32', } # Only these hosts are allowed for dependencies in this DEPS file. @@ -135,7 +134,7 @@ Var('chromium_git') + '/chromium/blink.git' + '@' + Var('webkit_revision'), 'src/third_party/icu': - Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'df1bf389ea55d8e5b87cfb834705f5f9b7c251eb', + Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'eda9e75b1fa17f57ffa369ee3543a2301b68d0a9', 'src/third_party/libexif/sources': Var('chromium_git') + '/chromium/deps/libexif/sources.git' + '@' + 'ed98343daabd7b4497f97fda972e132e6877c48a', @@ -159,10 +158,10 @@ Var('chromium_git') + '/external/snappy.git' + '@' + '762bb32f0c9d2f31ba4958c7c0933d22e80c20bf', 'src/tools/grit': - Var('chromium_git') + '/external/grit-i18n.git' + '@' + 'a5890a8118c0c80cc0560e6d8d5cf65e5d725509', # from svn revision 185 + Var('chromium_git') + '/external/grit-i18n.git' + '@' + '0287c187b11ed53590254e4d817e836a44a7a1a7', # from svn revision 186 'src/tools/gyp': - Var('chromium_git') + '/external/gyp.git' + '@' + '34640080d08ab2a37665512e52142947def3056d', # from svn revision 2034 + Var('chromium_git') + '/external/gyp.git' + '@' + '4a9b712d5cb4a5ba7a9950128a7219569caf7263', 'src/tools/swarming_client': Var('chromium_git') + '/external/swarming.client.git' + '@' + Var('swarming_revision'), @@ -207,7 +206,7 @@ Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'f5698b4f3e3e8eacad18d77cf69882fe14015de5', 'src/third_party/libjingle/source/talk': - Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'fbd8fd2847eb747d88dac20b1d5d723bd41f8b08', + Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '8fe2b9688185c0d290c565e6714e57e974ad4c79', 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/usrsctplib.git' + '@' + '13718c7b9fd376fde092cbd3c5347d15059ac652', # from svn revision 9167 @@ -231,7 +230,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '093c83b9ef8dab80548107376ed82fbe44e277a7', + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'f30d5eccc9edba6fbd14a0a198cef4c0df517908', 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'), @@ -345,6 +344,9 @@ Var('chromium_git') + '/external/omaha.git' + '@' + '098c7a3d157218dab4eed595e8f2fbe5a20a0bae', }, 'ios': { + 'src/ios/third_party/gcdwebserver/src': + Var('chromium_git') + '/external/github.com/swisspol/GCDWebServer.git' + '@' + '18889793b75d7ee593d62ac88997caad850acdb6', + 'src/third_party/google_toolbox_for_mac/src': Var('chromium_git') + '/external/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'), @@ -404,7 +406,7 @@ # For Linux and Chromium OS. 'src/third_party/cros_system_api': - Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '01a94923ff6654c584cf755dbe579145d828a6e6', + Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'c5bdf1006816594881f96840c21deeb90794969b', # Note that this is different from Android's freetype repo. 'src/third_party/freetype2/src':
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py index ad391d3c..8b642c4 100755 --- a/PRESUBMIT_test.py +++ b/PRESUBMIT_test.py
@@ -775,5 +775,39 @@ bot, master, PRESUBMIT.GetTryServerMasterForBot(bot))) +class UserMetricsActionTest(unittest.TestCase): + def testUserMetricsActionInActions(self): + input_api = MockInputApi() + file_with_user_action = 'file_with_user_action.cc' + contents_with_user_action = [ + 'base::UserMetricsAction("AboutChrome")' + ] + + input_api.files = [MockFile(file_with_user_action, + contents_with_user_action)] + + self.assertEqual( + [], PRESUBMIT._CheckUserActionUpdate(input_api, MockOutputApi())) + + + def testUserMetricsActionNotAddedToActions(self): + input_api = MockInputApi() + file_with_user_action = 'file_with_user_action.cc' + contents_with_user_action = [ + 'base::UserMetricsAction("NotInActionsXml")' + ] + + input_api.files = [MockFile(file_with_user_action, + contents_with_user_action)] + + output = PRESUBMIT._CheckUserActionUpdate(input_api, MockOutputApi()) + self.assertEqual( + ('File %s line %d: %s is missing in ' + 'tools/metrics/actions/actions.xml. Please run ' + 'tools/metrics/actions/extract_actions.py to update.' + % (file_with_user_action, 1, 'NotInActionsXml')), + output[0].message) + + if __name__ == '__main__': unittest.main()
diff --git a/PRESUBMIT_test_mocks.py b/PRESUBMIT_test_mocks.py index 03d9232..8e15d8c 100644 --- a/PRESUBMIT_test_mocks.py +++ b/PRESUBMIT_test_mocks.py
@@ -32,6 +32,9 @@ def AffectedSourceFiles(self, file_filter=None): return self.files + def LocalPaths(self): + return self.files + def PresubmitLocalPath(self): return os.path.dirname(__file__) @@ -62,22 +65,22 @@ return self.message class PresubmitError(PresubmitResult): - def __init__(self, message, items, long_text=''): + def __init__(self, message, items=None, long_text=''): MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) self.type = 'error' class PresubmitPromptWarning(PresubmitResult): - def __init__(self, message, items, long_text=''): + def __init__(self, message, items=None, long_text=''): MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) self.type = 'warning' class PresubmitNotifyResult(PresubmitResult): - def __init__(self, message, items, long_text=''): + def __init__(self, message, items=None, long_text=''): MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) self.type = 'notify' class PresubmitPromptOrNotify(PresubmitResult): - def __init__(self, message, items, long_text=''): + def __init__(self, message, items=None, long_text=''): MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) self.type = 'promptOrNotify' @@ -103,6 +106,14 @@ def LocalPath(self): return self._local_path + def rfind(self, p): + """os.path.basename is called on MockFile so we need an rfind method.""" + return self._local_path.rfind(p) + + def __getitem__(self, i): + """os.path.basename is called on MockFile so we need a get method.""" + return self._local_path[i] + class MockAffectedFile(MockFile): def AbsoluteLocalPath(self):
diff --git a/WATCHLISTS b/WATCHLISTS index d4e63d908..dc113fc 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -81,6 +81,11 @@ '|content/common/gpu/client/' \ '|webkit/common/gpu/' }, + 'auto_bisect': { + 'filepath': 'tools/run-bisect-perf-regression.py'\ + '|tools/run-perf-test.cfg'\ + '|tools/auto_bisect/' + }, 'autofill': { 'filepath': 'chrome/browser/autofill/|'\ 'chrome/browser/resources/options/autofill_|'\ @@ -576,7 +581,8 @@ '|chrome/browser/automation/automation_provider_json' }, 'remoting': { - 'filepath': 'remoting/', + 'filepath': 'remoting/' \ + '|testing/chromoting' }, 'rlz_id': { 'filepath' :'rlz/lib/machine_id.cc|'\ @@ -826,6 +832,7 @@ 'piman+watch@chromium.org', 'sievers+watch@chromium.org', 'kalyan.kondapally@intel.com'], + 'auto_bisect': ['auto-bisect-reviews@chromium.org'], 'autofill': ['estade+watch@chromium.org', 'rouslan+autofillwatch@chromium.org'], 'automation': ['robertshield@chromium.org'],
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index 0bddaf6..fb89fc6f 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -139,7 +139,14 @@ DISALLOW_COPY_AND_ASSIGN(AwAccessTokenStore); }; -} // namespace +void CallbackPermisisonStatusWrapper( + const base::Callback<void(content::PermissionStatus)>& callback, + bool allowed) { + callback.Run(allowed ? content::PERMISSION_STATUS_GRANTED + : content::PERMISSION_STATUS_DENIED); +} + +} // anonymous namespace std::string AwContentBrowserClient::GetAcceptLangsImpl() { // Start with the currnet locale. @@ -380,7 +387,7 @@ int bridge_id, const GURL& requesting_frame, bool user_gesture, - const base::Callback<void(bool)>& result_callback) { + const base::Callback<void(content::PermissionStatus)>& callback) { int render_process_id = web_contents->GetRenderProcessHost()->GetID(); int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID(); GURL origin = requesting_frame.GetOrigin(); @@ -391,19 +398,20 @@ case content::PERMISSION_GEOLOCATION: if (!delegate) { DVLOG(0) << "Dropping GeolocationPermission request"; - result_callback.Run(false); + callback.Run(content::PERMISSION_STATUS_DENIED); return; } - delegate->RequestGeolocationPermission(origin, result_callback); + delegate->RequestGeolocationPermission( + origin, base::Bind(&CallbackPermisisonStatusWrapper, callback)); break; case content::PERMISSION_PROTECTED_MEDIA_IDENTIFIER: if (!delegate) { DVLOG(0) << "Dropping ProtectedMediaIdentifierPermission request"; - result_callback.Run(false); + callback.Run(content::PERMISSION_STATUS_DENIED); return; } - delegate->RequestProtectedMediaIdentifierPermission(origin, - result_callback); + delegate->RequestProtectedMediaIdentifierPermission( + origin, base::Bind(&CallbackPermisisonStatusWrapper, callback)); break; case content::PERMISSION_MIDI_SYSEX: case content::PERMISSION_NOTIFICATIONS:
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h index e5d87497..cae1bf3 100644 --- a/android_webview/browser/aw_content_browser_client.h +++ b/android_webview/browser/aw_content_browser_client.h
@@ -112,7 +112,7 @@ int bridge_id, const GURL& requesting_frame, bool user_gesture, - const base::Callback<void(bool)>& result_callback) override; + const base::Callback<void(content::PermissionStatus)>& callback) override; void CancelPermissionRequest(content::PermissionType permission, content::WebContents* web_contents, int bridge_id,
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java b/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java index 1826e78..3f0d514d 100644 --- a/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java +++ b/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java
@@ -584,6 +584,14 @@ return mAwSettings.getMixedContentMode(); } + public void setOffscreenPreRaster(boolean enabled) { + mAwSettings.setOffscreenPreRaster(enabled); + } + + public boolean getOffscreenPreRaster() { + return mAwSettings.getOffscreenPreRaster(); + } + @Override public void setVideoOverlayForEmbeddedEncryptedVideoEnabled(boolean flag) { mAwSettings.setVideoOverlayForEmbeddedVideoEnabled(flag);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index c95137c..9384385 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -49,7 +49,6 @@ import org.chromium.content.browser.ContentViewCore; import org.chromium.content.browser.ContentViewStatics; import org.chromium.content.browser.SmartClipProvider; -import org.chromium.content.browser.WebContentsObserver; import org.chromium.content.common.CleanupReference; import org.chromium.content_public.browser.GestureStateListener; import org.chromium.content_public.browser.JavaScriptCallback; @@ -184,13 +183,14 @@ /** * Visual state callback, see {@link #insertVisualStateCallback} for details. * - * <p>The {@code requestId} is the id passed to {@link AwContents#insertVisualStateCallback} - * which can be used to match requests with the corresponding callbacks. */ @VisibleForTesting public abstract static class VisualStateCallback { + /** + * @param requestId the id passed to {@link AwContents#insertVisualStateCallback} + * which can be used to match requests with the corresponding callbacks. + */ public abstract void onComplete(long requestId); - public abstract void onFailure(long requestId); } private long mNativeAwContents; @@ -204,7 +204,7 @@ private NavigationController mNavigationController; private final AwContentsClient mContentsClient; private final AwContentViewClient mContentViewClient; - private WebContentsObserver mWebContentsObserver; + private AwWebContentsObserver mWebContentsObserver; private final AwContentsClientBridge mContentsClientBridge; private final AwWebContentsDelegateAdapter mWebContentsDelegate; private final AwContentsIoThreadClient mIoThreadClient; @@ -227,6 +227,8 @@ private boolean mHasRequestedVisitedHistoryFromClient; // TODO(boliu): This should be in a global context, not per webview. private final double mDIPScale; + // Whether the WebView has attempted to do any load (including uncommitted loads). + private boolean mDidAttemptLoad = false; // The base background color, i.e. not accounting for any CSS body from the current page. private int mBaseBackgroundColor = Color.WHITE; @@ -269,6 +271,8 @@ // when in this state. private boolean mTemporarilyDetached; + private Handler mHandler; + // True when this AwContents has been destroyed. // Do not use directly, call isDestroyed() instead. private boolean mIsDestroyed = false; @@ -601,6 +605,7 @@ mContainerView = containerView; mContainerView.setWillNotDraw(false); + mHandler = new Handler(); mContext = context; mInternalAccessAdapter = internalAccessAdapter; mNativeGLDelegate = nativeGLDelegate; @@ -843,7 +848,7 @@ private void installWebContentsObserver() { if (mWebContentsObserver != null) { - mWebContentsObserver.detachFromWebContents(); + mWebContentsObserver.destroy(); } mWebContentsObserver = new AwWebContentsObserver(mWebContents, mContentsClient); } @@ -908,6 +913,9 @@ if (wasWindowFocused) onWindowFocusChanged(wasWindowFocused); if (wasFocused) onFocusChanged(true, 0, null); + // Popups are always assumed as having made a load attempt. + mDidAttemptLoad = true; + // Restore injected JavaScript interfaces. for (Map.Entry<String, Pair<Object, Class>> entry : javascriptInterfaces.entrySet()) { @SuppressWarnings("unchecked") @@ -936,7 +944,7 @@ nativeOnDetachedFromWindow(mNativeAwContents); } mIsDestroyed = true; - new Handler().post(new Runnable() { + mHandler.post(new Runnable() { @Override public void run() { destroyNatives(); @@ -951,7 +959,7 @@ if (mCleanupReference != null) { assert mNativeAwContents != 0; - mWebContentsObserver.detachFromWebContents(); + mWebContentsObserver.destroy(); mWebContentsObserver = null; mContentViewCore.destroy(); mContentViewCore = null; @@ -1239,6 +1247,19 @@ return url; } + /** + * Gets the last committed URL. It represents the current page that is + * displayed in WebContents. It represents the current security context. + * + * @return The URL of the current page or null if it's empty. + */ + public String getLastCommittedUrl() { + if (isDestroyed()) return null; + String url = mWebContents.getLastCommittedUrl(); + if (url == null || url.trim().isEmpty()) return null; + return url; + } + public void requestFocus() { mAwViewMethods.requestFocus(); } @@ -1838,6 +1859,11 @@ return ports; } + public boolean hasAccessedInitialDocument() { + if (isDestroyed()) return false; + return mWebContents.hasAccessedInitialDocument(); + } + //-------------------------------------------------------------------------------------------- // View and ViewGroup method implementations //-------------------------------------------------------------------------------------------- @@ -2067,11 +2093,21 @@ * @param requestId an id that will be returned from the callback invocation to allow * callers to match requests with callbacks. * @param callback the callback to be inserted + * @throw IllegalStateException if this method is invoked after {@link #destroy()} has been + * called. */ public void insertVisualStateCallback(long requestId, VisualStateCallback callback) { + if (isDestroyed()) throw new IllegalStateException( + "insertVisualStateCallback cannot be called after the WebView has been destroyed"); nativeInsertVisualStateCallback(mNativeAwContents, requestId, callback); } + public boolean getDidAttemptLoad() { + if (mDidAttemptLoad) return mDidAttemptLoad; + mDidAttemptLoad = mWebContentsObserver.hasStartedAnyProvisionalLoad(); + return mDidAttemptLoad; + } + //-------------------------------------------------------------------------------------------- // Methods called from native via JNI //-------------------------------------------------------------------------------------------- @@ -2184,17 +2220,13 @@ */ @CalledByNative public void invokeVisualStateCallback( - final VisualStateCallback callback, final long requestId, final boolean result) { + final VisualStateCallback callback, final long requestId) { // Posting avoids invoking the callback inside invoking_composite_ // (see synchronous_compositor_impl.cc and crbug/452530). - mContainerView.getHandler().post(new Runnable() { + mHandler.post(new Runnable() { @Override public void run() { - if (result) { - callback.onComplete(requestId); - } else { - callback.onFailure(requestId); - } + callback.onComplete(requestId); } }); }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java index a0003e66..bf5af89 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java +++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java
@@ -37,4 +37,8 @@ // Call in response to a prior runFileChooser call. protected static native void nativeFilesSelectedInChooser(int processId, int renderId, int modeFlags, String[] filePath, String[] displayName); + + @Override + @CalledByNative + public abstract void navigationStateChanged(int flags); }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java index 3f2c707d..5e37d99 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java +++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
@@ -11,6 +11,7 @@ import android.os.Handler; import android.os.Message; import android.provider.MediaStore; +import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.View; @@ -19,6 +20,7 @@ import org.chromium.base.ContentUriUtils; import org.chromium.base.ThreadUtils; +import org.chromium.content_public.browser.InvalidateTypes; /** * Adapts the AwWebContentsDelegate interface to the AwContentsClient interface. @@ -213,6 +215,22 @@ } @Override + public void navigationStateChanged(int flags) { + if ((flags & InvalidateTypes.URL) != 0 + && mAwContents.hasAccessedInitialDocument() + && mAwContents.getDidAttemptLoad()) { + // Hint the client to show the last committed url, as it may be unsafe to show + // the pending entry. + String url = mAwContents.getLastCommittedUrl(); + url = TextUtils.isEmpty(url) ? "about:blank" : url; + mContentsClient.onPageStarted(url); + mContentsClient.onLoadResource(url); + mContentsClient.onProgressChanged(100); + mContentsClient.onPageFinished(url); + } + } + + @Override public void toggleFullscreenModeForTab(boolean enterFullscreen) { if (enterFullscreen) { mContentViewClient.enterFullscreen();
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java index c3c381a6..926d77f 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java +++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
@@ -4,8 +4,8 @@ package org.chromium.android_webview; -import org.chromium.content.browser.WebContentsObserver; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.net.NetError; /** @@ -13,12 +13,17 @@ */ public class AwWebContentsObserver extends WebContentsObserver { private final AwContentsClient mAwContentsClient; + private boolean mHasStartedAnyProvisionalLoad = false; public AwWebContentsObserver(WebContents webContents, AwContentsClient awContentsClient) { super(webContents); mAwContentsClient = awContentsClient; } + boolean hasStartedAnyProvisionalLoad() { + return mHasStartedAnyProvisionalLoad; + } + @Override public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) { String unreachableWebDataUrl = AwContentsStatics.getUnreachableWebDataUrl(); @@ -55,7 +60,7 @@ @Override public void didNavigateMainFrame(String url, String baseUrl, - boolean isNavigationToDifferentPage, boolean isFragmentNavigation) { + boolean isNavigationToDifferentPage, boolean isFragmentNavigation, int statusCode) { // This is here to emulate the Classic WebView firing onPageFinished for main frame // navigations where only the hash fragment changes. if (isFragmentNavigation) { @@ -67,4 +72,15 @@ public void didNavigateAnyFrame(String url, String baseUrl, boolean isReload) { mAwContentsClient.doUpdateVisitedHistory(url, isReload); } + + @Override + public void didStartProvisionalLoadForFrame( + long frameId, + long parentFrameId, + boolean isMainFrame, + String validatedUrl, + boolean isErrorPage, + boolean isIframeSrcdoc) { + mHasStartedAnyProvisionalLoad = true; + } }
diff --git a/android_webview/java_library_common.mk b/android_webview/java_library_common.mk index 36da45d..e756804 100644 --- a/android_webview/java_library_common.mk +++ b/android_webview/java_library_common.mk
@@ -55,6 +55,7 @@ $(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 \ +$(call intermediates-dir-for,GYP,shared)/enums/invalidate_types_java/org/chromium/content_public/browser/InvalidateTypes.java \ $(call intermediates-dir-for,GYP,shared)/enums/navigation_controller_java/org/chromium/content_public/browser/navigation_controller/LoadURLType.java \ $(call intermediates-dir-for,GYP,shared)/enums/navigation_controller_java/org/chromium/content_public/browser/navigation_controller/UserAgentOverrideOption.java \ $(call intermediates-dir-for,GYP,shared)/enums/popup_item_type_java/org/chromium/content/browser/input/PopupItemType.java \
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java index ef65bfe..08c6ebc 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
@@ -21,7 +21,9 @@ import org.chromium.content.browser.test.util.CallbackHelper; import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper; import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.net.test.util.TestWebServer; import java.lang.annotation.Annotation; import java.lang.reflect.Method; @@ -509,4 +511,78 @@ }); } + /** + * Loads the main html then triggers the popup window. + */ + public void triggerPopup(final AwContents parentAwContents, + TestAwContentsClient parentAwContentsClient, TestWebServer testWebServer, + String mainHtml, String popupHtml, String popupPath, String triggerScript) + throws Exception { + enableJavaScriptOnUiThread(parentAwContents); + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + parentAwContents.getSettings().setSupportMultipleWindows(true); + parentAwContents.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); + } + }); + + final String parentUrl = testWebServer.setResponse("/popupParent.html", mainHtml, null); + if (popupHtml != null) { + testWebServer.setResponse(popupPath, popupHtml, null); + } else { + testWebServer.setResponseWithNoContentStatus(popupPath); + } + + parentAwContentsClient.getOnCreateWindowHelper().setReturnValue(true); + loadUrlSync(parentAwContents, parentAwContentsClient.getOnPageFinishedHelper(), parentUrl); + + TestAwContentsClient.OnCreateWindowHelper onCreateWindowHelper = + parentAwContentsClient.getOnCreateWindowHelper(); + int currentCallCount = onCreateWindowHelper.getCallCount(); + parentAwContents.evaluateJavaScript(triggerScript, null); + onCreateWindowHelper.waitForCallback( + currentCallCount, 1, WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + /** + * POD object for holding references to helper objects of a popup window. + */ + public static class PopupInfo { + public final TestAwContentsClient popupContentsClient; + public final AwTestContainerView popupContainerView; + public final AwContents popupContents; + public PopupInfo(TestAwContentsClient popupContentsClient, + AwTestContainerView popupContainerView, AwContents popupContents) { + this.popupContentsClient = popupContentsClient; + this.popupContainerView = popupContainerView; + this.popupContents = popupContents; + } + } + + /** + * Supplies the popup window with AwContents then waits for the popup window to finish loading. + */ + public PopupInfo connectPendingPopup(final AwContents parentAwContents) throws Exception { + TestAwContentsClient popupContentsClient; + AwTestContainerView popupContainerView; + final AwContents popupContents; + popupContentsClient = new TestAwContentsClient(); + popupContainerView = createAwTestContainerViewOnMainSync(popupContentsClient); + popupContents = popupContainerView.getAwContents(); + enableJavaScriptOnUiThread(popupContents); + + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + parentAwContents.supplyContentsForPopup(popupContents); + } + }); + + OnPageFinishedHelper onPageFinishedHelper = popupContentsClient.getOnPageFinishedHelper(); + int callCount = onPageFinishedHelper.getCallCount(); + onPageFinishedHelper.waitForCallback(callCount, 1, WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); + + return new PopupInfo(popupContentsClient, popupContainerView, popupContents); + } }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java index 58378f317aa..109e29c 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java
@@ -87,15 +87,16 @@ String baseUrl = null; boolean navigationToDifferentPage = true; boolean fragmentNavigation = true; + int httpStatusCode = 200; callCount = mContentsClient.getOnPageFinishedHelper().getCallCount(); mWebContentsObserver.didNavigateMainFrame(EXAMPLE_URL, baseUrl, - !navigationToDifferentPage, fragmentNavigation); + !navigationToDifferentPage, fragmentNavigation, httpStatusCode); assertEquals("onPageFinished should be called for main frame fragment navigations.", callCount + 1, mContentsClient.getOnPageFinishedHelper().getCallCount()); callCount = mContentsClient.getOnPageFinishedHelper().getCallCount(); mWebContentsObserver.didNavigateMainFrame(EXAMPLE_URL, baseUrl, - !navigationToDifferentPage, !fragmentNavigation); + !navigationToDifferentPage, !fragmentNavigation, httpStatusCode); assertEquals("onPageFinished should be called only for main frame fragment navigations.", callCount, mContentsClient.getOnPageFinishedHelper().getCallCount()); }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java index edb6c7a..d363c5c 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java
@@ -279,4 +279,84 @@ webServer.shutdown(); } } + + @MediumTest + @Feature({"AndroidWebView"}) + public void testOnPageFinishedNotCalledOnDomModificationForBlankWebView() throws Throwable { + TestWebServer webServer = TestWebServer.start(); + try { + doTestOnPageFinishedNotCalledOnDomMutation(webServer); + } finally { + webServer.shutdown(); + } + } + + @MediumTest + @Feature({"AndroidWebView"}) + public void testOnPageFinishedCalledOnDomModificationAfterNonCommittedLoad() throws Throwable { + enableJavaScriptOnUiThread(mAwContents); + TestWebServer webServer = TestWebServer.start(); + try { + final String noContentUrl = webServer.setResponseWithNoContentStatus("/nocontent.html"); + TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = + mContentsClient.getOnPageFinishedHelper(); + final int onPageFinishedCallCount = onPageFinishedHelper.getCallCount(); + loadUrlAsync(mAwContents, noContentUrl); + // Mutate DOM. + executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, + "document.body.innerHTML='Hello, World!'"); + onPageFinishedHelper.waitForCallback(onPageFinishedCallCount); + assertEquals("about:blank", onPageFinishedHelper.getUrl()); + } finally { + webServer.shutdown(); + } + } + + @MediumTest + @Feature({"AndroidWebView"}) + public void testOnPageFinishedNotCalledOnDomModificationAfterLoadUrl() throws Throwable { + TestWebServer webServer = TestWebServer.start(); + try { + final String testUrl = + webServer.setResponse("/test.html", CommonResources.ABOUT_HTML, null); + loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), testUrl); + doTestOnPageFinishedNotCalledOnDomMutation(webServer); + } finally { + webServer.shutdown(); + } + } + + @MediumTest + @Feature({"AndroidWebView"}) + public void testOnPageFinishedNotCalledOnDomModificationAfterLoadData() + throws Throwable { + TestWebServer webServer = TestWebServer.start(); + try { + loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), + CommonResources.ABOUT_HTML, "text/html", false); + doTestOnPageFinishedNotCalledOnDomMutation(webServer); + } finally { + webServer.shutdown(); + } + } + + private void doTestOnPageFinishedNotCalledOnDomMutation(TestWebServer webServer) + throws Throwable { + enableJavaScriptOnUiThread(mAwContents); + TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = + mContentsClient.getOnPageFinishedHelper(); + final int onPageFinishedCallCount = onPageFinishedHelper.getCallCount(); + // Mutate DOM. + executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, + "document.body.innerHTML='Hello, World!'"); + // Rather than wait a fixed time to see that an onPageFinished callback isn't issued + // we load another valid page. Since callbacks arrive sequentially if the next callback + // we get is for the synchronizationUrl we know that DOM mutation did not schedule + // a callback for the iframe. + final String syncUrl = webServer.setResponse("/sync.html", "", null); + loadUrlAsync(mAwContents, syncUrl); + onPageFinishedHelper.waitForCallback(onPageFinishedCallCount); + assertEquals(syncUrl, onPageFinishedHelper.getUrl()); + assertEquals(onPageFinishedCallCount + 1, onPageFinishedHelper.getCallCount()); + } }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/CommandLineTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/CommandLineTest.java deleted file mode 100644 index fa1b325..0000000 --- a/android_webview/javatests/src/org/chromium/android_webview/test/CommandLineTest.java +++ /dev/null
@@ -1,55 +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. - -package org.chromium.android_webview.test; - -import android.os.Build; -import android.test.suitebuilder.annotation.SmallTest; - -import org.chromium.android_webview.AwBrowserProcess; -import org.chromium.base.CommandLine; -import org.chromium.base.test.util.Feature; -import org.chromium.base.test.util.MinAndroidSdkLevel; - -/** - * Test suite for setting by the command line. - */ -@MinAndroidSdkLevel(Build.VERSION_CODES.KITKAT) -public class CommandLineTest extends AwTestBase { - @Override - protected boolean needsBrowserProcessStarted() { - return false; - } - - @SmallTest - @Feature({"AndroidWebView"}) - public void testSetupCommandLine() throws Exception { - // The commandline starts off in Java: - CommandLine cl = CommandLine.getInstance(); - assertFalse(cl.isNativeImplementation()); - - // We can add a switch. - assertFalse(cl.hasSwitch("magic-switch")); - cl.appendSwitchWithValue("magic-switch", "magic"); - assertTrue(cl.hasSwitch("magic-switch")); - assertEquals("magic", cl.getSwitchValue("magic-switch")); - - // Setup Chrome. - AwBrowserProcess.loadLibrary(); - - // Now we should have switched to a native backed command line: - cl = CommandLine.getInstance(); - assertTrue(cl.isNativeImplementation()); - - // Our first switch is still there. - assertTrue(cl.hasSwitch("magic-switch")); - assertEquals("magic", cl.getSwitchValue("magic-switch")); - - // And we can add another one. - assertFalse(cl.hasSwitch("more-magic-switch")); - cl.appendSwitchWithValue("more-magic-switch", "more-magic"); - assertTrue(cl.hasSwitch("more-magic-switch")); - assertEquals("more-magic", cl.getSwitchValue("more-magic-switch")); - } -}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java index a81e9070..16d6b55 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
@@ -8,15 +8,12 @@ import android.test.suitebuilder.annotation.SmallTest; import org.chromium.android_webview.AwContents; -import org.chromium.android_webview.test.util.AwTestTouchUtils; import org.chromium.android_webview.test.util.CommonResources; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.MinAndroidSdkLevel; +import org.chromium.content.browser.test.util.TestCallbackHelperContainer; import org.chromium.net.test.util.TestWebServer; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; - /** * Tests for pop up window flow. */ @@ -25,9 +22,6 @@ private TestAwContentsClient mParentContentsClient; private AwTestContainerView mParentContainerView; private AwContents mParentContents; - private TestAwContentsClient mPopupContentsClient; - private AwTestContainerView mPopupContainerView; - private AwContents mPopupContents; private TestWebServer mWebServer; private static final String POPUP_TITLE = "Popup Window"; @@ -49,67 +43,45 @@ super.tearDown(); } - private void triggerPopup() throws Throwable { - enableJavaScriptOnUiThread(mParentContents); - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - mParentContents.getSettings().setSupportMultipleWindows(true); - mParentContents.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); - } - }); - + @SmallTest + @Feature({"AndroidWebView"}) + public void testPopupWindow() throws Throwable { final String popupPath = "/popup.html"; - - final String parentPageHtml = CommonResources.makeHtmlPageFrom("", - "<script>" + final String parentPageHtml = CommonResources.makeHtmlPageFrom("", "<script>" + "function tryOpenWindow() {" + " var newWindow = window.open('" + popupPath + "');" - + "}</script>" - + "<a class=\"full_view\" onclick=\"tryOpenWindow();\">Click me!</a>"); + + "}</script>"); + final String popupPageHtml = CommonResources.makeHtmlPageFrom( "<title>" + POPUP_TITLE + "</title>", "This is a popup window"); - final String parentUrl = mWebServer.setResponse("/popupParent.html", parentPageHtml, null); - mWebServer.setResponse(popupPath, popupPageHtml, null); - - mParentContentsClient.getOnCreateWindowHelper().setReturnValue(true); - loadUrlSync(mParentContents, - mParentContentsClient.getOnPageFinishedHelper(), - parentUrl); - - TestAwContentsClient.OnCreateWindowHelper onCreateWindowHelper = - mParentContentsClient.getOnCreateWindowHelper(); - int currentCallCount = onCreateWindowHelper.getCallCount(); - AwTestTouchUtils.simulateTouchCenterOfView(mParentContainerView); - onCreateWindowHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_MS, - TimeUnit.MILLISECONDS); - } - - private void connectPendingPopup() throws Exception { - mPopupContentsClient = new TestAwContentsClient(); - mPopupContainerView = createAwTestContainerViewOnMainSync(mPopupContentsClient); - mPopupContents = mPopupContainerView.getAwContents(); - - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - mParentContents.supplyContentsForPopup(mPopupContents); - } - }); + triggerPopup(mParentContents, mParentContentsClient, mWebServer, parentPageHtml, + popupPageHtml, popupPath, "tryOpenWindow()"); + AwContents popupContents = connectPendingPopup(mParentContents).popupContents; + assertEquals(POPUP_TITLE, getTitleOnUiThread(popupContents)); } @SmallTest @Feature({"AndroidWebView"}) - public void testPopupWindow() throws Throwable { - triggerPopup(); - connectPendingPopup(); - poll(new Callable<Boolean>() { - @Override - public Boolean call() throws Exception { - return POPUP_TITLE.equals(getTitleOnUiThread(mPopupContents)); - } - }); + public void testOnPageFinishedCalledOnDomModificationAfterNavigation() throws Throwable { + final String popupPath = "/popup.html"; + final String parentPageHtml = CommonResources.makeHtmlPageFrom("", "<script>" + + "function tryOpenWindow() {" + + " window.popupWindow = window.open('" + popupPath + "');" + + "}" + + "function modifyDomOfPopup() {" + + " window.popupWindow.document.body.innerHTML = 'Hello from the parent!';" + + "}</script>"); + + triggerPopup(mParentContents, mParentContentsClient, mWebServer, parentPageHtml, + null, popupPath, "tryOpenWindow()"); + TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = + connectPendingPopup(mParentContents).popupContentsClient.getOnPageFinishedHelper(); + final int onPageFinishedCallCount = onPageFinishedHelper.getCallCount(); + executeJavaScriptAndWaitForResult(mParentContents, mParentContentsClient, + "modifyDomOfPopup()"); + onPageFinishedHelper.waitForCallback(onPageFinishedCallCount); + assertEquals("about:blank", onPageFinishedHelper.getUrl()); } }
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 6d86ef3..44db7f1 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
@@ -763,4 +763,90 @@ mMessageObject.waitForMessage(); assertEquals(WORKER_MESSAGE, mMessageObject.getData()); } + + private static final String POPUP_MESSAGE = "from_popup"; + private static final String POPUP_URL = "/popup.html"; + private static final String IFRAME_URL = "/iframe.html"; + private static final String MAIN_PAGE_FOR_POPUP_TEST = "<!DOCTYPE html><html>" + + "<head>" + + " <script>" + + " function createPopup() {" + + " var popupWindow = window.open('" + POPUP_URL + "');" + + " onmessage = function(e) {" + + " popupWindow.postMessage(e.data, '*', e.ports);" + + " };" + + " }" + + " </script>" + + "</head>" + + "</html>"; + + // Sends message and ports to the iframe. + private static final String POPUP_PAGE_WITH_IFRAME = "<!DOCTYPE html><html>" + + "<script>" + + " onmessage = function(e) {" + + " var iframe = document.getElementsByTagName('iframe')[0];" + + " iframe.contentWindow.postMessage('" + POPUP_MESSAGE + "', '*', e.ports);" + + " };" + + "</script>" + + "<body><iframe src='" + IFRAME_URL + "'></iframe></body>" + + "</html>"; + + // Test if WebView can post a message from/to a popup window owning a message port. + @SmallTest + @Feature({"AndroidWebView", "Android-PostMessage"}) + public void testPostMessageToPopup() throws Throwable { + triggerPopup(mAwContents, mContentsClient, mWebServer, MAIN_PAGE_FOR_POPUP_TEST, ECHO_PAGE, + POPUP_URL, "createPopup()"); + connectPendingPopup(mAwContents); + final ChannelContainer channelContainer = new ChannelContainer(); + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + MessagePort[] channel = mAwContents.createMessageChannel(); + channelContainer.set(channel); + channel[0].setWebEventHandler(new MessagePort.WebEventHandler() { + @Override + public void onMessage(String message) { + channelContainer.setMessage(message); + } + }, null); + mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, mWebServer.getBaseUrl(), + new MessagePort[] {channel[1]}); + channel[0].postMessage(HELLO, null); + } + }); + channelContainer.waitForMessage(); + assertEquals(HELLO + JS_MESSAGE, channelContainer.getMessage()); + } + + // Test if WebView can post a message from/to an iframe in a popup window. + @SmallTest + @Feature({"AndroidWebView", "Android-PostMessage"}) + public void testPostMessageToIframeInsidePopup() throws Throwable { + mWebServer.setResponse(IFRAME_URL, ECHO_PAGE, null); + triggerPopup(mAwContents, mContentsClient, mWebServer, MAIN_PAGE_FOR_POPUP_TEST, + POPUP_PAGE_WITH_IFRAME, POPUP_URL, "createPopup()"); + connectPendingPopup(mAwContents); + final ChannelContainer channelContainer = new ChannelContainer(); + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + MessagePort[] channel = mAwContents.createMessageChannel(); + channelContainer.set(channel); + channel[0].setWebEventHandler(new MessagePort.WebEventHandler() { + @Override + public void onMessage(String message) { + channelContainer.setMessage(message); + } + }, null); + mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, mWebServer.getBaseUrl(), + new MessagePort[] {channel[1]}); + channel[0].postMessage(HELLO, null); + } + }); + channelContainer.waitForMessage(); + assertEquals(HELLO + JS_MESSAGE, channelContainer.getMessage()); + } }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java index 3ceeb13..8b1efaa 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java
@@ -6,6 +6,8 @@ import android.graphics.Bitmap; import android.graphics.Color; +import android.graphics.Rect; +import android.os.Build; import android.test.suitebuilder.annotation.SmallTest; import android.view.View; import android.webkit.WebChromeClient; @@ -16,6 +18,7 @@ import org.chromium.android_webview.test.util.GraphicsTestUtils; import org.chromium.android_webview.test.util.JavascriptEventObserver; import org.chromium.base.test.util.Feature; +import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.content.browser.ContentViewCore; import org.chromium.content.browser.test.util.CallbackHelper; import org.chromium.content.browser.test.util.DOMUtils; @@ -28,6 +31,7 @@ /** * Visual state related tests. */ +@MinAndroidSdkLevel(Build.VERSION_CODES.KITKAT) public class VisualStateTest extends AwTestBase { private static final String WAIT_FOR_JS_TEST_URL = @@ -59,11 +63,6 @@ assertEquals(requestId, id); ch.notifyCalled(); } - - @Override - public void onFailure(long id) { - fail("onFailure received"); - } }); } }); @@ -90,11 +89,6 @@ awContentsRef.get().insertVisualStateCallback(requestId, new VisualStateCallback() { @Override - public void onFailure(long id) { - fail("onFailure received"); - } - - @Override public void onComplete(long id) { assertEquals(requestId, id); Bitmap blueScreenshot = GraphicsTestUtils @@ -147,11 +141,6 @@ awContentsRef.get().insertVisualStateCallback(10, new VisualStateCallback() { @Override - public void onFailure(long id) { - fail("onFailure received"); - } - - @Override public void onComplete(long id) { Bitmap blueScreenshot = GraphicsTestUtils.drawAwContents( awContentsRef.get(), 100, 100); @@ -191,11 +180,6 @@ awContents.insertVisualStateCallback(20, new VisualStateCallback() { @Override - public void onFailure(long id) { - fail("onFailure received"); - } - - @Override public void onComplete(long id) { Bitmap redScreenshot = GraphicsTestUtils.drawAwContents( awContents, 100, 100); @@ -229,11 +213,6 @@ super.onPageFinished(url); awContentsRef.get().insertVisualStateCallback(10, new VisualStateCallback() { @Override - public void onFailure(long id) { - fail("onFailure received"); - } - - @Override public void onComplete(long id) { Bitmap blueScreenshot = GraphicsTestUtils.drawAwContents(awContentsRef.get(), 100, 100); @@ -271,11 +250,6 @@ public void run() { awContents.insertVisualStateCallback(20, new VisualStateCallback() { @Override - public void onFailure(long id) { - fail("onFailure received"); - } - - @Override public void onComplete(long id) { // NOTE: We cannot use drawAwContents here because the web contents // are rendered into the custom view while in fullscreen. @@ -310,11 +284,6 @@ super.onPageFinished(url); awContentsRef.get().insertVisualStateCallback(10, new VisualStateCallback() { @Override - public void onFailure(long id) { - fail("onFailure received"); - } - - @Override public void onComplete(long id) { Bitmap blueScreenshot = GraphicsTestUtils.drawAwContents(awContentsRef.get(), 100, 100); @@ -329,11 +298,6 @@ super.onShowCustomView(view, callback); awContentsRef.get().insertVisualStateCallback(20, new VisualStateCallback() { @Override - public void onFailure(long id) { - fail("onFailure received"); - } - - @Override public void onComplete(long id) { // NOTE: We cannot use drawAwContents here because the web contents are // rendered into the custom view while in fullscreen. @@ -361,6 +325,83 @@ assertTrue(testFinishedSignal.await(AwTestBase.WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS)); } + @Feature({"AndroidWebView"}) + @SmallTest + public void testVisualStateCallbackWhenContainerViewDetached() + throws Throwable { + final CountDownLatch readyToEnterFullscreenSignal = new CountDownLatch(1); + final CountDownLatch hasCustomViewSignal = new CountDownLatch(1); + final CountDownLatch testFinishedSignal = new CountDownLatch(1); + + final AtomicReference<AwContents> awContentsRef = new AtomicReference<>(); + final AtomicReference<View> customViewRef = new AtomicReference<>(); + + final TestAwContentsClient awContentsClient = new TestAwContentsClient() { + @Override + public void onPageFinished(String url) { + super.onPageFinished(url); + readyToEnterFullscreenSignal.countDown(); + } + + @Override + public void onShowCustomView( + final View customView, WebChromeClient.CustomViewCallback callback) { + // Please note that we don't attach the custom view to the window here + // (awContentsClient is an instance of TestAwContentsClient, not + // FullScreenVideoTestAwContentsClient). + customView.setClipBounds(new Rect(0, 0, 100, 100)); + customView.measure(100, 100); + customView.layout(0, 0, 100, 100); + customViewRef.set(customView); + hasCustomViewSignal.countDown(); + } + }; + final AwTestContainerView testView = createAwTestContainerViewOnMainSync(awContentsClient); + final AwContents awContents = testView.getAwContents(); + awContentsRef.set(awContents); + final ContentViewCore contentViewCore = testView.getContentViewCore(); + enableJavaScriptOnUiThread(awContents); + awContents.getSettings().setFullscreenSupported(true); + + // JS will notify this observer once it has entered fullscreen. + final JavascriptEventObserver jsObserver = new JavascriptEventObserver(); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + jsObserver.register(contentViewCore, "jsObserver"); + } + }); + + loadUrlSync(awContents, awContentsClient.getOnPageFinishedHelper(), FULLSCREEN_TEST_URL); + + assertTrue(readyToEnterFullscreenSignal.await( + AwTestBase.WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + DOMUtils.clickNode(VisualStateTest.this, contentViewCore, ENTER_FULLSCREEN_CONTROL_ID); + + assertTrue(hasCustomViewSignal.await(AwTestBase.WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + assertTrue(jsObserver.waitForEvent(WAIT_TIMEOUT_MS)); + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + awContents.insertVisualStateCallback(20, new VisualStateCallback() { + @Override + public void onComplete(long id) { + assertFalse(customViewRef.get().isAttachedToWindow()); + // NOTE: We cannot use drawAwContents here because the web contents + // are rendered into the custom view while in fullscreen. + Bitmap redScreenshot = GraphicsTestUtils.drawView( + customViewRef.get(), 100, 100); + assertEquals(Color.RED, redScreenshot.getPixel(50, 50)); + testFinishedSignal.countDown(); + } + }); + } + }); + + assertTrue(testFinishedSignal.await(AwTestBase.WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } + private static final LoadUrlParams createTestPageUrl(String backgroundColor) { return LoadUrlParams.createLoadDataParams( "<html><body bgcolor=" + backgroundColor + "></body></html>", "text/html", false);
diff --git a/android_webview/libwebviewchromium.gypi b/android_webview/libwebviewchromium.gypi index d5da2f0..32b1c95 100644 --- a/android_webview/libwebviewchromium.gypi +++ b/android_webview/libwebviewchromium.gypi
@@ -23,6 +23,7 @@ '../content/content.gyp:console_message_level_java', '../content/content.gyp:content_gamepad_mapping', '../content/content.gyp:gesture_event_type_java', + '../content/content.gyp:invalidate_types_java', '../content/content.gyp:navigation_controller_java', '../content/content.gyp:popup_item_type_java', '../content/content.gyp:result_codes_java',
diff --git a/android_webview/native/aw_autofill_client.cc b/android_webview/native/aw_autofill_client.cc index c0427fa..b9210e5e 100644 --- a/android_webview/native/aw_autofill_client.cc +++ b/android_webview/native/aw_autofill_client.cc
@@ -199,7 +199,7 @@ NOTIMPLEMENTED(); } -void AwAutofillClient::OnUnmaskVerificationResult(bool success) { +void AwAutofillClient::OnUnmaskVerificationResult(GetRealPanResult result) { NOTIMPLEMENTED(); }
diff --git a/android_webview/native/aw_autofill_client.h b/android_webview/native/aw_autofill_client.h index 9881f8d..d8e4651 100644 --- a/android_webview/native/aw_autofill_client.h +++ b/android_webview/native/aw_autofill_client.h
@@ -65,7 +65,7 @@ void ShowUnmaskPrompt( const autofill::CreditCard& card, base::WeakPtr<autofill::CardUnmaskDelegate> delegate) override; - void OnUnmaskVerificationResult(bool success) override; + void OnUnmaskVerificationResult(GetRealPanResult result) override; void ConfirmSaveCreditCard(const base::Closure& save_card_callback) override; bool HasCreditCardScanFeature() override; void ScanCreditCard(const CreditCardScanCallback& callback) override;
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc index e192656..d2433d9 100644 --- a/android_webview/native/aw_contents.cc +++ b/android_webview/native/aw_contents.cc
@@ -1039,15 +1039,15 @@ namespace { void InvokeVisualStateCallback(const JavaObjectWeakGlobalRef& java_ref, - long request_id, - ScopedJavaGlobalRef<jobject>* callback, - bool result) { + long request_id, + ScopedJavaGlobalRef<jobject>* callback, + bool result) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = java_ref.get(env); if (obj.is_null()) return; Java_AwContents_invokeVisualStateCallback( - env, obj.obj(), callback->obj(), request_id, result); + env, obj.obj(), callback->obj(), request_id); } } // namespace
diff --git a/android_webview/native/aw_web_contents_delegate.cc b/android_webview/native/aw_web_contents_delegate.cc index acece1b..d2a71e6e 100644 --- a/android_webview/native/aw_web_contents_delegate.cc +++ b/android_webview/native/aw_web_contents_delegate.cc
@@ -163,6 +163,18 @@ } } +void AwWebContentsDelegate::NavigationStateChanged( + content::WebContents* source, + content::InvalidateTypes changed_flags) { + JNIEnv* env = AttachCurrentThread(); + + ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env); + if (java_delegate.obj()) { + Java_AwWebContentsDelegate_navigationStateChanged(env, java_delegate.obj(), + changed_flags); + } +} + // Notifies the delegate about the creation of a new WebContents. This // typically happens when popups are created. void AwWebContentsDelegate::WebContentsCreated(
diff --git a/android_webview/native/aw_web_contents_delegate.h b/android_webview/native/aw_web_contents_delegate.h index 96cd32575..afc881b 100644 --- a/android_webview/native/aw_web_contents_delegate.h +++ b/android_webview/native/aw_web_contents_delegate.h
@@ -40,6 +40,8 @@ bool user_gesture, bool* was_blocked) override; + void NavigationStateChanged(content::WebContents* source, + content::InvalidateTypes changed_flags) override; void WebContentsCreated(content::WebContents* source_contents, int opener_render_frame_id, const base::string16& frame_name,
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index ed4cd13..7db48e06 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -352,48 +352,46 @@ } } -if (!is_win || link_chrome_on_windows) { - executable("ash_shell") { - testonly = true - sources = [ - "shell/shell_main.cc", - ] +executable("ash_shell") { + testonly = true + sources = [ + "shell/shell_main.cc", + ] - deps = [ - ":ash_shell_lib", - "//components/user_manager", - ] + deps = [ + ":ash_shell_lib", + "//components/user_manager", + ] - if (is_win) { - configs -= [ "//build/config/win:console" ] - configs += [ "//build/config/win:windowed" ] - deps += [ "//sandbox" ] - } - - if (is_chromeos) { - deps += [ "//device/bluetooth" ] - } + if (is_win) { + configs -= [ "//build/config/win:console" ] + configs += [ "//build/config/win:windowed" ] + deps += [ "//sandbox" ] } - test("ash_shell_unittests") { - sources = [ - "shell/window_watcher_unittest.cc", - "test/ash_unittests.cc", - ] + if (is_chromeos) { + deps += [ "//device/bluetooth" ] + } +} - deps = [ - ":ash_shell_lib", - ":test_support", - "//base/test:test_support", - "//components/user_manager", - "//content/test:test_support", - "//skia", - "//testing/gtest", - "//ui/accessibility", - ] +test("ash_shell_unittests") { + sources = [ + "shell/window_watcher_unittest.cc", + "test/ash_unittests.cc", + ] - if (is_chromeos) { - deps += [ "//ui/display" ] - } + deps = [ + ":ash_shell_lib", + ":test_support", + "//base/test:test_support", + "//components/user_manager", + "//content/test:test_support", + "//skia", + "//testing/gtest", + "//ui/accessibility", + ] + + if (is_chromeos) { + deps += [ "//ui/display" ] } }
diff --git a/ash/ash_switches.cc b/ash/ash_switches.cc index a50a1ae..f11743dd 100644 --- a/ash/ash_switches.cc +++ b/ash/ash_switches.cc
@@ -64,10 +64,6 @@ // Enables software based mirroring. const char kAshEnableSoftwareMirroring[] = "ash-enable-software-mirroring"; -// Enables gesture swipe to close windows while in Overview mode. -const char kAshEnableSwipeToCloseInOverviewMode[] = - "ash-enable-swipe-to-close-in-overview-mode"; - // Enables touch view testing. // TODO(skuhne): Remove TOGGLE_TOUCH_VIEW_TESTING accelerator once this // flag is removed.
diff --git a/ash/ash_switches.h b/ash/ash_switches.h index 2442aff..4edb61e 100644 --- a/ash/ash_switches.h +++ b/ash/ash_switches.h
@@ -33,7 +33,6 @@ ASH_EXPORT extern const char kAshEnableMirroredScreen[]; ASH_EXPORT extern const char kAshEnablePowerButtonQuickLock[]; ASH_EXPORT extern const char kAshEnableSoftwareMirroring[]; -ASH_EXPORT extern const char kAshEnableSwipeToCloseInOverviewMode[]; ASH_EXPORT extern const char kAshEnableSystemSounds[]; ASH_EXPORT extern const char kAshEnableTouchViewTesting[]; ASH_EXPORT extern const char kAshHideNotificationsForFactory[];
diff --git a/ash/display/cursor_window_controller.cc b/ash/display/cursor_window_controller.cc index a59a5d83..ee6b565 100644 --- a/ash/display/cursor_window_controller.cc +++ b/ash/display/cursor_window_controller.cc
@@ -93,6 +93,7 @@ : is_cursor_compositing_enabled_(false), container_(NULL), cursor_type_(ui::kCursorNone), + visible_(true), cursor_set_(ui::CURSOR_SET_NORMAL), cursor_rotation_(gfx::Display::ROTATE_0), delegate_(new CursorWindowDelegate()) { @@ -169,6 +170,7 @@ cursor_type_ = cursor.native_type(); cursor_rotation_ = display_.rotation(); UpdateCursorImage(); + UpdateCursorVisibility(); } void CursorWindowController::SetCursorSet(ui::CursorSetType cursor_set) { @@ -179,10 +181,8 @@ void CursorWindowController::SetVisibility(bool visible) { if (!cursor_window_) return; - if (visible) - cursor_window_->Show(); - else - cursor_window_->Hide(); + visible_ = visible; + UpdateCursorVisibility(); } void CursorWindowController::SetContainer(aura::Window* container) { @@ -204,7 +204,7 @@ UpdateCursorImage(); container->AddChild(cursor_window_.get()); - cursor_window_->Show(); + UpdateCursorVisibility(); SetBoundsInScreen(container->bounds()); } @@ -265,4 +265,14 @@ } } +void CursorWindowController::UpdateCursorVisibility() { + if (!cursor_window_) + return; + bool visible = (visible_ && cursor_type_ != ui::kCursorNone); + if (visible) + cursor_window_->Show(); + else + cursor_window_->Hide(); +} + } // namespace ash
diff --git a/ash/display/cursor_window_controller.h b/ash/display/cursor_window_controller.h index 6e55c2f9..8af6906 100644 --- a/ash/display/cursor_window_controller.h +++ b/ash/display/cursor_window_controller.h
@@ -60,6 +60,9 @@ // Updates cursor image based on current cursor state. void UpdateCursorImage(); + // Hides/shows cursor window based on current cursor state. + void UpdateCursorVisibility(); + bool is_cursor_compositing_enabled_; aura::Window* container_; @@ -69,6 +72,9 @@ // The native_type of the cursor, see definitions in cursor.h int cursor_type_; + // The last requested cursor visibility. + bool visible_; + ui::CursorSetType cursor_set_; gfx::Display::Rotation cursor_rotation_; gfx::Point hot_point_;
diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc index 7a3b6f9..5d5144b 100644 --- a/ash/display/display_controller.cc +++ b/ash/display/display_controller.cc
@@ -39,6 +39,7 @@ #include "ui/compositor/compositor_vsync_manager.h" #include "ui/gfx/display.h" #include "ui/gfx/screen.h" +#include "ui/wm/core/coordinate_conversion.h" #include "ui/wm/public/activation_client.h" #if defined(OS_CHROMEOS) @@ -266,6 +267,7 @@ focus_activation_store_(new FocusActivationStore()), cursor_window_controller_(new CursorWindowController()), mirror_window_controller_(new MirrorWindowController()), + cursor_display_id_for_restore_(gfx::Display::kInvalidDisplayID), weak_ptr_factory_(this) { #if defined(OS_CHROMEOS) if (base::SysInfo::IsRunningOnChromeOS()) @@ -569,18 +571,44 @@ if (closest_distance_squared < 0 || closest_distance_squared > distance_squared) { aura::Window* root_window = GetRootWindowForDisplayId(display.id()); - aura::client::ScreenPositionClient* client = - aura::client::GetScreenPositionClient(root_window); - client->ConvertPointFromScreen(root_window, ¢er); + ::wm::ConvertPointFromScreen(root_window, ¢er); root_window->GetHost()->ConvertPointToNativeScreen(¢er); dst_root_window = root_window; target_location_in_native = center; closest_distance_squared = distance_squared; } } + + gfx::Point target_location_in_root = target_location_in_native; dst_root_window->GetHost()->ConvertPointFromNativeScreen( - &target_location_in_native); - dst_root_window->MoveCursorTo(target_location_in_native); + &target_location_in_root); + +#if defined(USE_OZONE) + gfx::Point target_location_in_screen = target_location_in_root; + ::wm::ConvertPointToScreen(dst_root_window, &target_location_in_screen); + int64 target_display_id = + display_manager->FindDisplayContainingPoint(target_location_in_screen) + .id(); + + // Do not move the cursor if the cursor's location did not change. This avoids + // moving (and showing) the cursor on startup. + // - |cursor_location_in_screen_coords_for_restore_| is checked to ensure that + // the cursor is moved when the cursor's native position does not change but + // the scale factor or rotation of the display it is on have changed. + // - |cursor_display_id_for_restore_| is checked to ensure that the cursor is + // moved when the cursor's native position and screen position do not change + // but the display that it is on has changed. This occurs when swapping the + // primary display. + if (target_location_in_native != + cursor_location_in_native_coords_for_restore_ || + target_location_in_screen != + cursor_location_in_screen_coords_for_restore_ || + target_display_id != cursor_display_id_for_restore_) { + dst_root_window->MoveCursorTo(target_location_in_root); + } +#else + dst_root_window->MoveCursorTo(target_location_in_root); +#endif } bool DisplayController::UpdateWorkAreaOfDisplayNearestWindow( @@ -713,14 +741,16 @@ focus_activation_store_->Store(clear_focus); gfx::Screen* screen = Shell::GetScreen(); gfx::Point point_in_screen = screen->GetCursorScreenPoint(); - gfx::Display display = screen->GetDisplayNearestPoint(point_in_screen); - aura::Window* root_window = GetRootWindowForDisplayId(display.id()); + cursor_location_in_screen_coords_for_restore_ = point_in_screen; - aura::client::ScreenPositionClient* client = - aura::client::GetScreenPositionClient(root_window); - client->ConvertPointFromScreen(root_window, &point_in_screen); - root_window->GetHost()->ConvertPointToNativeScreen(&point_in_screen); - cursor_location_in_native_coords_for_restore_ = point_in_screen; + gfx::Display display = screen->GetDisplayNearestPoint(point_in_screen); + cursor_display_id_for_restore_ = display.id(); + + gfx::Point point_in_native = point_in_screen; + aura::Window* root_window = GetRootWindowForDisplayId(display.id()); + ::wm::ConvertPointFromScreen(root_window, &point_in_native); + root_window->GetHost()->ConvertPointToNativeScreen(&point_in_native); + cursor_location_in_native_coords_for_restore_ = point_in_native; } void DisplayController::PostDisplayConfigurationChange() {
diff --git a/ash/display/display_controller.h b/ash/display/display_controller.h index 73822e85..d9b2d63 100644 --- a/ash/display/display_controller.h +++ b/ash/display/display_controller.h
@@ -211,10 +211,16 @@ scoped_ptr<CursorWindowController> cursor_window_controller_; scoped_ptr<MirrorWindowController> mirror_window_controller_; - // Stores the curent cursor location (in native coordinates) used to - // restore the cursor location when display configuration - // changed. + // Stores the current cursor location (in native coordinates and screen + // coordinates respectively). The locations are used to restore the cursor + // location when the display configuration changes and to determine whether + // the mouse should be moved after a display configuration change. gfx::Point cursor_location_in_native_coords_for_restore_; + gfx::Point cursor_location_in_screen_coords_for_restore_; + + // Stores the cursor's display. The id is used to determine whether the mouse + // should be moved after a display configuration change. + int64 cursor_display_id_for_restore_; base::WeakPtrFactory<DisplayController> weak_ptr_factory_;
diff --git a/ash/touch/touch_transformer_controller.cc b/ash/touch/touch_transformer_controller.cc index aa6475b..d88416e 100644 --- a/ash/touch/touch_transformer_controller.cc +++ b/ash/touch/touch_transformer_controller.cc
@@ -204,8 +204,8 @@ RootWindowController::ForWindow(root)->ash_host()->UpdateDisplayID( display1_id, display2_id); DisplayInfo source_display = - gfx::Display::InternalDisplayId() == display1_id ? - display1 : display2; + display_controller->GetPrimaryDisplayId() == display1_id ? display1 + : display2; // Mapping from framebuffer size to the source display's native // resolution. device_manager->UpdateTouchInfoForDisplay(
diff --git a/ash/virtual_keyboard_controller.cc b/ash/virtual_keyboard_controller.cc index 3ecc0bc2..2f46e5c 100644 --- a/ash/virtual_keyboard_controller.cc +++ b/ash/virtual_keyboard_controller.cc
@@ -50,13 +50,19 @@ } void VirtualKeyboardController::OnMaximizeModeStarted() { - if (!IsSmartVirtualKeyboardEnabled()) + if (!IsSmartVirtualKeyboardEnabled()) { SetKeyboardEnabled(true); + } else { + UpdateKeyboardEnabled(); + } } void VirtualKeyboardController::OnMaximizeModeEnded() { - if (!IsSmartVirtualKeyboardEnabled()) + if (!IsSmartVirtualKeyboardEnabled()) { SetKeyboardEnabled(false); + } else { + UpdateKeyboardEnabled(); + } } void VirtualKeyboardController::OnTouchscreenDeviceConfigurationChanged() { @@ -103,11 +109,16 @@ ->IsMaximizeModeWindowManagerEnabled()); return; } - SetKeyboardEnabled(!has_internal_keyboard_ && has_touchscreen_ && + bool ignore_internal_keyboard = Shell::GetInstance() + ->maximize_mode_controller() + ->IsMaximizeModeWindowManagerEnabled(); + bool is_internal_keyboard_active = + has_internal_keyboard_ && !ignore_internal_keyboard; + SetKeyboardEnabled(!is_internal_keyboard_active && has_touchscreen_ && (!has_external_keyboard_ || ignore_external_keyboard_)); ash::Shell::GetInstance() ->system_tray_notifier() - ->NotifyVirtualKeyboardSuppressionChanged(!has_internal_keyboard_ && + ->NotifyVirtualKeyboardSuppressionChanged(!is_internal_keyboard_active && has_touchscreen_ && has_external_keyboard_); }
diff --git a/ash/virtual_keyboard_controller_unittest.cc b/ash/virtual_keyboard_controller_unittest.cc index f3d169b..7ca7a2a 100644 --- a/ash/virtual_keyboard_controller_unittest.cc +++ b/ash/virtual_keyboard_controller_unittest.cc
@@ -154,7 +154,7 @@ }; // Tests that the onscreen keyboard is disabled if an internal keyboard is -// present. +// present and maximized mode is disabled. TEST_F(VirtualKeyboardControllerAutoTest, DisabledIfInternalKeyboardPresent) { std::vector<ui::TouchscreenDevice> screens; screens.push_back(ui::TouchscreenDevice( @@ -235,6 +235,79 @@ ASSERT_FALSE(keyboard::IsKeyboardEnabled()); } +// Tests maximized mode interaction without disabling the internal keyboard. +TEST_F(VirtualKeyboardControllerAutoTest, EnabledDuringMaximizeMode) { + std::vector<ui::TouchscreenDevice> screens; + screens.push_back(ui::TouchscreenDevice( + 1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(1024, 768), 0)); + UpdateTouchscreenDevices(screens); + std::vector<ui::KeyboardDevice> keyboards; + keyboards.push_back( + ui::KeyboardDevice(1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL)); + UpdateKeyboardDevices(keyboards); + ASSERT_FALSE(keyboard::IsKeyboardEnabled()); + // Toggle maximized mode on. + Shell::GetInstance() + ->maximize_mode_controller() + ->EnableMaximizeModeWindowManager(true); + ASSERT_TRUE(keyboard::IsKeyboardEnabled()); + // Toggle maximized mode off. + Shell::GetInstance() + ->maximize_mode_controller() + ->EnableMaximizeModeWindowManager(false); + ASSERT_FALSE(keyboard::IsKeyboardEnabled()); +} + +// Tests that keyboard gets suppressed in maximized mode. +TEST_F(VirtualKeyboardControllerAutoTest, SuppressedInMaximizedMode) { + std::vector<ui::TouchscreenDevice> screens; + screens.push_back(ui::TouchscreenDevice( + 1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(1024, 768), 0)); + UpdateTouchscreenDevices(screens); + std::vector<ui::KeyboardDevice> keyboards; + keyboards.push_back( + ui::KeyboardDevice(1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL)); + keyboards.push_back( + ui::KeyboardDevice(2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL)); + UpdateKeyboardDevices(keyboards); + // Toggle maximized mode on. + Shell::GetInstance() + ->maximize_mode_controller() + ->EnableMaximizeModeWindowManager(true); + ASSERT_FALSE(keyboard::IsKeyboardEnabled()); + ASSERT_TRUE(notified()); + ASSERT_TRUE(IsVirtualKeyboardSuppressed()); + // Toggle show keyboard. Keyboard should be visible. + ResetObserver(); + Shell::GetInstance() + ->virtual_keyboard_controller() + ->ToggleIgnoreExternalKeyboard(); + ASSERT_TRUE(keyboard::IsKeyboardEnabled()); + ASSERT_TRUE(notified()); + ASSERT_TRUE(IsVirtualKeyboardSuppressed()); + // Toggle show keyboard. Keyboard should be hidden. + ResetObserver(); + Shell::GetInstance() + ->virtual_keyboard_controller() + ->ToggleIgnoreExternalKeyboard(); + ASSERT_FALSE(keyboard::IsKeyboardEnabled()); + ASSERT_TRUE(notified()); + ASSERT_TRUE(IsVirtualKeyboardSuppressed()); + // Remove external keyboard. Should be notified that the keyboard is not + // suppressed. + ResetObserver(); + keyboards.pop_back(); + UpdateKeyboardDevices(keyboards); + ASSERT_TRUE(keyboard::IsKeyboardEnabled()); + ASSERT_TRUE(notified()); + ASSERT_FALSE(IsVirtualKeyboardSuppressed()); + // Toggle maximized mode oFF. + Shell::GetInstance() + ->maximize_mode_controller() + ->EnableMaximizeModeWindowManager(false); + ASSERT_FALSE(keyboard::IsKeyboardEnabled()); +} + class VirtualKeyboardControllerAlwaysEnabledTest : public VirtualKeyboardControllerAutoTest { public:
diff --git a/ash/wm/overview/overview_animation_type.h b/ash/wm/overview/overview_animation_type.h index 5df51cb..dde3a15 100644 --- a/ash/wm/overview/overview_animation_type.h +++ b/ash/wm/overview/overview_animation_type.h
@@ -14,8 +14,6 @@ OVERVIEW_ANIMATION_NONE, // Used to fade in the close button and label. OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN, - // Used to fade out the close button. - OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT, // Used to position windows when entering/exiting overview mode and when a // window is closed while overview mode is active. OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS, @@ -23,12 +21,7 @@ OVERVIEW_ANIMATION_HIDE_WINDOW, // Used to restore windows to their original position when exiting overview // mode. - OVERVIEW_ANIMATION_RESTORE_WINDOW, - // Used to animate windows when a user performs a touch drag gesture. - OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM, - // Used to animate windows back in to position when a touch drag gesture is - // cancelled. - OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL + OVERVIEW_ANIMATION_RESTORE_WINDOW }; } // namespace ash
diff --git a/ash/wm/overview/scoped_overview_animation_settings.cc b/ash/wm/overview/scoped_overview_animation_settings.cc index 3cb6bcb..e0cf977 100644 --- a/ash/wm/overview/scoped_overview_animation_settings.cc +++ b/ash/wm/overview/scoped_overview_animation_settings.cc
@@ -20,22 +20,15 @@ // The time duration for widgets to fade in. const int kFadeInMilliseconds = 80; -// The time duration for widgets to fade out. -const int kFadeOutMilliseconds = 100; - base::TimeDelta GetAnimationDuration(OverviewAnimationType animation_type) { switch (animation_type) { case OVERVIEW_ANIMATION_NONE: - case OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM: return base::TimeDelta(); case OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN: return base::TimeDelta::FromMilliseconds(kFadeInMilliseconds); - case OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT: - return base::TimeDelta::FromMilliseconds(kFadeOutMilliseconds); case OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS: case OVERVIEW_ANIMATION_RESTORE_WINDOW: case OVERVIEW_ANIMATION_HIDE_WINDOW: - case OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL: return base::TimeDelta::FromMilliseconds(kTransitionMilliseconds); } NOTREACHED(); @@ -51,7 +44,6 @@ switch (animation_type) { case OVERVIEW_ANIMATION_NONE: - case OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM: animation_settings_.SetPreemptionStrategy( ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); break; @@ -63,10 +55,6 @@ animation_settings_.SetPreemptionStrategy( ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); break; - case OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT: - animation_settings_.SetPreemptionStrategy( - ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); - break; case OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS: case OVERVIEW_ANIMATION_RESTORE_WINDOW: animation_settings_.SetPreemptionStrategy( @@ -77,11 +65,6 @@ animation_settings_.SetPreemptionStrategy( ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); break; - case OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL: - animation_settings_.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - animation_settings_.SetTweenType(gfx::Tween::EASE_IN_OUT); - break; } animation_settings_.SetTransitionDuration( GetAnimationDuration(animation_type));
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/window_selector_controller.cc index 6f21c8f..df14d27 100644 --- a/ash/wm/overview/window_selector_controller.cc +++ b/ash/wm/overview/window_selector_controller.cc
@@ -6,7 +6,6 @@ #include <vector> -#include "ash/ash_switches.h" #include "ash/metrics/user_metrics_recorder.h" #include "ash/root_window_controller.h" #include "ash/session/session_state_delegate.h" @@ -16,15 +15,12 @@ #include "ash/wm/overview/window_selector.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" -#include "base/command_line.h" #include "base/metrics/histogram.h" #include "ui/aura/window.h" namespace ash { -WindowSelectorController::WindowSelectorController() - : swipe_to_close_enabled_(base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshEnableSwipeToCloseInOverviewMode)) { +WindowSelectorController::WindowSelectorController() { } WindowSelectorController::~WindowSelectorController() {
diff --git a/ash/wm/overview/window_selector_controller.h b/ash/wm/overview/window_selector_controller.h index 518d05de..8d4a625 100644 --- a/ash/wm/overview/window_selector_controller.h +++ b/ash/wm/overview/window_selector_controller.h
@@ -48,8 +48,6 @@ // are visible during overview mode. bool IsRestoringMinimizedWindows() const; - bool swipe_to_close_enabled() const { return swipe_to_close_enabled_; } - // WindowSelectorDelegate: void OnSelectionEnded() override; @@ -62,9 +60,6 @@ scoped_ptr<WindowSelector> window_selector_; base::Time last_selection_time_; - // Tracks whether the "Swipe-to-close" feature is enabled. - bool swipe_to_close_enabled_; - DISALLOW_COPY_AND_ASSIGN(WindowSelectorController); };
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc index 7e74caf..f3e8eca2 100644 --- a/ash/wm/overview/window_selector_item.cc +++ b/ash/wm/overview/window_selector_item.cc
@@ -37,13 +37,6 @@ namespace { -// The minimum fling velocity which will cause a window to be closed. Unit is -// pixels per second. -const float kMinimumFlingVelocity = 4000.0f; - -// The minimum opacity used during touch scroll gestures. -const float kMinimumOpacity = 0.2f; - // In the conceptual overview table, the window margin is the space reserved // around the window within the cell. This margin does not overlap so the // closest distance between adjacent windows will be twice this amount. @@ -91,24 +84,6 @@ layer->SetOpacity(1.0f); } -// Convenience method to fade out a window using the animation settings defined -// by OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT. -void SetupFadeOut(aura::Window* window) { - ScopedOverviewAnimationSettings animation_settings( - OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT, - window); - window->layer()->SetOpacity(0.0f); -} - -// Calculates the window opacity from the given scroll |distance| and the -// |min opacity_distance|. -float CalculateOpacityFromScrollDistance(int distance, - int min_opacity_distance) { - float opacity = - 1.0f - static_cast<float>(abs(distance)) / min_opacity_distance; - return std::min(1.0f, std::max(kMinimumOpacity, opacity)); -} - // An image button with a close window icon. class OverviewCloseButton : public views::ImageButton { public: @@ -136,10 +111,9 @@ } // namespace WindowSelectorItem::OverviewLabelButton::OverviewLabelButton( - WindowSelectorItem* selector_item, + views::ButtonListener* listener, const base::string16& text) - : LabelButton(selector_item, text), - selector_item_(selector_item), + : LabelButton(listener, text), top_padding_(0) { } @@ -152,12 +126,6 @@ return bounds; } -void WindowSelectorItem::OverviewLabelButton::OnGestureEvent( - ui::GestureEvent* event) { - selector_item_->OnGestureEvent(event); - views::LabelButton::OnGestureEvent(event); -} - WindowSelectorItem::WindowSelectorItem(aura::Window* window) : dimmed_(false), root_window_(window->GetRootWindow()), @@ -260,72 +228,6 @@ wm::GetWindowState(transform_window_.window())->Activate(); } -void WindowSelectorItem::OnGestureEvent(ui::GestureEvent* event) { - if (!Shell::GetInstance() - ->window_selector_controller() - ->swipe_to_close_enabled()) - return; - - int delta_x = 0; - if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN) - scroll_x_origin_ = event->x(); - else - delta_x = event->x() - scroll_x_origin_; - - switch (event->type()) { - case ui::ET_GESTURE_SCROLL_BEGIN: { - // We need to call SetHandled() for the ET_GESTURE_SCROLL_BEGIN event so - // that future ET_GESTURE_SCROLL_* events are sent here. - event->SetHandled(); - close_button_->SetEnabled(false); - SetupFadeOut(close_button_widget_.GetNativeWindow()); - break; - } - case ui::ET_GESTURE_SCROLL_UPDATE: { - event->SetHandled(); - ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings; - transform_window_.BeginScopedAnimation( - OverviewAnimationType::OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM, - &animation_settings); - - gfx::Transform new_transform; - new_transform.Translate(delta_x, 0); - new_transform.PreconcatTransform( - transform_window_.get_overview_transform()); - transform_window_.SetTransform(root_window(), new_transform); - - const float opacity = CalculateOpacityFromScrollDistance( - delta_x, GetMinimumCloseDistance()); - transform_window_.SetOpacity(opacity); - break; - } - case ui::ET_GESTURE_SCROLL_END: { - event->SetHandled(); - if (abs(delta_x) > GetMinimumCloseDistance()) { - transform_window_.Close(); - break; - } - ResetScrolledWindow(); - break; - } - case ui::ET_SCROLL_FLING_START: { - event->SetHandled(); - if (abs(delta_x) > GetMinimumCloseDistance() || - fabs(event->details().velocity_x()) > kMinimumFlingVelocity) { - transform_window_.Close(); - break; - } - ResetScrolledWindow(); - break; - } - case ui::ET_GESTURE_END: - scroll_x_origin_ = 0; - break; - default: - break; - } -} - void WindowSelectorItem::OnWindowDestroying(aura::Window* window) { window->RemoveObserver(this); transform_window_.OnWindowDestroyed(); @@ -338,20 +240,6 @@ UpdateCloseButtonAccessibilityName(); } -void WindowSelectorItem::ResetScrolledWindow() { - ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings; - transform_window_.BeginScopedAnimation( - OverviewAnimationType::OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL, - &animation_settings); - - transform_window_.SetTransform(root_window(), - transform_window_.get_overview_transform()); - transform_window_.SetOpacity(1.0); - - SetupFadeInAfterLayout(close_button_widget_.GetNativeWindow()); - close_button_->SetEnabled(true); -} - void WindowSelectorItem::SetItemBounds(const gfx::Rect& target_bounds, OverviewAnimationType animation_type) { DCHECK(root_window_ == GetWindow()->GetRootWindow()); @@ -456,8 +344,4 @@ GetWindow()->title())); } -int WindowSelectorItem::GetMinimumCloseDistance() const { - return target_bounds_.size().width() / 2; -} - } // namespace ash
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/window_selector_item.h index 0e4aa8fa..063b141e 100644 --- a/ash/wm/overview/window_selector_item.h +++ b/ash/wm/overview/window_selector_item.h
@@ -33,25 +33,18 @@ public: class OverviewLabelButton : public views::LabelButton { public: - OverviewLabelButton(WindowSelectorItem* selector_item, + OverviewLabelButton(views::ButtonListener* listener, const base::string16& text); ~OverviewLabelButton() override; void set_top_padding(int top_padding) { top_padding_ = top_padding; } - // views::LabelButton: - void OnGestureEvent(ui::GestureEvent* event) override; - protected: // views::LabelButton: gfx::Rect GetChildAreaBounds() override; private: - // The WindowSelectorItem that the touch gestures are delegated to. - // Not owned. - WindowSelectorItem* selector_item_; - // Padding on top of the button. int top_padding_; @@ -101,9 +94,6 @@ const gfx::Rect& target_bounds() const { return target_bounds_; } - // Handles the gestures on the Window - void OnGestureEvent(ui::GestureEvent* event); - // views::ButtonListener: void ButtonPressed(views::Button* sender, const ui::Event& event) override; @@ -137,14 +127,6 @@ // Updates the close buttons accessibility name. void UpdateCloseButtonAccessibilityName(); - // Animates the |transform_window_| back to it's original overview mode - // position. - void ResetScrolledWindow(); - - // Returns the minimum distance at which a scroll gesture will cause this - // selector item to be closed. - int GetMinimumCloseDistance() const; - // True if the item is being shown in the overview, false if it's being // filtered. bool dimmed_; @@ -176,10 +158,6 @@ // close_button_widget_. views::ImageButton* close_button_; - // The original X location for a scroll begin event. |original_x_| is in the - // local coordinate space of |window_label_button_view_|. - float scroll_x_origin_; - DISALLOW_COPY_AND_ASSIGN(WindowSelectorItem); };
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc index ec60952..5ebf669 100644 --- a/ash/wm/overview/window_selector_unittest.cc +++ b/ash/wm/overview/window_selector_unittest.cc
@@ -3,11 +3,9 @@ // found in the LICENSE file. #include <algorithm> -#include <map> #include <vector> #include "ash/accessibility_delegate.h" -#include "ash/ash_switches.h" #include "ash/drag_drop/drag_drop_controller.h" #include "ash/root_window_controller.h" #include "ash/screen_util.h" @@ -73,18 +71,6 @@ } } -// A short drag distance that will not cause an overview item to close. -const int kShortDragDistance = 10; - -// A far drag distance that will cause an overview item to close. -const int kFarDragDistance = 200; - -// A slow fling velocity that should not cause selctor items to close. -const int kSlowFlingVelocity = 2000; - -// A fast fling velocity that should cause selector items to close. -const int kFastFlingVelocity = 5000; - } // namespace // TODO(bruthig): Move all non-simple method definitions out of class @@ -279,24 +265,6 @@ DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest); }; -class WindowSelectorSwipeToCloseEnabledTest : public WindowSelectorTest { - public: - WindowSelectorSwipeToCloseEnabledTest() {} - ~WindowSelectorSwipeToCloseEnabledTest() override {} - - // WindowSelectorTest: - void SetUp() override; - - private: - DISALLOW_COPY_AND_ASSIGN(WindowSelectorSwipeToCloseEnabledTest); -}; - -void WindowSelectorSwipeToCloseEnabledTest::SetUp() { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kAshEnableSwipeToCloseInOverviewMode); - WindowSelectorTest::SetUp(); -} - // Tests that an a11y alert is sent on entering overview mode. TEST_F(WindowSelectorTest, A11yAlertOnOverviewMode) { gfx::Rect bounds(0, 0, 400, 400); @@ -1274,210 +1242,4 @@ EXPECT_FALSE(IsSelecting()); } -// Verify swipe to close doesn't work when swipe to close is not enabled. -TEST_F(WindowSelectorTest, WindowTapDragFarDistance) { - scoped_ptr<views::Widget> widget = - CreateWindowWidget(gfx::Rect(0, 0, 400, 400)); - - ToggleOverview(); - ASSERT_TRUE(IsSelecting()); - - aura::Window* window = widget->GetNativeWindow(); - gfx::Rect bounds = ToNearestRect(GetTransformedBoundsInRootWindow(window)); - ui::test::EventGenerator event_generator(window->GetRootWindow()); - - ASSERT_FALSE(widget->IsClosed()); - - gfx::Point start(bounds.CenterPoint()); - gfx::Point end(start.x() - kFarDragDistance, start.y()); - event_generator.GestureScrollSequence( - start, end, base::TimeDelta::FromMilliseconds(10), 5); - - EXPECT_FALSE(widget->IsClosed()); - - RunAllPendingInMessageLoop(); - EXPECT_TRUE(IsSelecting()); -} - -// Verify the window moves and fades as it is dragged. -TEST_F(WindowSelectorSwipeToCloseEnabledTest, - VerifyWindowBehaviourDuringTapDrag) { - scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 400, 400))); - - ToggleOverview(); - - gfx::Rect bounds = - ToNearestRect(GetTransformedBoundsInRootWindow(window.get())); - ui::test::EventGenerator event_generator(window->GetRootWindow()); - - const gfx::Point drag_start_point(bounds.CenterPoint()); - const gfx::Point drag_left_point(drag_start_point.x() - kFarDragDistance, - drag_start_point.y()); - const gfx::Point drag_right_point(drag_start_point.x() + kFarDragDistance, - drag_start_point.y()); - - const int drag_left_delta_x = drag_start_point.x() - drag_left_point.x(); - const int drag_right_delta_x = drag_start_point.x() - drag_right_point.x(); - - const gfx::Rect original_bounds = window->GetBoundsInScreen(); - - ASSERT_EQ(1.0f, window->layer()->opacity()); - - event_generator.set_current_location(drag_start_point); - event_generator.PressTouch(); - - EXPECT_EQ(1.0f, window->layer()->opacity()); - - event_generator.MoveTouch(drag_left_point); - - EXPECT_EQ(original_bounds.x() - drag_left_delta_x, - window->GetBoundsInScreen().x()); - EXPECT_EQ(original_bounds.y(), window->GetBoundsInScreen().y()); - - EXPECT_LT(window->layer()->opacity(), 0.5f); - - event_generator.MoveTouch(drag_start_point); - - EXPECT_EQ(original_bounds.x(), window->GetBoundsInScreen().x()); - EXPECT_EQ(original_bounds.y(), window->GetBoundsInScreen().y()); - EXPECT_EQ(1.0f, window->layer()->opacity()); - - event_generator.MoveTouch(drag_right_point); - - EXPECT_EQ(original_bounds.x() - drag_right_delta_x, - window->GetBoundsInScreen().x()); - EXPECT_EQ(original_bounds.y(), window->GetBoundsInScreen().y()); - - EXPECT_LT(window->layer()->opacity(), 0.5f); -} - -// Test dragging a window a short distance. -TEST_F(WindowSelectorSwipeToCloseEnabledTest, WindowTapDragShortDistance) { - scoped_ptr<views::Widget> widget = - CreateWindowWidget(gfx::Rect(0, 0, 400, 400)); - - ToggleOverview(); - - aura::Window* window = widget->GetNativeWindow(); - gfx::Rect bounds = ToNearestRect(GetTransformedBoundsInRootWindow(window)); - ui::test::EventGenerator event_generator(window->GetRootWindow()); - - ASSERT_FALSE(widget->IsClosed()); - - gfx::Point start(bounds.CenterPoint()); - gfx::Point end(start.x() - kShortDragDistance, start.y()); - event_generator.GestureScrollSequence( - start, end, base::TimeDelta::FromMilliseconds(10), 5); - - EXPECT_FALSE(widget->IsClosed()); - - RunAllPendingInMessageLoop(); - EXPECT_TRUE(IsSelecting()); -} - -// Test dragging a window a far distance. -TEST_F(WindowSelectorSwipeToCloseEnabledTest, WindowTapDragFarDistance) { - scoped_ptr<views::Widget> widget = - CreateWindowWidget(gfx::Rect(0, 0, 400, 400)); - - ToggleOverview(); - ASSERT_TRUE(IsSelecting()); - - aura::Window* window = widget->GetNativeWindow(); - gfx::Rect bounds = ToNearestRect(GetTransformedBoundsInRootWindow(window)); - ui::test::EventGenerator event_generator(window->GetRootWindow()); - - ASSERT_FALSE(widget->IsClosed()); - - gfx::Point start(bounds.CenterPoint()); - gfx::Point end(start.x() - kFarDragDistance, start.y()); - event_generator.GestureScrollSequence( - start, end, base::TimeDelta::FromMilliseconds(10), 5); - - EXPECT_TRUE(widget->IsClosed()); - - RunAllPendingInMessageLoop(); - EXPECT_FALSE(IsSelecting()); -} - -// Test a slow velocity fling. -TEST_F(WindowSelectorSwipeToCloseEnabledTest, SlowVelocityFling) { - scoped_ptr<views::Widget> widget = - CreateWindowWidget(gfx::Rect(0, 0, 400, 400)); - - ToggleOverview(); - - aura::Window* window = widget->GetNativeWindow(); - gfx::RectF bounds = GetTransformedBoundsInRootWindow(window); - ui::test::EventGenerator event_generator(window->GetRootWindow()); - - ASSERT_FALSE(widget->IsClosed()); - - gfx::Point start(bounds.CenterPoint().x(), bounds.CenterPoint().y()); - gfx::Point end(start.x() - kShortDragDistance, start.y()); - const base::TimeDelta kScrollDuration = - event_generator.CalculateScrollDurationForFlingVelocity( - start, end, kSlowFlingVelocity, 10); - event_generator.GestureScrollSequence(start, end, kScrollDuration, 10); - - EXPECT_FALSE(widget->IsClosed()); - - RunAllPendingInMessageLoop(); - EXPECT_TRUE(IsSelecting()); -} - -// Test a fast velocity fling. -TEST_F(WindowSelectorSwipeToCloseEnabledTest, FastVelocityFling) { - scoped_ptr<views::Widget> widget = - CreateWindowWidget(gfx::Rect(0, 0, 400, 400)); - - ToggleOverview(); - ASSERT_TRUE(IsSelecting()); - - aura::Window* window = widget->GetNativeWindow(); - gfx::RectF bounds = GetTransformedBoundsInRootWindow(window); - ui::test::EventGenerator event_generator(window->GetRootWindow()); - - ASSERT_FALSE(widget->IsClosed()); - - gfx::Point start(bounds.CenterPoint().x(), bounds.CenterPoint().y()); - gfx::Point end(start.x() - kShortDragDistance, start.y()); - const base::TimeDelta kScrollDuration = - event_generator.CalculateScrollDurationForFlingVelocity( - start, end, kFastFlingVelocity, 10); - event_generator.GestureScrollSequence(start, end, kScrollDuration, 10); - - EXPECT_TRUE(widget->IsClosed()); - - RunAllPendingInMessageLoop(); - EXPECT_FALSE(IsSelecting()); -} - -// Test a fast velocity fling. -TEST_F(WindowSelectorSwipeToCloseEnabledTest, SlowVelocityFlingAtAFarDistance) { - scoped_ptr<views::Widget> widget = - CreateWindowWidget(gfx::Rect(0, 0, 400, 400)); - - ToggleOverview(); - ASSERT_TRUE(IsSelecting()); - - aura::Window* window = widget->GetNativeWindow(); - gfx::RectF bounds = GetTransformedBoundsInRootWindow(window); - ui::test::EventGenerator event_generator(window->GetRootWindow()); - - ASSERT_FALSE(widget->IsClosed()); - - gfx::Point start(bounds.CenterPoint().x(), bounds.CenterPoint().y()); - gfx::Point end(start.x() - kFarDragDistance, start.y()); - const base::TimeDelta kScrollDuration = - event_generator.CalculateScrollDurationForFlingVelocity( - start, end, kSlowFlingVelocity, 10); - event_generator.GestureScrollSequence(start, end, kScrollDuration, 10); - - EXPECT_TRUE(widget->IsClosed()); - - RunAllPendingInMessageLoop(); - EXPECT_FALSE(IsSelecting()); -} - } // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn index 25fc7c0..402b19a 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1068,6 +1068,8 @@ source_set("prefs") { sources = [ "prefs/base_prefs_export.h", + "prefs/base_prefs_switches.cc", + "prefs/base_prefs_switches.h", "prefs/default_pref_store.cc", "prefs/default_pref_store.h", "prefs/json_pref_store.cc",
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java index c03cad2..4198853 100644 --- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java +++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -72,13 +72,6 @@ } /** - * @return True if the running version of the Android supports HTML clipboard. - */ - public static boolean isHTMLClipboardSupported() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; - } - - /** * @see android.view.View#setLayoutDirection(int) */ public static void setLayoutDirection(View view, int layoutDirection) {
diff --git a/base/base.gyp b/base/base.gyp index ddbaf22..3888ad9 100644 --- a/base/base.gyp +++ b/base/base.gyp
@@ -338,6 +338,8 @@ ], 'sources': [ 'prefs/base_prefs_export.h', + 'prefs/base_prefs_switches.cc', + 'prefs/base_prefs_switches.h', 'prefs/default_pref_store.cc', 'prefs/default_pref_store.h', 'prefs/json_pref_store.cc', @@ -382,12 +384,18 @@ # TODO(pasko): Remove this target when crbug.com/424562 is fixed. # GN: //base:protect_file_posix 'target_name': 'protect_file_posix', - 'type': 'static_library', - 'dependencies': [ - 'base', - ], - 'sources': [ - 'files/protect_file_posix.cc', + 'conditions': [ + ['os_posix == 1', { + 'type': 'static_library', + 'dependencies': [ + 'base', + ], + 'sources': [ + 'files/protect_file_posix.cc', + ], + }, { + 'type': 'none', + }], ], }, { @@ -938,6 +946,8 @@ 'test/mock_chrome_application_mac.mm', 'test/mock_devices_changed_observer.cc', 'test/mock_devices_changed_observer.h', + 'test/mock_log.cc', + 'test/mock_log.h', 'test/multiprocess_test.cc', 'test/multiprocess_test.h', 'test/multiprocess_test_android.cc',
diff --git a/base/base_nacl.gyp b/base/base_nacl.gyp index 63e1ed4..90a2893 100644 --- a/base/base_nacl.gyp +++ b/base/base_nacl.gyp
@@ -7,8 +7,12 @@ 'chromium_code': 1, }, 'includes': [ - '../build/common_untrusted.gypi', + # base.gypi must be included before common_untrusted.gypi. + # + # TODO(sergeyu): Replace the target_defaults magic in base.gypi with a + # sources variables lists. That way order of includes will not matter. 'base.gypi', + '../build/common_untrusted.gypi', ], 'conditions': [ ['disable_nacl==0 and disable_nacl_untrusted==0', {
diff --git a/base/json/json_file_value_serializer.cc b/base/json/json_file_value_serializer.cc index 71033f6..72a09700 100644 --- a/base/json/json_file_value_serializer.cc +++ b/base/json/json_file_value_serializer.cc
@@ -10,16 +10,14 @@ using base::FilePath; -const char JSONFileValueSerializer::kAccessDenied[] = "Access denied."; -const char JSONFileValueSerializer::kCannotReadFile[] = "Can't read file."; -const char JSONFileValueSerializer::kFileLocked[] = "File locked."; -const char JSONFileValueSerializer::kNoSuchFile[] = "File doesn't exist."; +const char JSONFileValueDeserializer::kAccessDenied[] = "Access denied."; +const char JSONFileValueDeserializer::kCannotReadFile[] = "Can't read file."; +const char JSONFileValueDeserializer::kFileLocked[] = "File locked."; +const char JSONFileValueDeserializer::kNoSuchFile[] = "File doesn't exist."; JSONFileValueSerializer::JSONFileValueSerializer( const base::FilePath& json_file_path) - : json_file_path_(json_file_path), - allow_trailing_comma_(false), - last_read_size_(0U) { + : json_file_path_(json_file_path) { } JSONFileValueSerializer::~JSONFileValueSerializer() { @@ -53,7 +51,17 @@ return true; } -int JSONFileValueSerializer::ReadFileToString(std::string* json_string) { +JSONFileValueDeserializer::JSONFileValueDeserializer( + const base::FilePath& json_file_path) + : json_file_path_(json_file_path), + allow_trailing_comma_(false), + last_read_size_(0U) { +} + +JSONFileValueDeserializer::~JSONFileValueDeserializer() { +} + +int JSONFileValueDeserializer::ReadFileToString(std::string* json_string) { DCHECK(json_string); if (!base::ReadFileToString(json_file_path_, json_string)) { #if defined(OS_WIN) @@ -74,7 +82,7 @@ return JSON_NO_ERROR; } -const char* JSONFileValueSerializer::GetErrorMessageForCode(int error_code) { +const char* JSONFileValueDeserializer::GetErrorMessageForCode(int error_code) { switch (error_code) { case JSON_NO_ERROR: return ""; @@ -92,8 +100,8 @@ } } -base::Value* JSONFileValueSerializer::Deserialize(int* error_code, - std::string* error_str) { +base::Value* JSONFileValueDeserializer::Deserialize(int* error_code, + std::string* error_str) { std::string json_string; int error = ReadFileToString(&json_string); if (error != JSON_NO_ERROR) { @@ -104,7 +112,7 @@ return NULL; } - JSONStringValueSerializer serializer(json_string); - serializer.set_allow_trailing_comma(allow_trailing_comma_); - return serializer.Deserialize(error_code, error_str); + JSONStringValueDeserializer deserializer(json_string); + deserializer.set_allow_trailing_comma(allow_trailing_comma_); + return deserializer.Deserialize(error_code, error_str); }
diff --git a/base/json/json_file_value_serializer.h b/base/json/json_file_value_serializer.h index 6cfcbe83..aab47ee 100644 --- a/base/json/json_file_value_serializer.h +++ b/base/json/json_file_value_serializer.h
@@ -14,10 +14,9 @@ class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer { public: - // |json_file_path_| is the path of a file that will be source of the - // deserialization or the destination of the serialization. - // When deserializing, the file should exist, but when serializing, the - // serializer will attempt to create the file at the specified location. + // |json_file_path_| is the path of a file that will be destination of the + // serialization. The serializer will attempt to create the file at the + // specified location. explicit JSONFileValueSerializer(const base::FilePath& json_file_path); ~JSONFileValueSerializer() override; @@ -36,6 +35,22 @@ // output. bool SerializeAndOmitBinaryValues(const base::Value& root); + private: + bool SerializeInternal(const base::Value& root, bool omit_binary_values); + + const base::FilePath json_file_path_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueSerializer); +}; + +class BASE_EXPORT JSONFileValueDeserializer : public base::ValueDeserializer { + public: + // |json_file_path_| is the path of a file that will be source of the + // deserialization. + explicit JSONFileValueDeserializer(const base::FilePath& json_file_path); + + ~JSONFileValueDeserializer() override; + // Attempt to deserialize the data structure encoded in the file passed // in to the constructor into a structure of Value objects. If the return // value is NULL, and if |error_code| is non-null, |error_code| will @@ -69,22 +84,20 @@ allow_trailing_comma_ = new_value; } - // Returns the syze (in bytes) of JSON string read from disk in the last + // Returns the size (in bytes) of JSON string read from disk in the last // successful |Deserialize()| call. size_t get_last_read_size() const { return last_read_size_; } private: - bool SerializeInternal(const base::Value& root, bool omit_binary_values); + // A wrapper for ReadFileToString which returns a non-zero JsonFileError if + // there were file errors. + int ReadFileToString(std::string* json_string); const base::FilePath json_file_path_; bool allow_trailing_comma_; size_t last_read_size_; - // A wrapper for ReadFileToString which returns a non-zero JsonFileError if - // there were file errors. - int ReadFileToString(std::string* json_string); - - DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueSerializer); + DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueDeserializer); }; #endif // BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
diff --git a/base/json/json_string_value_serializer.cc b/base/json/json_string_value_serializer.cc index b626640..debf9f08 100644 --- a/base/json/json_string_value_serializer.cc +++ b/base/json/json_string_value_serializer.cc
@@ -12,17 +12,7 @@ JSONStringValueSerializer::JSONStringValueSerializer(std::string* json_string) : json_string_(json_string), - json_string_readonly_(*json_string), - pretty_print_(false), - allow_trailing_comma_(false) { -} - -JSONStringValueSerializer::JSONStringValueSerializer( - const base::StringPiece& json_string) - : json_string_(nullptr), - json_string_readonly_(json_string), - pretty_print_(false), - allow_trailing_comma_(false) { + pretty_print_(false) { } JSONStringValueSerializer::~JSONStringValueSerializer() {} @@ -50,9 +40,17 @@ return base::JSONWriter::WriteWithOptions(&root, options, json_string_); } -Value* JSONStringValueSerializer::Deserialize(int* error_code, - std::string* error_str) { - return base::JSONReader::ReadAndReturnError(json_string_readonly_, +JSONStringValueDeserializer::JSONStringValueDeserializer( + const base::StringPiece& json_string) + : json_string_(json_string), + allow_trailing_comma_(false) { +} + +JSONStringValueDeserializer::~JSONStringValueDeserializer() {} + +Value* JSONStringValueDeserializer::Deserialize(int* error_code, + std::string* error_str) { + return base::JSONReader::ReadAndReturnError(json_string_, allow_trailing_comma_ ? base::JSON_ALLOW_TRAILING_COMMAS : base::JSON_PARSE_RFC, error_code, error_str);
diff --git a/base/json/json_string_value_serializer.h b/base/json/json_string_value_serializer.h index 7f99bc9..bc0e66d 100644 --- a/base/json/json_string_value_serializer.h +++ b/base/json/json_string_value_serializer.h
@@ -15,16 +15,11 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer { public: - // |json_string| is the string that will be source of the deserialization - // or the destination of the serialization. The caller of the constructor - // retains ownership of the string. |json_string| must not be null. + // |json_string| is the string that will be the destination of the + // serialization. The caller of the constructor retains ownership of the + // string. |json_string| must not be null. explicit JSONStringValueSerializer(std::string* json_string); - // This version allows initialization with a StringPiece for deserialization - // only. Retains a reference to the contents of |json_string|, so the data - // must outlive the JSONStringValueSerializer. - explicit JSONStringValueSerializer(const base::StringPiece& json_string); - ~JSONStringValueSerializer() override; // Attempt to serialize the data structure represented by Value into @@ -36,6 +31,27 @@ // output. bool SerializeAndOmitBinaryValues(const base::Value& root); + void set_pretty_print(bool new_value) { pretty_print_ = new_value; } + bool pretty_print() { return pretty_print_; } + + private: + bool SerializeInternal(const base::Value& root, bool omit_binary_values); + + // Owned by the caller of the constructor. + std::string* json_string_; + bool pretty_print_; // If true, serialization will span multiple lines. + + DISALLOW_COPY_AND_ASSIGN(JSONStringValueSerializer); +}; + +class BASE_EXPORT JSONStringValueDeserializer : public base::ValueDeserializer { + public: + // This retains a reference to the contents of |json_string|, so the data + // must outlive the JSONStringValueDeserializer. + explicit JSONStringValueDeserializer(const base::StringPiece& json_string); + + ~JSONStringValueDeserializer() override; + // Attempt to deserialize the data structure encoded in the string passed // in to the constructor into a structure of Value objects. If the return // value is null, and if |error_code| is non-null, |error_code| will @@ -46,28 +62,17 @@ base::Value* Deserialize(int* error_code, std::string* error_message) override; - void set_pretty_print(bool new_value) { pretty_print_ = new_value; } - bool pretty_print() { return pretty_print_; } - void set_allow_trailing_comma(bool new_value) { allow_trailing_comma_ = new_value; } private: - bool SerializeInternal(const base::Value& root, bool omit_binary_values); - - // String for writing. Owned by the caller of the constructor. Will be null if - // the serializer was initialized with a const string. - std::string* json_string_; - // String for reading. Data is owned by the caller of the constructor. If - // |json_string_| is non-null, this is a view onto |json_string_|. - base::StringPiece json_string_readonly_; - bool pretty_print_; // If true, serialization will span multiple lines. + // Data is owned by the caller of the constructor. + base::StringPiece json_string_; // If true, deserialization will allow trailing commas. bool allow_trailing_comma_; - DISALLOW_COPY_AND_ASSIGN(JSONStringValueSerializer); + DISALLOW_COPY_AND_ASSIGN(JSONStringValueDeserializer); }; #endif // BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_ -
diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc index d2a84de..225ee675 100644 --- a/base/json/json_value_serializer_unittest.cc +++ b/base/json/json_value_serializer_unittest.cc
@@ -86,28 +86,10 @@ ASSERT_EQ(1, value); } -// Test proper JSON [de]serialization from string is working. -TEST(JSONValueSerializerTest, ReadProperJSONFromString) { +// Test proper JSON deserialization from string is working. +TEST(JSONValueDeserializerTest, ReadProperJSONFromString) { // Try to deserialize it through the serializer. - JSONStringValueSerializer str_deserializer(kProperJSON); - - int error_code = 0; - std::string error_message; - scoped_ptr<Value> value( - str_deserializer.Deserialize(&error_code, &error_message)); - ASSERT_TRUE(value.get()); - ASSERT_EQ(0, error_code); - ASSERT_TRUE(error_message.empty()); - // Verify if the same JSON is still there. - CheckJSONIsStillTheSame(*value); -} - -// Test proper JSON deserialization from a string pointer is working. -TEST(JSONValueSerializerTest, ReadProperJSONFromStringPointer) { - // Try to deserialize a string pointer through the serializer. (This exercises - // a separate code path to passing a StringPiece.) - std::string proper_json(kProperJSON); - JSONStringValueSerializer str_deserializer(&proper_json); + JSONStringValueDeserializer str_deserializer(kProperJSON); int error_code = 0; std::string error_message; @@ -121,12 +103,12 @@ } // Test proper JSON deserialization from a StringPiece substring. -TEST(JSONValueSerializerTest, ReadProperJSONFromStringPiece) { +TEST(JSONValueDeserializerTest, ReadProperJSONFromStringPiece) { // Create a StringPiece for the substring of kProperJSONPadded that matches // kProperJSON. base::StringPiece proper_json(kProperJSONPadded); proper_json = proper_json.substr(5, proper_json.length() - 10); - JSONStringValueSerializer str_deserializer(proper_json); + JSONStringValueDeserializer str_deserializer(proper_json); int error_code = 0; std::string error_message; @@ -141,9 +123,9 @@ // Test that trialing commas are only properly deserialized from string when // the proper flag for that is set. -TEST(JSONValueSerializerTest, ReadJSONWithTrailingCommasFromString) { +TEST(JSONValueDeserializerTest, ReadJSONWithTrailingCommasFromString) { // Try to deserialize it through the serializer. - JSONStringValueSerializer str_deserializer(kProperJSONWithCommas); + JSONStringValueDeserializer str_deserializer(kProperJSONWithCommas); int error_code = 0; std::string error_message; @@ -161,8 +143,8 @@ CheckJSONIsStillTheSame(*value); } -// Test proper JSON [de]serialization from file is working. -TEST(JSONValueSerializerTest, ReadProperJSONFromFile) { +// Test proper JSON deserialization from file is working. +TEST(JSONValueDeserializerTest, ReadProperJSONFromFile) { ScopedTempDir tempdir; ASSERT_TRUE(tempdir.CreateUniqueTempDir()); // Write it down in the file. @@ -171,7 +153,7 @@ WriteFile(temp_file, kProperJSON, strlen(kProperJSON))); // Try to deserialize it through the serializer. - JSONFileValueSerializer file_deserializer(temp_file); + JSONFileValueDeserializer file_deserializer(temp_file); int error_code = 0; std::string error_message; @@ -186,7 +168,7 @@ // Test that trialing commas are only properly deserialized from file when // the proper flag for that is set. -TEST(JSONValueSerializerTest, ReadJSONWithCommasFromFile) { +TEST(JSONValueDeserializerTest, ReadJSONWithCommasFromFile) { ScopedTempDir tempdir; ASSERT_TRUE(tempdir.CreateUniqueTempDir()); // Write it down in the file. @@ -196,7 +178,7 @@ strlen(kProperJSONWithCommas))); // Try to deserialize it through the serializer. - JSONFileValueSerializer file_deserializer(temp_file); + JSONFileValueDeserializer file_deserializer(temp_file); // This must fail without the proper flag. int error_code = 0; std::string error_message; @@ -214,11 +196,27 @@ CheckJSONIsStillTheSame(*value); } +TEST(JSONValueDeserializerTest, AllowTrailingComma) { + scoped_ptr<Value> root; + scoped_ptr<Value> root_expected; + static const char kTestWithCommas[] = "{\"key\": [true,],}"; + static const char kTestNoCommas[] = "{\"key\": [true]}"; + + JSONStringValueDeserializer deserializer(kTestWithCommas); + deserializer.set_allow_trailing_comma(true); + JSONStringValueDeserializer deserializer_expected(kTestNoCommas); + root.reset(deserializer.Deserialize(NULL, NULL)); + ASSERT_TRUE(root.get()); + root_expected.reset(deserializer_expected.Deserialize(NULL, NULL)); + ASSERT_TRUE(root_expected.get()); + ASSERT_TRUE(root->Equals(root_expected.get())); +} + TEST(JSONValueSerializerTest, Roundtrip) { static const char kOriginalSerialization[] = "{\"bool\":true,\"double\":3.14,\"int\":42,\"list\":[1,2],\"null\":null}"; - JSONStringValueSerializer serializer(kOriginalSerialization); - scoped_ptr<Value> root(serializer.Deserialize(NULL, NULL)); + JSONStringValueDeserializer deserializer(kOriginalSerialization); + scoped_ptr<Value> root(deserializer.Deserialize(NULL, NULL)); ASSERT_TRUE(root.get()); ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); @@ -241,10 +239,6 @@ ASSERT_TRUE(root_dict->GetDouble("double", &double_value)); ASSERT_DOUBLE_EQ(3.14, double_value); - // We shouldn't be able to write using this serializer, since it was - // initialized with a const string. - ASSERT_FALSE(serializer.Serialize(*root_dict)); - std::string test_serialization; JSONStringValueSerializer mutable_serializer(&test_serialization); ASSERT_TRUE(mutable_serializer.Serialize(*root_dict)); @@ -331,7 +325,7 @@ ASSERT_EQ(kExpected, actual); // escaped ascii text -> json - JSONStringValueSerializer deserializer(kExpected); + JSONStringValueDeserializer deserializer(kExpected); scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL)); ASSERT_TRUE(deserial_root.get()); DictionaryValue* dict_root = @@ -355,7 +349,7 @@ ASSERT_EQ(kExpected, actual); // escaped ascii text -> json - JSONStringValueSerializer deserializer(kExpected); + JSONStringValueDeserializer deserializer(kExpected); scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL)); ASSERT_TRUE(deserial_root.get()); DictionaryValue* dict_root = @@ -366,7 +360,7 @@ // Test converting escaped regular chars static const char kEscapedChars[] = "{\"test\":\"\\u0067\\u006f\"}"; - JSONStringValueSerializer deserializer2(kEscapedChars); + JSONStringValueDeserializer deserializer2(kEscapedChars); deserial_root.reset(deserializer2.Deserialize(NULL, NULL)); ASSERT_TRUE(deserial_root.get()); dict_root = static_cast<DictionaryValue*>(deserial_root.get()); @@ -374,22 +368,6 @@ ASSERT_EQ(ASCIIToUTF16("go"), test_value); } -TEST(JSONValueSerializerTest, AllowTrailingComma) { - scoped_ptr<Value> root; - scoped_ptr<Value> root_expected; - static const char kTestWithCommas[] = "{\"key\": [true,],}"; - static const char kTestNoCommas[] = "{\"key\": [true]}"; - - JSONStringValueSerializer serializer(kTestWithCommas); - serializer.set_allow_trailing_comma(true); - JSONStringValueSerializer serializer_expected(kTestNoCommas); - root.reset(serializer.Deserialize(NULL, NULL)); - ASSERT_TRUE(root.get()); - root_expected.reset(serializer_expected.Deserialize(NULL, NULL)); - ASSERT_TRUE(root_expected.get()); - ASSERT_TRUE(root->Equals(root_expected.get())); -} - TEST(JSONValueSerializerTest, JSONReaderComments) { ValidateJsonList("[ // 2, 3, ignore me ] \n1 ]"); ValidateJsonList("[ /* 2, \n3, ignore me ]*/ \n1 ]"); @@ -435,7 +413,7 @@ ASSERT_TRUE(PathExists(original_file_path)); - JSONFileValueSerializer deserializer(original_file_path); + JSONFileValueDeserializer deserializer(original_file_path); scoped_ptr<Value> root; root.reset(deserializer.Deserialize(NULL, NULL)); @@ -483,7 +461,7 @@ ASSERT_TRUE(PathExists(original_file_path)); - JSONFileValueSerializer deserializer(original_file_path); + JSONFileValueDeserializer deserializer(original_file_path); scoped_ptr<Value> root; root.reset(deserializer.Deserialize(NULL, NULL)); ASSERT_TRUE(root.get()); @@ -508,9 +486,9 @@ source_file_path = source_file_path.Append( FILE_PATH_LITERAL("serializer_test_nowhitespace.json")); ASSERT_TRUE(PathExists(source_file_path)); - JSONFileValueSerializer serializer(source_file_path); + JSONFileValueDeserializer deserializer(source_file_path); scoped_ptr<Value> root; - root.reset(serializer.Deserialize(NULL, NULL)); + root.reset(deserializer.Deserialize(NULL, NULL)); ASSERT_TRUE(root.get()); }
diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h index accc0d9..353ed7c6 100644 --- a/base/mac/foundation_util.h +++ b/base/mac/foundation_util.h
@@ -296,6 +296,7 @@ CF_CAST_DECL(CGColor); CF_CAST_DECL(CTFont); +CF_CAST_DECL(CTFontDescriptor); CF_CAST_DECL(CTRun); CF_CAST_DECL(SecACL);
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm index 2895b663..27d6e7c 100644 --- a/base/mac/foundation_util.mm +++ b/base/mac/foundation_util.mm
@@ -362,6 +362,7 @@ CF_CAST_DEFN(CGColor); +CF_CAST_DEFN(CTFontDescriptor); CF_CAST_DEFN(CTRun); #if defined(OS_IOS)
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h index 2795b19..25d937e 100644 --- a/base/mac/sdk_forward_declarations.h +++ b/base/mac/sdk_forward_declarations.h
@@ -285,6 +285,10 @@ - (NSString*)UUIDString; @end +@interface NSControl (MountainLionSDK) +@property BOOL allowsExpansionToolTips; +@end + #endif // MAC_OS_X_VERSION_10_8
diff --git a/base/memory/discardable_shared_memory.h b/base/memory/discardable_shared_memory.h index 59c5d5b5..e3b437c 100644 --- a/base/memory/discardable_shared_memory.h +++ b/base/memory/discardable_shared_memory.h
@@ -74,7 +74,7 @@ // must have been mapped via Map(). void* memory() const; - // Returns the last know usage time for DiscardableSharedMemory object. This + // Returns the last known usage time for DiscardableSharedMemory object. This // may be earlier than the "true" usage time when memory has been used by a // different process. Returns NULL time if purged. Time last_known_usage() const { return last_known_usage_; } @@ -84,7 +84,7 @@ // for two reasons; object might be locked or our last known usage timestamp // might be out of date. Last known usage time is updated to |current_time| // if locked or the actual last usage timestamp if unlocked. It is often - // neccesary to call this function twice for the object to successfully be + // necessary to call this function twice for the object to successfully be // purged. First call, updates |last_known_usage_|. Second call, successfully // purges the object using the updated |last_known_usage_|. // Note: there is no guarantee that multiple calls to this function will
diff --git a/base/prefs/base_prefs_switches.cc b/base/prefs/base_prefs_switches.cc new file mode 100644 index 0000000..304248b7 --- /dev/null +++ b/base/prefs/base_prefs_switches.cc
@@ -0,0 +1,12 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/prefs/base_prefs_switches.h" + +namespace switches { + +// Pretty-prints pref JSON files. +const char kPrettyPrintPrefs[] = "pretty-print-prefs"; + +} // namespace switches
diff --git a/base/prefs/base_prefs_switches.h b/base/prefs/base_prefs_switches.h new file mode 100644 index 0000000..7a6b665 --- /dev/null +++ b/base/prefs/base_prefs_switches.h
@@ -0,0 +1,14 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_PREFS_BASE_PREFS_SWITCHES_H_ +#define BASE_PREFS_BASE_PREFS_SWITCHES_H_ + +namespace switches { + +extern const char kPrettyPrintPrefs[]; + +} // namespace switches + +#endif // BASE_PREFS_BASE_PREFS_SWITCHES_H_
diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc index c52a95c9..2e34b50 100644 --- a/base/prefs/json_pref_store.cc +++ b/base/prefs/json_pref_store.cc
@@ -8,12 +8,14 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/json/json_file_value_serializer.h" #include "base/json/json_string_value_serializer.h" #include "base/memory/ref_counted.h" #include "base/metrics/histogram.h" +#include "base/prefs/base_prefs_switches.h" #include "base/prefs/pref_filter.h" #include "base/sequenced_task_runner.h" #include "base/strings/string_util.h" @@ -56,16 +58,16 @@ DVLOG(1) << "Error while loading JSON file: " << error_msg << ", file: " << path.value(); switch (error_code) { - case JSONFileValueSerializer::JSON_ACCESS_DENIED: + case JSONFileValueDeserializer::JSON_ACCESS_DENIED: return PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED; break; - case JSONFileValueSerializer::JSON_CANNOT_READ_FILE: + case JSONFileValueDeserializer::JSON_CANNOT_READ_FILE: return PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER; break; - case JSONFileValueSerializer::JSON_FILE_LOCKED: + case JSONFileValueDeserializer::JSON_FILE_LOCKED: return PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED; break; - case JSONFileValueSerializer::JSON_NO_SUCH_FILE: + case JSONFileValueDeserializer::JSON_NO_SUCH_FILE: return PersistentPrefStore::PREF_READ_ERROR_NO_FILE; break; default: @@ -119,14 +121,14 @@ std::string error_msg; scoped_ptr<JsonPrefStore::ReadResult> read_result( new JsonPrefStore::ReadResult); - JSONFileValueSerializer serializer(path); - read_result->value.reset(serializer.Deserialize(&error_code, &error_msg)); + JSONFileValueDeserializer deserializer(path); + read_result->value.reset(deserializer.Deserialize(&error_code, &error_msg)); read_result->error = HandleReadErrors(read_result->value.get(), path, error_code, error_msg); read_result->no_dir = !base::PathExists(path.DirName()); if (read_result->error == PersistentPrefStore::PREF_READ_ERROR_NONE) - RecordJsonDataSizeHistogram(path, serializer.get_last_read_size()); + RecordJsonDataSizeHistogram(path, deserializer.get_last_read_size()); return read_result.Pass(); } @@ -398,7 +400,10 @@ pref_filter_->FilterSerializeData(prefs_.get()); JSONStringValueSerializer serializer(output); - serializer.set_pretty_print(true); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kPrettyPrintPrefs)) { + serializer.set_pretty_print(true); + } return serializer.Serialize(*prefs_); }
diff --git a/base/process/kill.cc b/base/process/kill.cc index caca348..a647d96 100644 --- a/base/process/kill.cc +++ b/base/process/kill.cc
@@ -14,11 +14,8 @@ bool result = true; NamedProcessIterator iter(executable_name, filter); while (const ProcessEntry* entry = iter.NextProcessEntry()) { -#if defined(OS_WIN) - result &= KillProcessById(entry->pid(), exit_code, true); -#else - result &= KillProcess(entry->pid(), exit_code, true); -#endif + Process process = Process::Open(entry->pid()); + result &= KillProcess(process.Handle(), exit_code, true); } return result; }
diff --git a/base/process/kill.h b/base/process/kill.h index 8c0a213d..df0d95e 100644 --- a/base/process/kill.h +++ b/base/process/kill.h
@@ -57,12 +57,6 @@ BASE_EXPORT bool KillProcessGroup(ProcessHandle process_group_id); #endif // defined(OS_POSIX) -#if defined(OS_WIN) -BASE_EXPORT bool KillProcessById(ProcessId process_id, - int exit_code, - bool wait); -#endif // defined(OS_WIN) - // Get the termination status of the process by interpreting the // circumstances of the child process' death. |exit_code| is set to // the status returned by waitpid() on POSIX, and from @@ -94,22 +88,6 @@ ProcessHandle handle, int* exit_code); #endif // defined(OS_POSIX) -// Waits for process to exit. On POSIX systems, if the process hasn't been -// signaled then puts the exit code in |exit_code|; otherwise it's considered -// a failure. On Windows |exit_code| is always filled. Returns true on success, -// and closes |handle| in any case. -BASE_EXPORT bool WaitForExitCode(ProcessHandle handle, int* exit_code); - -// Waits for process to exit. If it did exit within |timeout_milliseconds|, -// then puts the exit code in |exit_code|, and returns true. -// In POSIX systems, if the process has been signaled then |exit_code| is set -// to -1. Returns false on failure (the caller is then responsible for closing -// |handle|). -// The caller is always responsible for closing the |handle|. -BASE_EXPORT bool WaitForExitCodeWithTimeout(ProcessHandle handle, - int* exit_code, - base::TimeDelta timeout); - // Wait for all the processes based on the named executable to exit. If filter // is non-null, then only processes selected by the filter are waited on. // Returns after all processes have exited or wait_milliseconds have expired.
diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc index 77705eeb..298486bf 100644 --- a/base/process/kill_posix.cc +++ b/base/process/kill_posix.cc
@@ -22,161 +22,6 @@ namespace { -#if !defined(OS_NACL_NONSFI) -bool WaitpidWithTimeout(ProcessHandle handle, - int* status, - base::TimeDelta wait) { - // This POSIX version of this function only guarantees that we wait no less - // than |wait| for the process to exit. The child process may - // exit sometime before the timeout has ended but we may still block for up - // to 256 milliseconds after the fact. - // - // waitpid() has no direct support on POSIX for specifying a timeout, you can - // either ask it to block indefinitely or return immediately (WNOHANG). - // When a child process terminates a SIGCHLD signal is sent to the parent. - // Catching this signal would involve installing a signal handler which may - // affect other parts of the application and would be difficult to debug. - // - // Our strategy is to call waitpid() once up front to check if the process - // has already exited, otherwise to loop for |wait|, sleeping for - // at most 256 milliseconds each time using usleep() and then calling - // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and - // we double it every 4 sleep cycles. - // - // usleep() is speced to exit if a signal is received for which a handler - // has been installed. This means that when a SIGCHLD is sent, it will exit - // depending on behavior external to this function. - // - // This function is used primarily for unit tests, if we want to use it in - // the application itself it would probably be best to examine other routes. - - if (wait.InMilliseconds() == base::kNoTimeout) { - return HANDLE_EINTR(waitpid(handle, status, 0)) > 0; - } - - pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG)); - static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds. - int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds. - int64 double_sleep_time = 0; - - // If the process hasn't exited yet, then sleep and try again. - TimeTicks wakeup_time = TimeTicks::Now() + wait; - while (ret_pid == 0) { - TimeTicks now = TimeTicks::Now(); - if (now > wakeup_time) - break; - // Guaranteed to be non-negative! - int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); - // Sleep for a bit while we wait for the process to finish. - if (sleep_time_usecs > max_sleep_time_usecs) - sleep_time_usecs = max_sleep_time_usecs; - - // usleep() will return 0 and set errno to EINTR on receipt of a signal - // such as SIGCHLD. - usleep(sleep_time_usecs); - ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG)); - - if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) && - (double_sleep_time++ % 4 == 0)) { - max_sleep_time_usecs *= 2; - } - } - - return ret_pid > 0; -} - -#if defined(OS_MACOSX) -// Using kqueue on Mac so that we can wait on non-child processes. -// We can't use kqueues on child processes because we need to reap -// our own children using wait. -static bool WaitForSingleNonChildProcess(ProcessHandle handle, - TimeDelta wait) { - DCHECK_GT(handle, 0); - DCHECK(wait.InMilliseconds() == kNoTimeout || wait > TimeDelta()); - - ScopedFD kq(kqueue()); - if (!kq.is_valid()) { - DPLOG(ERROR) << "kqueue"; - return false; - } - - struct kevent change = {0}; - EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); - int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL)); - if (result == -1) { - if (errno == ESRCH) { - // If the process wasn't found, it must be dead. - return true; - } - - DPLOG(ERROR) << "kevent (setup " << handle << ")"; - return false; - } - - // Keep track of the elapsed time to be able to restart kevent if it's - // interrupted. - bool wait_forever = wait.InMilliseconds() == kNoTimeout; - TimeDelta remaining_delta; - TimeTicks deadline; - if (!wait_forever) { - remaining_delta = wait; - deadline = TimeTicks::Now() + remaining_delta; - } - - result = -1; - struct kevent event = {0}; - - while (wait_forever || remaining_delta > TimeDelta()) { - struct timespec remaining_timespec; - struct timespec* remaining_timespec_ptr; - if (wait_forever) { - remaining_timespec_ptr = NULL; - } else { - remaining_timespec = remaining_delta.ToTimeSpec(); - remaining_timespec_ptr = &remaining_timespec; - } - - result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr); - - if (result == -1 && errno == EINTR) { - if (!wait_forever) { - remaining_delta = deadline - TimeTicks::Now(); - } - result = 0; - } else { - break; - } - } - - if (result < 0) { - DPLOG(ERROR) << "kevent (wait " << handle << ")"; - return false; - } else if (result > 1) { - DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result " - << result; - return false; - } else if (result == 0) { - // Timed out. - return false; - } - - DCHECK_EQ(result, 1); - - if (event.filter != EVFILT_PROC || - (event.fflags & NOTE_EXIT) == 0 || - event.ident != static_cast<uintptr_t>(handle)) { - DLOG(ERROR) << "kevent (wait " << handle - << "): unexpected event: filter=" << event.filter - << ", fflags=" << event.fflags - << ", ident=" << event.ident; - return false; - } - - return true; -} -#endif // OS_MACOSX -#endif // !defined(OS_NACL_NONSFI) - TerminationStatus GetTerminationStatusImpl(ProcessHandle handle, bool can_block, int* exit_code) { @@ -302,52 +147,6 @@ } #if !defined(OS_NACL_NONSFI) -bool WaitForExitCode(ProcessHandle handle, int* exit_code) { - int status; - if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) { - NOTREACHED(); - return false; - } - - if (WIFEXITED(status)) { - *exit_code = WEXITSTATUS(status); - return true; - } - - // If it didn't exit cleanly, it must have been signaled. - DCHECK(WIFSIGNALED(status)); - return false; -} - -bool WaitForExitCodeWithTimeout(ProcessHandle handle, - int* exit_code, - TimeDelta timeout) { - ProcessHandle parent_pid = GetParentProcessId(handle); - ProcessHandle our_pid = GetCurrentProcessHandle(); - if (parent_pid != our_pid) { -#if defined(OS_MACOSX) - // On Mac we can wait on non child processes. - return WaitForSingleNonChildProcess(handle, timeout); -#else - // Currently on Linux we can't handle non child processes. - NOTIMPLEMENTED(); -#endif // OS_MACOSX - } - - int status; - if (!WaitpidWithTimeout(handle, &status, timeout)) - return false; - if (WIFSIGNALED(status)) { - *exit_code = -1; - return true; - } - if (WIFEXITED(status)) { - *exit_code = WEXITSTATUS(status); - return true; - } - return false; -} - bool WaitForProcessesToExit(const FilePath::StringType& executable_name, TimeDelta wait, const ProcessFilter* filter) {
diff --git a/base/process/kill_win.cc b/base/process/kill_win.cc index 387c9e2..3c93047 100644 --- a/base/process/kill_win.cc +++ b/base/process/kill_win.cc
@@ -101,22 +101,6 @@ return result; } -// Attempts to kill the process identified by the given process -// entry structure, giving it the specified exit code. -// Returns true if this is successful, false otherwise. -bool KillProcessById(ProcessId process_id, int exit_code, bool wait) { - HANDLE process = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, - FALSE, // Don't inherit handle - process_id); - if (!process) { - DPLOG(ERROR) << "Unable to open process " << process_id; - return false; - } - bool ret = KillProcess(process, exit_code, wait); - CloseHandle(process); - return ret; -} - TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { DWORD tmp_exit_code = 0; @@ -175,26 +159,6 @@ } } -bool WaitForExitCode(ProcessHandle handle, int* exit_code) { - // TODO(rvargas) crbug.com/417532: Remove this function. - Process process(handle); - return process.WaitForExit(exit_code); -} - -bool WaitForExitCodeWithTimeout(ProcessHandle handle, - int* exit_code, - TimeDelta timeout) { - if (::WaitForSingleObject( - handle, static_cast<DWORD>(timeout.InMilliseconds())) != WAIT_OBJECT_0) - return false; - DWORD temp_code; // Don't clobber out-parameters in case of failure. - if (!::GetExitCodeProcess(handle, &temp_code)) - return false; - - *exit_code = temp_code; - return true; -} - bool WaitForProcessesToExit(const FilePath::StringType& executable_name, TimeDelta wait, const ProcessFilter* filter) {
diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc index 203b7c8..f9963fa 100644 --- a/base/process/launch_posix.cc +++ b/base/process/launch_posix.cc
@@ -33,7 +33,7 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/posix/eintr_wrapper.h" -#include "base/process/kill.h" +#include "base/process/process.h" #include "base/process/process_metrics.h" #include "base/strings/stringprintf.h" #include "base/synchronization/waitable_event.h" @@ -684,7 +684,8 @@ // Always wait for exit code (even if we know we'll declare // GOT_MAX_OUTPUT). - bool success = WaitForExitCode(pid, exit_code); + Process process(pid); + bool success = process.WaitForExit(exit_code); // If we stopped because we read as much as we wanted, we return // GOT_MAX_OUTPUT (because the child may exit due to |SIGPIPE|).
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc index bc2f3f8..a36bf77 100644 --- a/base/process/process_posix.cc +++ b/base/process/process_posix.cc
@@ -5,12 +5,206 @@ #include "base/process/process.h" #include <sys/resource.h> -#include <sys/time.h> -#include <sys/types.h> +#include <sys/wait.h> +#include "base/files/scoped_file.h" #include "base/logging.h" +#include "base/posix/eintr_wrapper.h" #include "base/process/kill.h" +#if defined(OS_MACOSX) +#include <sys/event.h> +#endif + +namespace { + +#if !defined(OS_NACL_NONSFI) + +bool WaitpidWithTimeout(base::ProcessHandle handle, + int* status, + base::TimeDelta wait) { + // This POSIX version of this function only guarantees that we wait no less + // than |wait| for the process to exit. The child process may + // exit sometime before the timeout has ended but we may still block for up + // to 256 milliseconds after the fact. + // + // waitpid() has no direct support on POSIX for specifying a timeout, you can + // either ask it to block indefinitely or return immediately (WNOHANG). + // When a child process terminates a SIGCHLD signal is sent to the parent. + // Catching this signal would involve installing a signal handler which may + // affect other parts of the application and would be difficult to debug. + // + // Our strategy is to call waitpid() once up front to check if the process + // has already exited, otherwise to loop for |wait|, sleeping for + // at most 256 milliseconds each time using usleep() and then calling + // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and + // we double it every 4 sleep cycles. + // + // usleep() is speced to exit if a signal is received for which a handler + // has been installed. This means that when a SIGCHLD is sent, it will exit + // depending on behavior external to this function. + // + // This function is used primarily for unit tests, if we want to use it in + // the application itself it would probably be best to examine other routes. + + if (wait == base::TimeDelta::Max()) { + return HANDLE_EINTR(waitpid(handle, status, 0)) > 0; + } + + pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG)); + static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds. + int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds. + int64 double_sleep_time = 0; + + // If the process hasn't exited yet, then sleep and try again. + base::TimeTicks wakeup_time = base::TimeTicks::Now() + wait; + while (ret_pid == 0) { + base::TimeTicks now = base::TimeTicks::Now(); + if (now > wakeup_time) + break; + // Guaranteed to be non-negative! + int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); + // Sleep for a bit while we wait for the process to finish. + if (sleep_time_usecs > max_sleep_time_usecs) + sleep_time_usecs = max_sleep_time_usecs; + + // usleep() will return 0 and set errno to EINTR on receipt of a signal + // such as SIGCHLD. + usleep(sleep_time_usecs); + ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG)); + + if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) && + (double_sleep_time++ % 4 == 0)) { + max_sleep_time_usecs *= 2; + } + } + + return ret_pid > 0; +} + +#if defined(OS_MACOSX) +// Using kqueue on Mac so that we can wait on non-child processes. +// We can't use kqueues on child processes because we need to reap +// our own children using wait. +static bool WaitForSingleNonChildProcess(base::ProcessHandle handle, + base::TimeDelta wait) { + DCHECK_GT(handle, 0); + DCHECK_GT(wait, base::TimeDelta()); + + base::ScopedFD kq(kqueue()); + if (!kq.is_valid()) { + DPLOG(ERROR) << "kqueue"; + return false; + } + + struct kevent change = {0}; + EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); + int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL)); + if (result == -1) { + if (errno == ESRCH) { + // If the process wasn't found, it must be dead. + return true; + } + + DPLOG(ERROR) << "kevent (setup " << handle << ")"; + return false; + } + + // Keep track of the elapsed time to be able to restart kevent if it's + // interrupted. + bool wait_forever = (wait == base::TimeDelta::Max()); + base::TimeDelta remaining_delta; + base::TimeTicks deadline; + if (!wait_forever) { + remaining_delta = wait; + deadline = base::TimeTicks::Now() + remaining_delta; + } + + result = -1; + struct kevent event = {0}; + + while (wait_forever || remaining_delta > base::TimeDelta()) { + struct timespec remaining_timespec; + struct timespec* remaining_timespec_ptr; + if (wait_forever) { + remaining_timespec_ptr = NULL; + } else { + remaining_timespec = remaining_delta.ToTimeSpec(); + remaining_timespec_ptr = &remaining_timespec; + } + + result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr); + + if (result == -1 && errno == EINTR) { + if (!wait_forever) { + remaining_delta = deadline - base::TimeTicks::Now(); + } + result = 0; + } else { + break; + } + } + + if (result < 0) { + DPLOG(ERROR) << "kevent (wait " << handle << ")"; + return false; + } else if (result > 1) { + DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result " + << result; + return false; + } else if (result == 0) { + // Timed out. + return false; + } + + DCHECK_EQ(result, 1); + + if (event.filter != EVFILT_PROC || + (event.fflags & NOTE_EXIT) == 0 || + event.ident != static_cast<uintptr_t>(handle)) { + DLOG(ERROR) << "kevent (wait " << handle + << "): unexpected event: filter=" << event.filter + << ", fflags=" << event.fflags + << ", ident=" << event.ident; + return false; + } + + return true; +} +#endif // OS_MACOSX + +bool WaitForExitWithTimeoutImpl(base::ProcessHandle handle, + int* exit_code, + base::TimeDelta timeout) { + base::ProcessHandle parent_pid = base::GetParentProcessId(handle); + base::ProcessHandle our_pid = base::GetCurrentProcessHandle(); + if (parent_pid != our_pid) { +#if defined(OS_MACOSX) + // On Mac we can wait on non child processes. + return WaitForSingleNonChildProcess(handle, timeout); +#else + // Currently on Linux we can't handle non child processes. + NOTIMPLEMENTED(); +#endif // OS_MACOSX + } + + int status; + if (!WaitpidWithTimeout(handle, &status, timeout)) + return false; + if (WIFSIGNALED(status)) { + *exit_code = -1; + return true; + } + if (WIFEXITED(status)) { + *exit_code = WEXITSTATUS(status); + return true; + } + return false; +} +#endif // !defined(OS_NACL_NONSFI) + +} // namespace + namespace base { Process::Process(ProcessHandle handle) : process_(handle) { @@ -102,15 +296,11 @@ } bool Process::WaitForExit(int* exit_code) { - // TODO(rvargas) crbug.com/417532: Remove this constant. - const int kNoTimeout = -1; - return WaitForExitWithTimeout(TimeDelta::FromMilliseconds(kNoTimeout), - exit_code); + return WaitForExitWithTimeout(TimeDelta::Max(), exit_code); } bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) { - // TODO(rvargas) crbug.com/417532: Move the implementation here. - return base::WaitForExitCodeWithTimeout(Handle(), exit_code, timeout); + return WaitForExitWithTimeoutImpl(Handle(), exit_code, timeout); } #if !defined(OS_LINUX)
diff --git a/base/process/process_win.cc b/base/process/process_win.cc index 8e5360b3..b62fdb4f 100644 --- a/base/process/process_win.cc +++ b/base/process/process_win.cc
@@ -7,6 +7,7 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/metrics/field_trial.h" +#include "base/numerics/safe_conversions.h" #include "base/process/kill.h" #include "base/win/windows_version.h" @@ -141,10 +142,17 @@ } bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) { - // TODO(rvargas) crbug.com/417532: Move the implementation here. - if (timeout > TimeDelta::FromMilliseconds(INFINITE)) - timeout = TimeDelta::FromMilliseconds(INFINITE); - return base::WaitForExitCodeWithTimeout(Handle(), exit_code, timeout); + // Limit timeout to INFINITE. + DWORD timeout_ms = saturated_cast<DWORD>(timeout.InMilliseconds()); + if (::WaitForSingleObject(Handle(), timeout_ms) != WAIT_OBJECT_0) + return false; + + DWORD temp_code; // Don't clobber out-parameters in case of failure. + if (!::GetExitCodeProcess(Handle(), &temp_code)) + return false; + + *exit_code = temp_code; + return true; } bool Process::IsProcessBackgrounded() const {
diff --git a/base/synchronization/waitable_event.h b/base/synchronization/waitable_event.h index 5adc1ec6..c35af54 100644 --- a/base/synchronization/waitable_event.h +++ b/base/synchronization/waitable_event.h
@@ -21,9 +21,6 @@ namespace base { -// This replaces INFINITE from Win32 -static const int kNoTimeout = -1; - class TimeDelta; // A WaitableEvent can be a useful thread synchronization tool when you want to
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn index 05a3dc3..120159ee 100644 --- a/base/test/BUILD.gn +++ b/base/test/BUILD.gn
@@ -36,6 +36,8 @@ "mock_chrome_application_mac.mm", "mock_devices_changed_observer.cc", "mock_devices_changed_observer.h", + "mock_log.cc", + "mock_log.h", "multiprocess_test.cc", "multiprocess_test.h", "multiprocess_test_android.cc",
diff --git a/base/test/data/prefs/write.golden.json b/base/test/data/prefs/write.golden.json index 9a5523c..fb1fff1 100644 --- a/base/test/data/prefs/write.golden.json +++ b/base/test/data/prefs/write.golden.json
@@ -1,11 +1 @@ -{ - "homepage": "http://www.cnn.com", - "long_int": { - "pref": "214748364842" - }, - "some_directory": "/usr/sbin/", - "tabs": { - "max_tabs": 10, - "new_windows_in_tabs": false - } -} +{"homepage":"http://www.cnn.com","long_int":{"pref":"214748364842"},"some_directory":"/usr/sbin/","tabs":{"max_tabs":10,"new_windows_in_tabs":false}} \ No newline at end of file
diff --git a/base/test/gtest_util.cc b/base/test/gtest_util.cc index c0bc04a6..b811194 100644 --- a/base/test/gtest_util.cc +++ b/base/test/gtest_util.cc
@@ -47,7 +47,7 @@ bool ReadTestNamesFromFile(const FilePath& path, std::vector<SplitTestName>* output) { - JSONFileValueSerializer deserializer(path); + JSONFileValueDeserializer deserializer(path); int error_code = 0; std::string error_message; scoped_ptr<base::Value> value( @@ -80,4 +80,4 @@ return true; } -} // namespace +} // namespace base
diff --git a/base/test/mock_log.cc b/base/test/mock_log.cc new file mode 100644 index 0000000..fa511d4 --- /dev/null +++ b/base/test/mock_log.cc
@@ -0,0 +1,68 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/test/mock_log.h" + +namespace base { +namespace test { + +// static +MockLog* MockLog::g_instance_ = nullptr; +Lock MockLog::g_lock; + +MockLog::MockLog() : is_capturing_logs_(false) { +} + +MockLog::~MockLog() { + if (is_capturing_logs_) { + StopCapturingLogs(); + } +} + +void MockLog::StartCapturingLogs() { + AutoLock scoped_lock(g_lock); + + // We don't use CHECK(), which can generate a new LOG message, and + // thus can confuse MockLog objects or other registered + // LogSinks. + RAW_CHECK(!is_capturing_logs_); + RAW_CHECK(!g_instance_); + + is_capturing_logs_ = true; + g_instance_ = this; + previous_handler_ = logging::GetLogMessageHandler(); + logging::SetLogMessageHandler(LogMessageHandler); +} + +void MockLog::StopCapturingLogs() { + AutoLock scoped_lock(g_lock); + + // We don't use CHECK(), which can generate a new LOG message, and + // thus can confuse MockLog objects or other registered + // LogSinks. + RAW_CHECK(is_capturing_logs_); + RAW_CHECK(g_instance_ == this); + + is_capturing_logs_ = false; + logging::SetLogMessageHandler(previous_handler_); + g_instance_ = nullptr; +} + +// static +bool MockLog::LogMessageHandler(int severity, + const char* file, + int line, + size_t message_start, + const std::string& str) { + // gMock guarantees thread-safety for calling a mocked method + // (https://code.google.com/p/googlemock/wiki/CookBook#Using_Google_Mock_and_Threads) + // but we also need to make sure that Start/StopCapturingLogs are synchronized + // with LogMessageHandler. + AutoLock scoped_lock(g_lock); + + return g_instance_->Log(severity, file, line, message_start, str); +} + +} // namespace test +} // namespace base
diff --git a/base/test/mock_log.h b/base/test/mock_log.h new file mode 100644 index 0000000..315ef1f --- /dev/null +++ b/base/test/mock_log.h
@@ -0,0 +1,98 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_TEST_MOCK_LOG_H_ +#define BASE_TEST_MOCK_LOG_H_ + +#include <string> + +#include "base/logging.h" +#include "base/macros.h" +#include "base/synchronization/lock.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace base { +namespace test { + +// A MockLog object intercepts LOG() messages issued during its lifespan. Using +// this together with gMock, it's very easy to test how a piece of code calls +// LOG(). The typical usage: +// +// TEST(FooTest, LogsCorrectly) { +// MockLog log; +// +// // We expect the WARNING "Something bad!" exactly twice. +// EXPECT_CALL(log, Log(WARNING, _, "Something bad!")) +// .Times(2); +// +// // We allow foo.cc to call LOG(INFO) any number of times. +// EXPECT_CALL(log, Log(INFO, HasSubstr("/foo.cc"), _)) +// .Times(AnyNumber()); +// +// log.StartCapturingLogs(); // Call this after done setting expectations. +// Foo(); // Exercises the code under test. +// } +// +// CAVEAT: base/logging does not allow a thread to call LOG() again when it's +// already inside a LOG() call. Doing so will cause a deadlock. Therefore, +// it's the user's responsibility to not call LOG() in an action triggered by +// MockLog::Log(). You may call RAW_LOG() instead. +class MockLog { + public: + // Creates a MockLog object that is not capturing logs. If it were to start + // to capture logs, it could be a problem if some other threads already exist + // and are logging, as the user hasn't had a chance to set up expectation on + // this object yet (calling a mock method before setting the expectation is + // UNDEFINED behavior). + MockLog(); + + // When the object is destructed, it stops intercepting logs. + ~MockLog(); + + // Starts log capturing if the object isn't already doing so. + // Otherwise crashes. + void StartCapturingLogs(); + + // Stops log capturing if the object is capturing logs. Otherwise crashes. + void StopCapturingLogs(); + + // Log method is invoked for every log message before it's sent to other log + // destinations (if any). The method should return true to signal that it + // handled the message and the message should not be sent to other log + // destinations. + MOCK_METHOD5(Log, + bool(int severity, + const char* file, + int line, + size_t message_start, + const std::string& str)); + + private: + // The currently active mock log. + static MockLog* g_instance_; + + // Lock protecting access to g_instance_. + static Lock g_lock; + + // Static function which is set as the logging message handler. + // Called once for each message. + static bool LogMessageHandler(int severity, + const char* file, + int line, + size_t message_start, + const std::string& str); + + // True if this object is currently capturing logs. + bool is_capturing_logs_; + + // The previous handler to restore when the MockLog is destroyed. + logging::LogMessageHandlerFunction previous_handler_; + + DISALLOW_COPY_AND_ASSIGN(MockLog); +}; + +} // namespace test +} // namespace base + +#endif // BASE_TEST_MOCK_LOG_H_
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc index 3430169..cbed238 100644 --- a/base/trace_event/memory_dump_manager.cc +++ b/base/trace_event/memory_dump_manager.cc
@@ -6,6 +6,7 @@ #include <algorithm> +#include "base/atomic_sequence_num.h" #include "base/compiler_specific.h" #include "base/trace_event/memory_dump_provider.h" #include "base/trace_event/process_memory_dump.h" @@ -15,7 +16,27 @@ namespace trace_event { namespace { + MemoryDumpManager* g_instance_for_testing = nullptr; +const int kTraceEventNumArgs = 1; +const char* kTraceEventArgNames[] = {"dumps"}; +const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE}; +StaticAtomicSequenceNumber g_next_guid; + +const char* DumpPointTypeToString(const DumpPointType& dump_point_type) { + switch (dump_point_type) { + case DumpPointType::TASK_BEGIN: + return "TASK_BEGIN"; + case DumpPointType::TASK_END: + return "TASK_END"; + case DumpPointType::PERIODIC_INTERVAL: + return "PERIODIC_INTERVAL"; + case DumpPointType::EXPLICITLY_TRIGGERED: + return "EXPLICITLY_TRIGGERED"; + } + NOTREACHED(); + return "UNKNOWN"; +} } // TODO(primiano): this should be smarter and should do something similar to @@ -76,13 +97,18 @@ dump_providers_enabled_.erase(it); } -void MemoryDumpManager::RequestDumpPoint(DumpPointType type) { - // TODO(primiano): this will have more logic, IPC broadcast & co. +void MemoryDumpManager::RequestDumpPoint(DumpPointType dump_point_type) { + // TODO(primiano): this will have more logic to coordinate dump points across + // multiple processes via IPC. See crbug.com/462930. + // Bail out immediately if tracing is not enabled at all. if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_))) return; - CreateLocalDumpPoint(); + // TODO(primiano): Make guid actually unique (cross-process) by hashing it + // with the PID. See crbug.com/462931 for details. + const uint64 guid = g_next_guid.GetNext(); + CreateLocalDumpPoint(dump_point_type, guid); } void MemoryDumpManager::BroadcastDumpRequest() { @@ -90,23 +116,28 @@ } // Creates a dump point for the current process and appends it to the trace. -void MemoryDumpManager::CreateLocalDumpPoint() { - AutoLock lock(lock_); +void MemoryDumpManager::CreateLocalDumpPoint(DumpPointType dump_point_type, + uint64 guid) { bool did_any_provider_dump = false; scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump()); - for (auto it = dump_providers_enabled_.begin(); - it != dump_providers_enabled_.end();) { - MemoryDumpProvider* dump_provider = *it; - if (!dump_provider->DumpInto(pmd.get())) { - LOG(ERROR) << "The memory dumper " << dump_provider->GetFriendlyName() - << " failed, possibly due to sandboxing (crbug.com/461788), " - "disabling it for current process. Try restarting chrome " - "with the --no-sandbox switch."; - it = dump_providers_enabled_.erase(it); - } else { - did_any_provider_dump = true; - ++it; + // Serialize dump point generation so that memory dump providers don't have to + // deal with thread safety. + { + AutoLock lock(lock_); + for (auto it = dump_providers_enabled_.begin(); + it != dump_providers_enabled_.end();) { + MemoryDumpProvider* dump_provider = *it; + if (dump_provider->DumpInto(pmd.get())) { + did_any_provider_dump = true; + ++it; + } else { + LOG(ERROR) << "The memory dumper " << dump_provider->GetFriendlyName() + << " failed, possibly due to sandboxing (crbug.com/461788), " + "disabling it for current process. Try restarting chrome " + "with the --no-sandbox switch."; + it = dump_providers_enabled_.erase(it); + } } } @@ -114,9 +145,15 @@ if (!did_any_provider_dump) return; - scoped_refptr<TracedValue> value(new TracedValue()); - pmd->AsValueInto(value.get()); - // TODO(primiano): add the dump point to the trace at this point. + scoped_refptr<ConvertableToTraceFormat> event_value(new TracedValue()); + pmd->AsValueInto(static_cast<TracedValue*>(event_value.get())); + const char* const event_name = DumpPointTypeToString(dump_point_type); + + TRACE_EVENT_API_ADD_TRACE_EVENT( + TRACE_EVENT_PHASE_MEMORY_DUMP, + TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name, guid, + kTraceEventNumArgs, kTraceEventArgNames, kTraceEventArgTypes, + NULL /* arg_values */, &event_value, TRACE_EVENT_FLAG_HAS_ID); } void MemoryDumpManager::OnTraceLogEnabled() {
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h index 1a22e61..8a9b3b7e 100644 --- a/base/trace_event/memory_dump_manager.h +++ b/base/trace_event/memory_dump_manager.h
@@ -43,7 +43,7 @@ // Requests a memory dump. The dump might happen or not depending on the // filters and categories specified when enabling tracing. - void RequestDumpPoint(DumpPointType type); + void RequestDumpPoint(DumpPointType dump_point_type); // TraceLog::EnabledStateObserver implementation. void OnTraceLogEnabled() override; @@ -65,7 +65,7 @@ void BroadcastDumpRequest(); // Creates a dump point for the current process and appends it to the trace. - void CreateLocalDumpPoint(); + void CreateLocalDumpPoint(DumpPointType dump_point_type, uint64 guid); std::vector<MemoryDumpProvider*> dump_providers_registered_; // Not owned. std::vector<MemoryDumpProvider*> dump_providers_enabled_; // Not owned.
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h index e12d8f42..c30a84a 100644 --- a/base/trace_event/trace_event.h +++ b/base/trace_event/trace_event.h
@@ -1039,6 +1039,7 @@ #define TRACE_EVENT_PHASE_CREATE_OBJECT ('N') #define TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ('O') #define TRACE_EVENT_PHASE_DELETE_OBJECT ('D') +#define TRACE_EVENT_PHASE_MEMORY_DUMP ('v') // Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT. #define TRACE_EVENT_FLAG_NONE (static_cast<unsigned char>(0))
diff --git a/base/values.cc b/base/values.cc index 061b7a1..52876cf 100644 --- a/base/values.cc +++ b/base/values.cc
@@ -1143,6 +1143,9 @@ ValueSerializer::~ValueSerializer() { } +ValueDeserializer::~ValueDeserializer() { +} + std::ostream& operator<<(std::ostream& out, const Value& value) { std::string json; JSONWriter::WriteWithOptions(&value,
diff --git a/base/values.h b/base/values.h index 4648283a..1e1cae3 100644 --- a/base/values.h +++ b/base/values.h
@@ -492,13 +492,20 @@ DISALLOW_COPY_AND_ASSIGN(ListValue); }; -// This interface is implemented by classes that know how to serialize and -// deserialize Value objects. +// This interface is implemented by classes that know how to serialize +// Value objects. class BASE_EXPORT ValueSerializer { public: virtual ~ValueSerializer(); virtual bool Serialize(const Value& root) = 0; +}; + +// This interface is implemented by classes that know how to deserialize Value +// objects. +class BASE_EXPORT ValueDeserializer { + public: + virtual ~ValueDeserializer(); // This method deserializes the subclass-specific format into a Value object. // If the return value is non-NULL, the caller takes ownership of returned
diff --git a/base/win/scoped_process_information_unittest.cc b/base/win/scoped_process_information_unittest.cc index ccfa729..614504d4 100644 --- a/base/win/scoped_process_information_unittest.cc +++ b/base/win/scoped_process_information_unittest.cc
@@ -8,6 +8,7 @@ #include "base/command_line.h" #include "base/process/kill.h" +#include "base/process/process.h" #include "base/test/multiprocess_test.h" #include "base/win/scoped_process_information.h" #include "testing/multiprocess_func_list.h" @@ -135,13 +136,13 @@ // Validate that we have separate handles that are good. int exit_code = 0; - ASSERT_TRUE(base::WaitForExitCode(process_info.TakeProcessHandle(), - &exit_code)); + base::Process process(process_info.TakeProcessHandle()); + ASSERT_TRUE(process.WaitForExit(&exit_code)); ASSERT_EQ(7, exit_code); exit_code = 0; - ASSERT_TRUE(base::WaitForExitCode(duplicate.TakeProcessHandle(), - &exit_code)); + base::Process dup_process(duplicate.TakeProcessHandle()); + ASSERT_TRUE(dup_process.WaitForExit(&exit_code)); ASSERT_EQ(7, exit_code); ASSERT_TRUE(::CloseHandle(process_info.TakeThreadHandle()));
diff --git a/base/win/win_util.cc b/base/win/win_util.cc index a3c9ece..957f937 100644 --- a/base/win/win_util.cc +++ b/base/win/win_util.cc
@@ -57,7 +57,7 @@ // Returns true if a physical keyboard is detected on Windows 8 and up. // Uses the Setup APIs to enumerate the attached keyboards and returns true -// if the keyboard count is more than 1. While this will work in most cases +// if the keyboard count is 1 or more.. While this will work in most cases // it won't work if there are devices which expose keyboard interfaces which // are attached to the machine. bool IsKeyboardPresentOnSlate() { @@ -89,6 +89,7 @@ device_info_data.cbSize = sizeof(device_info_data); if (!SetupDiEnumDeviceInfo(device_info, i, &device_info_data)) break; + // Get the device ID. wchar_t device_id[MAX_DEVICE_ID_LEN]; CONFIGRET status = CM_Get_Device_ID(device_info_data.DevInst, @@ -96,20 +97,19 @@ MAX_DEVICE_ID_LEN, 0); if (status == CR_SUCCESS) { - // To reduce the scope of the hack we only look for PNP and HID + // To reduce the scope of the hack we only look for PNP, MSF and HID // keyboards. - if (StartsWith(L"ACPI\\PNP", device_id, false) || - StartsWith(L"HID\\VID", device_id, false)) { + if (StartsWith(device_id, L"ACPI\\PNP", false) || + StartsWith(device_id, L"ACPI\\MSF", false) || + StartsWith(device_id, L"HID\\VID", false)) { keyboard_count++; } } } - // On a Windows machine, the API's always report 1 keyboard at least - // regardless of whether the machine has a keyboard attached or not. - // The heuristic we are using is to check the count and return true - // if the API's report more than one keyboard. Please note that this + // The heuristic we are using is to check the count of keyboards and return + // true if the API's report one or more keyboards. Please note that this // will break for non keyboard devices which expose a keyboard PDO. - return keyboard_count > 1; + return keyboard_count >= 1; } } // namespace
diff --git a/build/all.gyp b/build/all.gyp index 17958a0..499fc579 100644 --- a/build/all.gyp +++ b/build/all.gyp
@@ -467,6 +467,12 @@ }, # target_name: chromium_builder_tests ], 'conditions': [ + # TODO(GYP): make gn_migration.gypi work unconditionally. + ['OS=="linux" and target_arch=="x64" and chromeos==0 and chromecast==0 and disable_nacl==0', { + 'includes': [ + 'gn_migration.gypi', + ], + }], ['OS!="ios"', { 'targets': [ { @@ -516,156 +522,6 @@ ['OS!="ios" and OS!="android"', { 'targets': [ { - # TODO(GYP) - make gyp_all and gn_all work on iOS and Android also. - 'target_name': 'gyp_all', - 'type': 'none', - 'dependencies': [ - ':gn_all', - '../chrome/chrome.gyp:chromedriver_unittests', - '../components/components_tests.gyp:components_browsertests', - # '../components/nacl.gyp:nacl_loader_unittests', # TODO(GYP) - # '../remoting/remoting.gyp:remoting_unittests', # TODO(GYP) - '../ui/compositor/compositor.gyp:compositor_unittests', - ], - 'conditions': [ - ['OS!="android"', { - 'dependencies': [ - # '../device/device_tests.gyp:device_unittests', # TODO(GYP) - # '../google_apis/google_apis.gyp:google_apis_unittests', # TODO(GYP) - ], - }], - ], - }, - { - 'target_name': 'gn_all', - 'type': 'none', - - 'dependencies': [ - '../base/base.gyp:base_unittests', - '../cc/cc_tests.gyp:cc_unittests', - '../chrome/chrome.gyp:chrome', - '../chrome/chrome.gyp:browser_tests', - '../chrome/chrome.gyp:interactive_ui_tests', - '../chrome/chrome.gyp:sync_integration_tests', - '../chrome/chrome.gyp:unit_tests', - '../components/components_tests.gyp:components_unittests', - '../content/content_shell_and_tests.gyp:content_shell', - '../content/content_shell_and_tests.gyp:content_browsertests', - '../content/content_shell_and_tests.gyp:content_perftests', - '../content/content_shell_and_tests.gyp:content_unittests', - '../crypto/crypto.gyp:crypto_unittests', - '../extensions/extensions_tests.gyp:extensions_browsertests', - '../extensions/extensions_tests.gyp:extensions_unittests', - '../google_apis/gcm/gcm.gyp:gcm_unit_tests', - '../gpu/gpu.gyp:gpu_unittests', - '../ipc/ipc.gyp:ipc_tests', - '../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests', - '../jingle/jingle.gyp:jingle_unittests', - '../media/media.gyp:media_unittests', - '../media/cast/cast.gyp:cast_unittests', - '../mojo/mojo.gyp:mojo', - '../mojo/mojo_base.gyp:mojo_common_unittests', - '../net/net.gyp:net_unittests', - '../ppapi/ppapi_internal.gyp:ppapi_tests', - '../printing/printing.gyp:printing_unittests', - '../sql/sql.gyp:sql_unittests', - '../skia/skia_tests.gyp:skia_unittests', - '../sync/sync.gyp:sync_unit_tests', - - # TODO(GYP): the Blink test targets should be public, but - # currently aren't. all_blink puls them in, though - # "//third_party/WebKit/Source/platform:heap_unittests", - # "//third_party/WebKit/Source/platform:platform_unittests", - # "//third_party/WebKit/Source/wtf:wtf_unittests", - '../third_party/WebKit/public/all.gyp:all_blink', - - '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', - - # TODO(GYP): Needed only w/ cld_version==1. What configs set that? - '../third_party/cld/cld.gyp:cld', - - # TODO(GYP): This is needed only w/ use_system_fontconfig==0. What configs set that? - #'../third_party/fontconfig/fontconfig.gyp:fontconfig', - - # TODO(GYP): This will be pulled in automatically when enable_webrtc==true. - # For now pull it in manually so that it doesn't regress. - '../third_party/libsrtp/libsrtp.gyp:libsrtp', - - '../third_party/mojo/mojo_edk_tests.gyp:mojo_system_unittests', - '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_bindings_unittests', - '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_environment_unittests', - '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_system_perftests', - '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_system_unittests', - '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_utility_unittests', - '../third_party/pdfium/samples/samples.gyp:pdfium_test', - - # TODO(GYP): Verify that this is no longer needed. - '../third_party/smhasher/smhasher.gyp:pmurhash', - - # TODO(GYP): This will be pulled in automatically when enable_webrtc==true. - # For now pull it in manually so that it doesn't regress. - '../third_party/usrsctp/usrsctp.gyp:usrsctplib', - - '../tools/gn/gn.gyp:gn', - '../tools/gn/gn.gyp:gn_unittests', - '../ui/accessibility/accessibility.gyp:accessibility_unittests', - '../ui/app_list/app_list.gyp:app_list_unittests', - '../ui/base/ui_base_tests.gyp:ui_base_unittests', - '../ui/display/display.gyp:display_unittests', - '../ui/events/events.gyp:events_unittests', - '../ui/gfx/gfx_tests.gyp:gfx_unittests', - '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests', - '../url/url.gyp:url_unittests', - ], - 'conditions': [ - ['OS!="win"', { - 'dependencies': [ - '../breakpad/breakpad.gyp:symupload', - ], - }], - ['use_x11==1', { - 'dependencies': [ - '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck', - ], - }], - ['toolkit_views==1', { - 'dependencies': [ - '../ui/views/views.gyp:views_unittests', - ], - }], - ['use_aura==1', { - 'dependencies': [ - '../ui/wm/wm.gyp:wm_unittests', - ], - }], - ['use_ozone==1', { - 'dependencies': [ - '../ui/ozone/ozone.gyp:ozone', - ], - }], - ['OS=="win" or OS=="mac" or OS=="android"', { - 'dependencies': [ - '../rlz/rlz.gyp:rlz_lib', - ], - }], - ['OS=="android"', { - 'dependencies': [ - '../chrome/chrome.gyp:chrome_shell_apk', - '../content/content_shell_and_tests.gyp:content_shell_apk', - ], - 'dependencies!': [ - '../url/url.gyp:url_unittests', - ], - }], - ['OS=="linux"', { - 'dependencies': [ - '../dbus/dbus.gyp:dbus_unittests', - '../sandbox/sandbox.gyp:sandbox_linux_unittests', - ], - }], - ], - }, - { 'target_name': 'chromium_builder_nacl_win_integration', 'type': 'none', 'dependencies': [ @@ -682,6 +538,7 @@ '../chrome/chrome.gyp:performance_browser_tests', '../chrome/chrome.gyp:sync_performance_tests', '../content/content_shell_and_tests.gyp:content_shell', + '../gpu/gpu.gyp:gpu_perftests', '../media/media.gyp:media_perftests', '../tools/perf/clear_system_cache/clear_system_cache.gyp:*', '../tools/telemetry/telemetry.gyp:*',
diff --git a/build/android/OWNERS b/build/android/OWNERS index bd675fb8..9a5d270 100644 --- a/build/android/OWNERS +++ b/build/android/OWNERS
@@ -1,2 +1,3 @@ jbudorick@chromium.org klundberg@chromium.org +pasko@chromium.org
diff --git a/build/android/buildbot/bb_device_steps.py b/build/android/buildbot/bb_device_steps.py index a53bb563..c3c344b 100755 --- a/build/android/buildbot/bb_device_steps.py +++ b/build/android/buildbot/bb_device_steps.py
@@ -218,7 +218,7 @@ args = ['--browser', 'android-chrome-shell'] devices = android_commands.GetAttachedDevices() if devices: - args = args + ['--device', devices[0]] + args = args + ['--device', 'android'] bb_annotations.PrintNamedStep(step_name) RunCmd([run_tests_path] + args)
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py index ca587705..cb547fb9 100755 --- a/build/android/gyp/proguard.py +++ b/build/android/gyp/proguard.py
@@ -28,7 +28,31 @@ '-outjars', outjars, '-libraryjars', libraryjars, '@' + options.proguard_config] - build_utils.CheckOutput(proguard_cmd, print_stdout=True) + build_utils.CheckOutput(proguard_cmd, print_stdout=True, + stdout_filter=FilterProguardOutput) + + +def FilterProguardOutput(output): + '''ProGuard outputs boring stuff to stdout (proguard version, jar path, etc) + as well as interesting stuff (notes, warnings, etc). If stdout is entirely + boring, this method suppresses the output. + ''' + ignore_patterns = [ + 'ProGuard, version ', + 'Reading program jar [', + 'Reading library jar [', + 'Preparing output jar [', + ' Copying resources from program jar [', + ] + for line in output.splitlines(): + for pattern in ignore_patterns: + if line.startswith(pattern): + break + else: + # line doesn't match any of the patterns; it's probably something worth + # printing out. + return output + return '' def main(args):
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml index 5a169c1..cfbf8585 100644 --- a/build/android/lint/suppressions.xml +++ b/build/android/lint/suppressions.xml
@@ -43,6 +43,8 @@ </issue> <issue id="IconDensities"> <!-- crbug.com/457918 is tracking missing assets --> + <ignore path="components/web_contents_delegate_android/android/java/res/drawable-xxhdpi"/> + <ignore path="components/web_contents_delegate_android/android/java/res/drawable-xxxhdpi"/> <ignore path="content/public/android/java/res/drawable-xxhdpi"/> <ignore path="content/public/android/java/res/drawable-xxxhdpi"/> <ignore path="chrome/android/java/res/drawable-xxhdpi"/> @@ -62,9 +64,47 @@ <issue id="MissingVersion"> <ignore path="AndroidManifest.xml"/> </issue> - <!-- Disabling is InlinedApi and NewApi is bad but we have too many of these errors and nobody is fixing it. crbug.com/411461 --> <issue id="InlinedApi" severity="ignore"/> - <issue id="NewApi" severity="ignore"/> + <issue id="NewApi"> + <ignore regexp="Attribute `paddingStart` referenced here can result in a crash on some specific devices older than API 17"/> + <ignore path="org/chromium/base/AnimationFrameTimeHistogram$Recorder.class"/> + <ignore path="org/chromium/base/JavaHandlerThread.class"/> + <ignore path="org/chromium/base/SysUtils.class"/> + <ignore path="org/chromium/chrome/browser/preferences/website/AddExceptionPreference.class"/> + <ignore path="org/chromium/chrome/browser/infobar/AnimationHelper$*.class"/> + <ignore path="org/chromium/chrome/browser/infobar/AppBannerInfoBar.class"/> + <ignore path="org/chromium/chrome/browser/BookmarkUtils.class"/> + <ignore path="org/chromium/chrome/browser/widget/ButtonCompat.class"/> + <ignore path="org/chromium/chrome/browser/autofill/CardUnmaskPrompt.class"/> + <ignore path="org/chromium/chrome/browser/LollipopTtsPlatformImpl.class"/> + <ignore path="org/chromium/chrome/browser/LollipopTtsPlatformImpl$*.class"/> + <ignore path="org/chromium/chrome/browser/TtsPlatformImpl.class"/> + <ignore path="org/chromium/chrome/browser/TtsPlatformImpl$*.class"/> + <ignore path="org/chromium/content/browser/accessibility/BrowserAccessibilityManager.class"/> + <ignore path="org/chromium/content/browser/ContentViewCore.class"/> + <ignore path="org/chromium/content/browser/accessibility/JellyBeanAccessibilityInjector.class"/> + <ignore path="org/chromium/content/browser/accessibility/JellyBeanBrowserAccessibilityManager$*.class"/> + <ignore path="org/chromium/content/browser/accessibility/LollipopAccessibilityInjector.class"/> + <ignore path="org/chromium/content/browser/accessibility/LollipopAccessibilityInjector$*.class"/> + <ignore path="org/chromium/content/browser/accessibility/LollipopBrowserAccessibilityManager.class"/> + <ignore path="org/chromium/media/AudioManagerAndroid.class"/> + <ignore path="org/chromium/media/MediaCodecBridge.class"/> + <ignore path="org/chromium/media/MediaDrmBridge.class"/> + <ignore path="org/chromium/media/MediaDrmBridge$*.class"/> + <ignore path="org/chromium/media/VideoCaptureCamera.class"/> + <ignore path="org/chromium/media/VideoCaptureCamera2.class"/> + <ignore path="org/chromium/media/VideoCaptureCamera2$*.class"/> + <ignore path="org/chromium/media/WebAudioMediaCodecBridge.class"/> + <ignore path="org/chromium/printing/PrintDocumentAdapterWrapper.class"/> + <ignore path="org/chromium/printing/PrintManagerDelegateImpl.class"/> + <ignore path="org/chromium/printing/PrintingControllerImpl.class"/> + <ignore path="org/chromium/ui/base/Clipboard.class"/> + <ignore path="org/chromium/ui/ColorPickerAdvancedComponent.class"/> + <ignore path="org/chromium/ui/gfx/DeviceDisplayInfo.class"/> + <ignore path="org/chromium/ui/gl/SurfaceTexturePlatformWrapper.class"/> + <ignore path="org/chromium/ui/widget/TextViewWithClickableSpans.class"/> + <ignore path="org/chromium/ui/picker/TwoFieldDatePicker.class"/> + </issue> <issue id="OldTargetApi"> <ignore path="AndroidManifest.xml"/> </issue> @@ -79,9 +119,6 @@ </issue> <issue id="SetJavaScriptEnabled" severity="ignore"/> <issue id="UnusedResources"> - <!-- TODO(aurimas): remove suppression once crbug.com/458328 is fixed. --> - <ignore path="content/public/android/java/res/layout/validation_message_bubble.xml" /> - <!-- These files are used by chrome_shell_apk and chrome_apk targets. --> <ignore path="chrome/android/java/res/layout/accessibility_tab_switcher.xml" /> <ignore path="chrome/android/java/res/drawable/btn_back.xml" />
diff --git a/build/android/provision_devices.py b/build/android/provision_devices.py index 6b3ea1d..5f00b31 100755 --- a/build/android/provision_devices.py +++ b/build/android/provision_devices.py
@@ -125,7 +125,7 @@ as_root=True) -def WipeDeviceData(device): +def WipeDeviceData(device, options): """Wipes data from device, keeping only the adb_keys for authorization. After wiping data on a device that has been authorized, adb can still @@ -139,16 +139,25 @@ """ device_authorized = device.FileExists(constants.ADB_KEYS_FILE) if device_authorized: - adb_keys = device.ReadFile(constants.ADB_KEYS_FILE, as_root=True) + adb_keys = device.ReadFile(constants.ADB_KEYS_FILE, + as_root=True).splitlines() device.RunShellCommand('wipe data', as_root=True) if device_authorized: - WriteAdbKeysFile(device, adb_keys) + adb_keys_set = set(adb_keys) + for adb_key_file in options.adb_key_files or []: + try: + with open(adb_key_file, 'r') as f: + adb_public_keys = f.readlines() + adb_keys_set.update(adb_public_keys) + except IOError: + logging.warning('Unable to find adb keys file %s.' % adb_key_file) + WriteAdbKeysFile(device, '\n'.join(adb_keys_set)) -def WipeDeviceIfPossible(device, timeout): +def WipeDeviceIfPossible(device, timeout, options): try: device.EnableRoot() - WipeDeviceData(device) + WipeDeviceData(device, options) device.Reboot(True, timeout=timeout, retries=0) except (errors.DeviceUnresponsiveError, device_errors.CommandFailedError): pass @@ -177,17 +186,9 @@ else: reboot_timeout = _DEFAULT_TIMEOUTS.PRE_LOLLIPOP - if options.adb_key_files: - adb_keys = set() - for adb_key_file in options.adb_key_files: - with open(adb_key_file, 'r') as f: - adb_public_keys = f.readlines() - adb_keys.update(adb_public_keys) - WriteAdbKeysFile(device, '\n'.join(adb_keys)) - try: if not options.skip_wipe: - WipeDeviceIfPossible(device, reboot_timeout) + WipeDeviceIfPossible(device, reboot_timeout, options) try: device.EnableRoot() except device_errors.CommandFailedError as e:
diff --git a/build/android/pylib/gtest/filter/content_browsertests_disabled b/build/android/pylib/gtest/filter/content_browsertests_disabled index b05f7ee..613c833a 100644 --- a/build/android/pylib/gtest/filter/content_browsertests_disabled +++ b/build/android/pylib/gtest/filter/content_browsertests_disabled
@@ -15,12 +15,19 @@ # Crashes RenderFrameHostManagerTest.IgnoreRendererDebugURLsWhenCrashed +# Crashes due to using --disable-gpu. +# Needs to investigate more in http://crbug.com/461624. +ScreenOrientationBrowserTest.* + # Plugins are not supported. BrowserPluginThreadedCompositorPixelTest.* BrowserPluginHostTest.* BrowserPluginTest.* PluginTest.* +# http://crbug.com/463740 +CrossPlatformAccessibilityBrowserTest.SelectedEditableTextAccessibility + # http://crbug.com/297230 DumpAccessibilityTreeTest.AccessibilityAriaLevel DumpAccessibilityTreeTest.AccessibilityAriaProgressbar @@ -67,3 +74,7 @@ # http://crbug.com/343604 MSE_ClearKey/EncryptedMediaTest.ConfigChangeVideo/0 + +# http://crbug.com/463041 +ScreenOrientationBrowserTest.ScreenOrientationChange +ScreenOrientationBrowserTest.WindowOrientationCange
diff --git a/build/android/pylib/remote/device/remote_device_environment.py b/build/android/pylib/remote/device/remote_device_environment.py index 6e75afa3..3b0c029c 100644 --- a/build/android/pylib/remote/device/remote_device_environment.py +++ b/build/android/pylib/remote/device/remote_device_environment.py
@@ -183,6 +183,7 @@ os.environ['APPURIFY_API_PROTO'] = self._api_protocol os.environ['APPURIFY_API_HOST'] = self._api_address os.environ['APPURIFY_API_PORT'] = self._api_port + os.environ['APPURIFY_STATUS_BASE_URL'] = 'none' self._GetAccessToken() if self._trigger: self._SelectDevice()
diff --git a/build/common.gypi b/build/common.gypi index 4fcd2117..edbd027 100644 --- a/build/common.gypi +++ b/build/common.gypi
@@ -1671,11 +1671,16 @@ # Location of Android NDK. 'variables': { 'variables': { - # Unfortunately we have to use absolute paths to the SDK/NDK because - # they're passed to ant which uses a different relative path from - # gyp. - 'android_ndk_root%': '<!(cd <(DEPTH) && pwd -P)/third_party/android_tools/ndk/', + # Standard libraries can use the relative path to the NDK. + 'android_ndk_root%': '../../third_party/android_tools/ndk/', + # Unfortunately, it is required to use the absolute path to the SDK + # because it us passed to ant which uses a different relative path + # from GYP. 'android_sdk_root%': '<!(cd <(DEPTH) && pwd -P)/third_party/android_tools/sdk/', + # Similarly, gdbserver and the Android toolchain need to use the + # absolute path to the NDK because they are used at different levels + # in the GYP files. + 'android_ndk_absolute_root%': '<!(cd <(DEPTH) && pwd -P)/third_party/android_tools/ndk/', 'android_host_arch%': '<!(uname -m)', # Android API-level of the SDK used for compilation. 'android_sdk_version%': '21', @@ -1684,6 +1689,7 @@ }, # Copy conditionally-set variables out one scope. 'android_ndk_root%': '<(android_ndk_root)', + 'android_ndk_absolute_root%': '<(android_ndk_absolute_root)', 'android_sdk_root%': '<(android_sdk_root)', 'android_sdk_version%': '<(android_sdk_version)', 'android_stlport_root': '<(android_ndk_root)/sources/cxx-stl/stlport', @@ -1699,17 +1705,17 @@ 'conditions': [ ['target_arch == "ia32"', { 'android_app_abi%': 'x86', - 'android_gdbserver%': '<(android_ndk_root)/prebuilt/android-x86/gdbserver/gdbserver', + 'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-x86/gdbserver/gdbserver', 'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-14/arch-x86', 'android_ndk_lib_dir%': 'usr/lib', - 'android_toolchain%': '<(android_ndk_root)/toolchains/x86-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin', + 'android_toolchain%': '<(android_ndk_absolute_root)/toolchains/x86-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin', }], ['target_arch == "x64"', { 'android_app_abi%': 'x86_64', - 'android_gdbserver%': '<(android_ndk_root)/prebuilt/android-x86_64/gdbserver/gdbserver', + 'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-x86_64/gdbserver/gdbserver', 'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-21/arch-x86_64', 'android_ndk_lib_dir%': 'usr/lib64', - 'android_toolchain%': '<(android_ndk_root)/toolchains/x86_64-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin', + 'android_toolchain%': '<(android_ndk_absolute_root)/toolchains/x86_64-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin', }], ['target_arch=="arm"', { 'conditions': [ @@ -1719,32 +1725,31 @@ 'android_app_abi%': 'armeabi-v7a', }], ], - 'android_gdbserver%': '<(android_ndk_root)/prebuilt/android-arm/gdbserver/gdbserver', + 'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-arm/gdbserver/gdbserver', 'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-14/arch-arm', 'android_ndk_lib_dir%': 'usr/lib', - 'android_toolchain%': '<(android_ndk_root)/toolchains/arm-linux-androideabi-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin', + 'android_toolchain%': '<(android_ndk_absolute_root)/toolchains/arm-linux-androideabi-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin', }], ['target_arch == "arm64"', { 'android_app_abi%': 'arm64-v8a', - 'android_gdbserver%': '<(android_ndk_root)/prebuilt/android-arm64/gdbserver/gdbserver', + 'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-arm64/gdbserver/gdbserver', 'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-21/arch-arm64', 'android_ndk_lib_dir%': 'usr/lib', - 'android_toolchain%': '<(android_ndk_root)/toolchains/aarch64-linux-android-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin', + 'android_toolchain%': '<(android_ndk_absolute_root)/toolchains/aarch64-linux-android-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin', }], ['target_arch == "mipsel"', { 'android_app_abi%': 'mips', - 'android_gdbserver%': '<(android_ndk_root)/prebuilt/android-mips/gdbserver/gdbserver', + 'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-mips/gdbserver/gdbserver', 'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-14/arch-mips', 'android_ndk_lib_dir%': 'usr/lib', - 'android_toolchain%': '<(android_ndk_root)/toolchains/mipsel-linux-android-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin', + 'android_toolchain%': '<(android_ndk_absolute_root)/toolchains/mipsel-linux-android-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin', }], ['target_arch == "mips64el"', { 'android_app_abi%': 'mips64', - 'android_gdbserver%': '<(android_ndk_root)/prebuilt/android-mips64/gdbserver/gdbserver', + 'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-mips64/gdbserver/gdbserver', 'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-21/arch-mips64', 'android_ndk_lib_dir%': 'usr/lib64', - 'android_toolchain%': '<(android_ndk_root)/toolchains/mips64el-linux-android-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin', - 'gcc_version%': 49, + 'android_toolchain%': '<(android_ndk_absolute_root)/toolchains/mips64el-linux-android-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin', }], ], }, @@ -2157,9 +2162,8 @@ 'enable_service_discovery%': 1 }], ['clang_use_chrome_plugins==1 and OS!="win"', { - 'clang_chrome_plugins_flags': [ - '<!@(<(DEPTH)/tools/clang/scripts/plugin_flags.sh)' - ], + 'clang_chrome_plugins_flags%': + '<!(python <(DEPTH)/tools/clang/scripts/plugin_flags.py)', }], ['asan==1 or msan==1 or lsan==1 or tsan==1', { 'clang%': 1, @@ -2298,13 +2302,13 @@ 'arm_thumb%': 1, }], - # Set default compiler flags depending on MIPS architecture variant. - ['target_arch=="mipsel" and mips_arch_variant=="r2" and android_webview_build==0', { - 'mips_fpu_mode%': 'fp32', - }], + # Set default compiler flags for MIPS floating-point support. ['target_arch=="mipsel" and android_webview_build==0', { 'mips_float_abi%': 'hard', }], + ['target_arch=="mipsel" and mips_arch_variant=="r2" and android_webview_build==0', { + 'mips_fpu_mode%': 'fp32', + }], ['android_webview_build==1', { # The WebView build gets its cpu-specific flags from the Android build system. @@ -2313,8 +2317,8 @@ 'arm_fpu%': '', 'arm_float_abi%': '', 'arm_thumb%': 0, - 'mips_fpu_mode%': '', 'mips_float_abi%': '', + 'mips_fpu_mode%': '', }], # Enable brlapi by default for chromeos. @@ -2603,7 +2607,7 @@ ], }, }], - ['clang==1 and OS!="win"', { + ['(clang==1 or host_clang==1) and OS!="win"', { # This is here so that all files get recompiled after a clang roll and # when turning clang on or off. # (defines are passed via the command line, and build systems rebuild @@ -4077,7 +4081,7 @@ ['mips_arch_variant=="r2"', { 'cflags': ['-mips32r2', '-Wa,-mips32r2'], 'conditions': [ - ['mips_fpu_mode!=""', { + ['mips_float_abi=="hard" and mips_fpu_mode!=""', { 'cflags': ['-m<(mips_fpu_mode)'], }], ],
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index 7c06e59..3afba89 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -113,11 +113,6 @@ # toolchains. cros_use_custom_toolchain = false } - - # TODO(brettw) remove this flag (and therefore enable linking all targets) on - # Windows when we have sufficient bot capacity. In the meantime, you can - # enable linking for local compiles. - link_chrome_on_windows = true } # TODO(dpranke): Remove these asserts when os and cpu_arch are removed.
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index c7c0f43..28608cb 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -160,6 +160,8 @@ jni_target_name = "${target_name}__jni_${classname}" jni_actions += [ ":$jni_target_name" ] action(jni_target_name) { + # The sources aren't compiled so don't check their dependencies. + check_includes = false depfile = "$target_gen_dir/$target_name.d" script = "//base/android/jni_generator/jni_generator.py" sources = [
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 64b91fe4..4397151 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -48,6 +48,13 @@ # http://gcc.gnu.org/wiki/DebugFission use_debug_fission = !is_win && use_gold && linux_use_bundled_binutils && !use_ccache + + if (is_win) { + # Whether the VS xtree header has been patched to disable warning 4702. If + # it has, then we don't need to disable 4702 (unreachable code warning). + # The patch is preapplied to the internal toolchain and hence all bots. + msvs_xtree_patched = false + } } # default_include_dirs --------------------------------------------------------- @@ -295,7 +302,7 @@ "-mips32r2", "-Wa,-mips32r2", ] - if (mips_fpu_mode != "") { + if (mips_float_abi == "hard" && mips_fpu_mode != "") { cflags += [ "-m$mips_fpu_mode" ] } } else if (mips_arch_variant == "r1") { @@ -788,6 +795,14 @@ "/wd4610", # Class can never be instantiated, constructor required. "/wd4996", # Deprecated function warning. ] + + # VS xtree header file needs to be patched or 4702 (unreachable code + # warning) is reported if _HAS_EXCEPTIONS=0. Disable the warning if xtree is + # not patched. + if (!msvs_xtree_patched && + exec_script("../../win_is_xtree_patched.py", [], "value") == 0) { + cflags += [ "/wd4702" ] # Unreachable code. + } } else { # Common GCC warning setup. cflags = [
diff --git a/build/config/features.gni b/build/config/features.gni index abafd1c..4d01a87 100644 --- a/build/config/features.gni +++ b/build/config/features.gni
@@ -49,6 +49,29 @@ # Enables proprietary codecs and demuxers; e.g. H264, MOV, AAC, and MP3. proprietary_codecs = false + + enable_configuration_policy = true + + # Enables support for background apps. + enable_background = !is_ios && !is_android + + enable_captive_portal_detection = !is_android && !is_ios + + # Enables use of the session service, which is enabled by default. + # Android stores them separately on the Java side. + enable_session_service = !is_android && !is_ios + + enable_plugin_installation = is_win || is_mac + + enable_app_list = !is_ios && !is_android + + enable_supervised_users = !is_ios + + enable_autofill_dialog = !is_ios && !(is_android && is_android_webview_build) + + enable_google_now = !is_ios && !is_android + + enable_one_click_signin = is_win || is_mac || (is_linux && !is_chromeos) } # Additional dependent variables ----------------------------------------------- @@ -113,11 +136,6 @@ safe_browsing_mode = 1 } -enable_configuration_policy = true - -# Enables support for background apps. -enable_background = !is_ios && !is_android - enable_task_manager = !is_ios && !is_android use_cups = is_desktop_linux || is_mac @@ -127,27 +145,14 @@ # TODO(scottmg) remove this when we've fixed printing. win_pdf_metafile_for_printing = true -enable_captive_portal_detection = !is_android && !is_ios - -# Enables use of the session service, which is enabled by default. -# Android stores them separately on the Java side. -enable_session_service = !is_android && !is_ios - # Whether we are using the rlz library or not. Platforms like Android send # rlz codes for searches but do not use the library. enable_rlz = is_chrome_branded && (is_win || is_mac || is_ios || is_chromeos) -enable_plugin_installation = is_win || is_mac - -enable_app_list = !is_ios && !is_android enable_settings_app = enable_app_list && !is_chromeos -enable_supervised_users = !is_ios - enable_service_discovery = enable_mdns || is_mac -enable_autofill_dialog = !is_ios && !(is_android && is_android_webview_build) - enable_wifi_bootstrapping = is_win || is_mac # Image loader extension is enabled on ChromeOS only. @@ -155,10 +160,6 @@ enable_remoting = !is_ios && !is_android -enable_google_now = !is_ios && !is_android - -enable_one_click_signin = is_win || is_mac || (is_linux && !is_chromeos) - # Chrome OS: whether to also build the upcoming version of # ChromeVox, which can then be enabled via a command-line switch. enable_chromevox_next = false
diff --git a/build/config/linux/gtk/BUILD.gn b/build/config/linux/gtk/BUILD.gn new file mode 100644 index 0000000..4968e2d --- /dev/null +++ b/build/config/linux/gtk/BUILD.gn
@@ -0,0 +1,42 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/linux/pkg_config.gni") + +assert(is_linux, "This file should only be referenced on Linux") + +# Depend on //build/config/linux/gtk to use GTK. +# +# GN doesn't check visibility for configs so we give this an obviously internal +# name to discourage random targets from accidentally depending on this and +# bypassing the GTK target's visibility. +pkg_config("gtk_internal_config") { + # Gtk requires gmodule, but it does not list it as a dependency in some + # misconfigured systems. + packages = [ + "gmodule-2.0", + "gtk+-2.0", + "gthread-2.0", + ] +} + +# Basically no parts of Chrome should depend on GTK. To prevent accidents, the +# parts that explicitly need GTK are whitelisted on this target. +group("gtk") { + visibility = [ + "//chrome/browser/ui/libgtk2ui", + "//remoting/host", + ] + direct_dependent_configs = [ ":gtk_internal_config" ] +} + +# Depend on "gtkprint" to get this. +pkg_config("gtkprint_internal_config") { + packages = [ "gtk+-unix-print-2.0" ] +} + +group("gtkprint") { + visibility = [ "//chrome/browser/ui/libgtk2ui" ] + direct_dependent_configs = [ ":gtkprint_internal_config" ] +}
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi new file mode 100644 index 0000000..273c38ef --- /dev/null +++ b/build/gn_migration.gypi
@@ -0,0 +1,502 @@ +# Copyright (c) 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file defines three targets that we are using to +# track the progress of the GYP->GN migration: +# +# If you run 'ninja gn_build gyp_remaining gyp_groups', and then +# run 'ninja', the second ninja invocation should do nothing. This +# indicates that everything built by a ninja build is in fact +# listed in one of these targets. +# +# 'gn_all' lists what GN is currently capable of building and should +# match the 'gn_all' target in //BUILD.gn. +# +# 'gyp_remaining' lists all of the targets that still need to be converted, +# i.e., all of the other (non-empty) targets that a GYP build +# will build. +# +# 'gyp_groups' lists any empty (group) targets in the GYP build that +# are not picked up by gn_all or gyp_remaining; this is a +# separate target to ensure that when we build it, only +# stamp targets file are we don't accidentally pick up something +# not listed in one of the other two targets. +# +# TODO(GYP), TODO(dpranke) Add a build step to the bot that enforces the +# above contracts. + +{ + 'targets': [ + { + # This target should mirror the structure of //:gn_all + # as closely as possible, for ease of comparison. + 'target_name': 'gn_all', + 'type': 'none', + 'dependencies': [ + '../base/base.gyp:base_unittests', + '../cc/cc_tests.gyp:cc_unittests', + '../chrome/chrome.gyp:chrome', + '../chrome/chrome.gyp:browser_tests', + '../chrome/chrome.gyp:interactive_ui_tests', + '../chrome/chrome.gyp:sync_integration_tests', + '../chrome/chrome.gyp:unit_tests', + '../components/components_tests.gyp:components_unittests', + '../content/content_shell_and_tests.gyp:content_shell', + '../content/content_shell_and_tests.gyp:content_browsertests', + '../content/content_shell_and_tests.gyp:content_perftests', + '../content/content_shell_and_tests.gyp:content_unittests', + '../crypto/crypto.gyp:crypto_unittests', + '../extensions/extensions_tests.gyp:extensions_browsertests', + '../extensions/extensions_tests.gyp:extensions_unittests', + '../google_apis/gcm/gcm.gyp:gcm_unit_tests', + '../gpu/gpu.gyp:gpu_unittests', + '../ipc/ipc.gyp:ipc_tests', + '../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests', + '../jingle/jingle.gyp:jingle_unittests', + '../media/media.gyp:media_unittests', + '../media/cast/cast.gyp:cast_unittests', + '../mojo/mojo.gyp:mojo', + '../mojo/mojo_base.gyp:mojo_common_unittests', + '../net/net.gyp:net_unittests', + '../printing/printing.gyp:printing_unittests', + '../skia/skia_tests.gyp:skia_unittests', + '../sql/sql.gyp:sql_unittests', + '../sync/sync.gyp:sync_unit_tests', + '../third_party/WebKit/public/all.gyp:all_blink', + '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', + '../third_party/codesighs/codesighs.gyp:codesighs', + '../third_party/mojo/mojo_edk_tests.gyp:mojo_system_unittests', + '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_bindings_unittests', + '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_environment_unittests', + '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_system_unittests', + '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_utility_unittests', + '../third_party/pdfium/samples/samples.gyp:pdfium_test', + '../third_party/smhasher/smhasher.gyp:pmurhash', + '../third_party/sqlite/sqlite.gyp:sqlite_shell', + '../tools/gn/gn.gyp:gn', + '../tools/gn/gn.gyp:gn_unittests', + '../ui/accessibility/accessibility.gyp:accessibility_unittests', + '../ui/app_list/app_list.gyp:app_list_unittests', + '../ui/base/ui_base_tests.gyp:ui_base_unittests', + '../ui/display/display.gyp:display_unittests', + '../ui/events/events.gyp:events_unittests', + '../ui/gfx/gfx_tests.gyp:gfx_unittests', + '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests', + '../url/url.gyp:url_unittests', + ], + 'conditions': [ + ['enable_extensions==1 and OS!="mac"', { + 'dependencies': [ + '../extensions/shell/app_shell.gyp:app_shell_unittests', + ], + }], + ['OS!="win"', { + 'dependencies': [ + '../breakpad/breakpad.gyp:symupload', + ], + }], + ['use_x11==1', { + 'dependencies': [ + '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck', + ], + }], + ['toolkit_views==1', { + 'dependencies': [ + '../ui/views/views.gyp:views_unittests', + ], + }], + ['use_aura==1', { + 'dependencies': [ + '../ui/wm/wm.gyp:wm_unittests', + ], + }], + ['use_ozone==1', { + 'dependencies': [ + '../ui/ozone/ozone.gyp:ozone', + ], + }], + ['OS=="win" or OS=="mac" or chromeos==1', { + 'dependencies': [ + '../rlz/rlz.gyp:rlz_lib', + ], + }], + ['OS=="android"', { + 'dependencies': [ + '../base/base.gyp:chromium_android_linker', + '../build/android/rezip.gyp:rezip_apk_jar', + '../chrome/chrome.gyp:chrome_shell_apk', + '../chrome/chrome.gyp:chromedriver_webview_shell_apk', + #"//clank" TODO(GYP) - conditional somehow? + '../tools/imagediff/imagediff.gyp:imagediff#host', + '../tools/telemetry/telemetry.gyp:bitmaptools#host', + + # TODO(GYP): Remove these when the components_unittests work. + #"//components/history/core/test:test", + #"//components/policy:policy_component_test_support", + #"//components/policy:test_support", + #"//components/rappor:test_support", + #"//components/signin/core/browser:test_support", + #"//components/sync_driver:test_support", + #"//components/user_manager", + #"//components/wallpaper", + + '../content/content_shell_and_tests.gyp:content_shell_apk', + + # TODO(GYP): Are these needed, or will they be pulled in automatically? + #"//third_party/android_tools:android_gcm_java", + #"//third_party/android_tools:uiautomator_java", + #"//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/mesa", + #"//third_party/mockito:mockito_java", + #"//third_party/openmax_dl/dl", + #"//third_party/speex", + #"//ui/android:ui_java", + + # TODO(GYP): Are these needed? + #"//chrome/test:test_support_unit", + #"//third_party/smhasher:murmurhash3", + #"//ui/message_center:test_support", + ], + 'dependencies!': [ + '../breakpad/breakpad.gyp:symupload', + '../chrome/chrome.gyp:browser_tests', + '../chrome/chrome.gyp:interactive_ui_tests', + '../chrome/chrome.gyp:sync_integration_tests', + '../chrome/chrome.gyp:unit_tests', + '../extensions/extensions_tests.gyp:extensions_browsertests', + '../extensions/extensions_tests.gyp:extensions_unittests', + '../google_apis/gcm/gcm.gyp:gcm_unit_tests', + '../ipc/ipc.gyp:ipc_tests', + '../jingle/jingle.gyp:jingle_unittests', + '../net/net.gyp:net_unittests', + #"//ppapi/examples", + '../third_party/pdfium/samples/samples.gyp:pdfium_test', + '../tools/gn/gn.gyp:gn', + '../tools/gn/gn.gyp:gn_unittests', + '../ui/app_list/app_list.gyp:app_list_unittests', + '../url/url.gyp:url_unittests', + ], + }], + ['OS=="linux"', { + 'dependencies': [ + '../sandbox/sandbox.gyp:chrome_sandbox', + '../sandbox/sandbox.gyp:sandbox_linux_unittests', + ], + }], + ['OS=="mac"', { + 'dependencies': [ + '../third_party/apple_sample_code/apple_sample_code.gyp:apple_sample_code', + '../third_party/molokocacao/molokocacao.gyp:molokocacao', + + # TODO(GYP): remove these when the corresponding root targets work. + "//cc/blink", + "//components/ui/zoom:ui_zoom", + "//content", + "//content/test:test_support", + "//device/battery", + "//device/bluetooth", + "//device/nfc", + "//device/usb", + "//device/vibration", + "//media/blink", + "//pdf", + "//storage/browser", + "//third_party/brotli", + "//third_party/flac", + "//third_party/hunspell", + "//third_party/iccjpeg", + "//third_party/libphonenumber", + "//third_party/ots", + "//third_party/qcms", + "//third_party/smhasher:murmurhash3", + "//third_party/speex", + "//third_party/webrtc/system_wrappers", + "//ui/native_theme", + "//ui/snapshot", + "//ui/surface", + ], + 'dependencies!': [ + "//chrome", # TODO(GYP) + "//chrome/test:browser_tests", # TODO(GYP) + "//chrome/test:interactive_ui_tests", # TODO(GYP) + "//chrome/test:sync_integration_tests", # TODO(GYP) + "//chrome/test:unit_tests", # TODO(GYP) + "//components:components_unittests", # TODO(GYP) + "//content/test:content_browsertests", # TODO(GYP) + "//content/test:content_perftests", # TODO(GYP) + "//content/test:content_unittests", # TODO(GYP) + "//extensions:extensions_browsertests", # TODO(GYP) + "//extensions:extensions_unittests", # TODO(GYP) + "//net:net_unittests", # TODO(GYP) + "//third_party/usrsctp", # TODO(GYP) + "//ui/app_list:app_list_unittests", # TODO(GYP) + "//ui/gfx:gfx_unittests", # TODO(GYP) + ], + }], + ['OS=="win"', { + 'dependencies': [ + "//ui/metro_viewer", + '../third_party/codesighs/codesighs.gyp:msdump2symdb', + ], + 'dependencies!': [ + "//crypto:crypto_unittests", # TODO(GYP) + "//net:net_unittests", # TODO(GYP) + ], + }], + ], + }, + { + # This target contains a list of things that actually currently + # build in GN, but aren't listed in //:gn_all + 'target_name': 'add_to_gn_all', + 'type': 'none', + 'dependencies': [ + '../breakpad/breakpad.gyp:microdump_stackwalk', + '../breakpad/breakpad.gyp:minidump_dump', + '../breakpad/breakpad.gyp:minidump_stackwalk', + '../cc/cc_tests.gyp:cc_perftests', + '../cc/blink/cc_blink_tests.gyp:cc_blink_unittests', + '../chrome/chrome.gyp:sync_performance_tests', + '../chrome/tools/profile_reset/jtl_compiler.gyp:jtl_compiler', + '../courgette/courgette.gyp:courgette_minimal_tool', + '../courgette/courgette.gyp:courgette_unittests', + '../extensions/shell/app_shell.gyp:app_shell', + '../gin/gin.gyp:gin_unittests', + '../google_apis/google_apis.gyp:google_apis_unittests', + '../gpu/gpu.gyp:angle_unittests', + '../gpu/gpu.gyp:gpu_perftests', + '../ipc/ipc.gyp:ipc_perftests', + '../media/media.gyp:ffmpeg_regression_tests', # TODO(GYP) this should be conditional on media_use_ffmpeg + '../media/media.gyp:media_perftests', + '../net/net.gyp:crash_cache', + '../net/net.gyp:crl_set_dump', + '../net/net.gyp:dns_fuzz_stub', + '../net/net.gyp:dump_cache', + '../net/net.gyp:gdig', + '../net/net.gyp:get_server_time', + '../net/net.gyp:net_watcher', # TODO(GYP): This should be conditional on use_v8_in_net + '../net/net.gyp:run_testserver', + '../net/net.gyp:stress_cache', + '../net/net.gyp:tld_cleanup', + '../ppapi/ppapi_internal.gyp:ppapi_tests', # TODO(GYP): Split out the examples and tests + '../third_party/codesighs/codesighs.gyp:maptsvdifftool', + '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_system_perftests', + '../ui/compositor/compositor.gyp:compositor_unittests', + '../ui/keyboard/keyboard.gyp:keyboard_unittests', + '../ui/snapshot/snapshot.gyp:snapshot_unittests', + ], + 'conditions': [ + ['use_aura==1', { + 'dependencies': [ + '../ui/aura/aura.gyp:aura_bench', + ], + }], + ['use_ash==1', { + 'dependencies': [ + '../ash/ash.gyp:ash_shell', + '../ash/ash.gyp:ash_shell_unittests', + '../ash/ash.gyp:ash_unittests', + ], + }], + ['OS=="android"', { + 'dependencies': [ + '../breakpad/breakpad.gyp:dump_syms', + ], + }], + ['OS=="linux"', { + 'dependencies': [ + '../breakpad/breakpad.gyp:breakpad_unittests', + '../breakpad/breakpad.gyp:dump_syms', + '../breakpad/breakpad.gyp:generate_test_dump', + '../breakpad/breakpad.gyp:minidump-2-core', + '../net/net.gyp:disk_cache_memory_test', + '../net/net.gyp:flip_in_mem_edsm_server', + '../net/net.gyp:flip_in_mem_edsm_server_unittests', + '../net/net.gyp:quic_client', + '../net/net.gyp:quic_server', + '../dbus/dbus.gyp:dbus_unittests', + ], + }], + ['OS!="win"', { + 'dependencies': [ + '../third_party/codesighs/codesighs.gyp:nm2tsv', + ], + }], + ['OS=="mac"', { + 'dependencies': [ + '../breakpad/breakpad.gyp:crash_inspector', + '../breakpad/breakpad.gyp:dump_syms', + '../breakpad/breakpad.gyp:symupload', + ], + }], + ['OS=="android" or OS=="linux"', { + 'dependencies': [ + '../net/net.gyp:disk_cache_memory_test', + ], + }], + ], + }, + { + 'target_name': 'gyp_remaining', + 'type': 'none', + 'dependencies': [ + ':add_to_gn_all', + ], + 'conditions': [ + ['OS=="linux"', { + 'dependencies': [ + '../base/base.gyp:base_i18n_perftests', + '../base/base.gyp:base_perftests', + '../base/base.gyp:build_utf8_validator_tables#host', + '../base/base.gyp:check_example', + '../base/base.gyp:protect_file_posix', + '../breakpad/breakpad.gyp:core-2-minidump', + '../build/sanitizers/sanitizers.gyp:llvm-symbolizer', + '../chrome/chrome.gyp:chrome_app_unittests', + '../chrome/chrome.gyp:chromedriver', + '../chrome/chrome.gyp:chromedriver_tests', + '../chrome/chrome.gyp:chromedriver_unittests', + '../chrome/chrome.gyp:load_library_perf_tests', + '../chrome/chrome.gyp:performance_browser_tests', + '../chrome/chrome.gyp:service_discovery_sniffer', + '../cloud_print/cloud_print.gyp:cloud_print_unittests', + '../components/components.gyp:network_hints_browser', + '../components/components.gyp:policy_templates', + '../components/components.gyp:session_manager_component', + '../components/components_tests.gyp:components_browsertests', + '../components/components_tests.gyp:components_perftests', + '../content/content.gyp:content_app_browser', + '../content/content.gyp:content_app_child', + '../content/content_shell_and_tests.gyp:content_gl_benchmark', + '../content/content_shell_and_tests.gyp:content_gl_tests', + '../courgette/courgette.gyp:courgette', + '../courgette/courgette.gyp:courgette_fuzz', + '../dbus/dbus.gyp:dbus_test_server', + '../device/device_tests.gyp:device_unittests', + '../gin/gin.gyp:gin_v8_snapshot_fingerprint', + '../gin/gin.gyp:gin_shell', + '../google_apis/gcm/gcm.gyp:mcs_probe', + '../gpu/gpu.gyp:gl_tests', + '../gpu/tools/tools.gyp:compositor_model_bench', + '../gpu/gles2_conform_support/gles2_conform_support.gyp:gles2_conform_support', + '../gpu/gles2_conform_support/gles2_conform_test.gyp:gles2_conform_test', + '../gpu/khronos_glcts_support/khronos_glcts_test.gyp:khronos_glcts_test', + '../media/cast/cast.gyp:cast_benchmarks', + '../media/cast/cast.gyp:generate_barcode_video', + '../media/cast/cast.gyp:generate_timecode_audio', + '../media/cast/cast.gyp:tap_proxy', + '../media/media.gyp:player_x11', + '../mojo/mojo_base.gyp:mojo_application_chromium', + '../net/net.gyp:hpack_example_generator', + '../net/net.gyp:hpack_fuzz_mutator', + '../net/net.gyp:hpack_fuzz_wrapper', + '../net/net.gyp:net_perftests', + '../ppapi/ppapi_internal.gyp:ppapi_unittests', + '../ppapi/tools/ppapi_tools.gyp:pepper_hash_for_uma', + '../remoting/app_remoting_webapp.gyp:ar_sample_app', + '../remoting/remoting.gyp:remoting_host', + '../remoting/remoting.gyp:remoting_it2me_native_messaging_host', + '../remoting/remoting.gyp:remoting_me2me_host', + '../remoting/remoting.gyp:remoting_me2me_native_messaging_host', + '../remoting/remoting.gyp:remoting_native_messaging_manifests', + '../remoting/remoting.gyp:remoting_perftests', + '../remoting/remoting.gyp:remoting_start_host', + '../remoting/remoting.gyp:remoting_unittests', + '../sandbox/sandbox.gyp:sandbox_linux_jni_unittests', + '../skia/skia.gyp:filter_fuzz_stub', + '../skia/skia.gyp:image_operations_bench', + '../sync/sync.gyp:run_sync_testserver', + '../sync/sync.gyp:sync_endtoend_tests', + '../sync/tools/sync_tools.gyp:sync_client', + '../sync/tools/sync_tools.gyp:sync_listen_notifications', + '../testing/gmock.gyp:gmock_main', + '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests', + '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests', + '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests', + '../third_party/webrtc/tools/tools.gyp:frame_analyzer', + '../third_party/webrtc/tools/tools.gyp:rgba_to_i420_converter', + '../tools/gn/gn.gyp:generate_test_gn_data', + '../tools/perf/clear_system_cache/clear_system_cache.gyp:clear_system_cache', + #'../tools/telemetry/telemetry.gyp:bitmaptools', TODO(GYP) should this be #host ? + '../ui/app_list/app_list.gyp:app_list_demo', + '../ui/compositor/compositor.gyp:compositor_unittests', + '../ui/message_center/message_center.gyp:message_center_unittests', + '../ui/views/examples/examples.gyp:views_examples_with_content_exe', + '../v8/tools/gyp/v8.gyp:v8_snapshot', + '../v8/tools/gyp/v8.gyp:postmortem-metadata', + + # TODO(GYP) - list all of the examples explicitly. + '../ppapi/ppapi_internal.gyp:*', + ], + 'conditions': [ + ['disable_nacl==0 and disable_nacl_untrusted==0', { + 'dependencies': [ + '../components/nacl.gyp:nacl_loader_unittests', + '../mojo/mojo_nacl.gyp:monacl_shell', + '../remoting/remoting.gyp:remoting_key_tester', + ] + }], + ['test_isolation_mode!="noop"', { + 'dependencies': [ + '../ash/ash.gyp:ash_unittests_run', + '../base/base.gyp:base_unittests_run', + '../cc/cc_tests.gyp:cc_unittests_run', + '../chrome/chrome.gyp:browser_tests_run', + '../chrome/chrome.gyp:chrome_run', + '../chrome/chrome.gyp:interactive_ui_tests_run', + '../chrome/chrome.gyp:sync_integration_tests_run', + '../chrome/chrome.gyp:unit_tests_run', + '../components/components_tests.gyp:components_browsertests_run', + '../components/components_tests.gyp:components_unittests_run', + '../content/content_shell_and_tests.gyp:content_browsertests_run', + '../content/content_shell_and_tests.gyp:content_unittests_run', + '../crypto/crypto.gyp:crypto_unittests_run', + '../courgette/courgette.gyp:courgette_unittests_run', + '../gpu/gpu.gyp:gpu_unittests_run', + '../media/cast/cast.gyp:cast_unittests_run', + '../media/media.gyp:media_unittests_run', + '../net/net.gyp:net_unittests_run', + '../sandbox/sandbox.gyp:sandbox_linux_unittests_run', + '../sql/sql.gyp:sql_unittests_run', + '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests_run', + '../ui/accessibility/accessibility.gyp:accessibility_unittests_run', + '../ui/app_list/app_list.gyp:app_list_unittests_run', + '../ui/events/events.gyp:events_unittests_run', + '../ui/message_center/message_center.gyp:message_center_unittests_run', + '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests_run', + ], + }], + ], + }], + ['use_aura==1', { + 'dependencies': [ + '../ui/aura/aura.gyp:aura_demo', + '../ui/aura/aura.gyp:aura_unittests', + ], + }], + ], + }, + { + # This target, when built, should cause no actual work + # to be done, just update a bunch of stamp files. + 'target_name': 'gyp_groups', + 'type': 'none', + 'dependencies': [ + 'All', + 'aura_builder', + 'blink_tests', + 'chromium_builder_asan', + 'chromium_builder_chromedriver', + 'chromium_builder_perf', + 'chromium_builder_tests', + 'chromium_builder_webrtc', + 'chromium_gpu_builder', + 'chromium_gpu_debug_builder', + ], + }, + ] +} +
diff --git a/build/gyp_helper.py b/build/gyp_helper.py index 645943a..a2cc7e19 100644 --- a/build/gyp_helper.py +++ b/build/gyp_helper.py
@@ -42,8 +42,12 @@ file_val = file_data.get(var) if file_val: if var in os.environ: - print 'INFO: Environment value for "%s" overrides value in %s.' % ( - var, os.path.abspath(file_path) + behavior = 'replaces' + if var == 'GYP_DEFINES': + os.environ[var] = file_val + ' ' + os.environ[var] + behavior = 'overrides' + print 'INFO: Environment value for "%s" %s value in %s' % ( + var, behavior, os.path.abspath(file_path) ) else: os.environ[var] = file_val
diff --git a/build/linux/system.gyp b/build/linux/system.gyp index 9079011..a71a5c5 100644 --- a/build/linux/system.gyp +++ b/build/linux/system.gyp
@@ -63,6 +63,7 @@ 'udev_device_get_sysname', 'udev_device_get_syspath', 'udev_device_new_from_devnum', + 'udev_device_new_from_subsystem_sysname', 'udev_device_new_from_syspath', 'udev_device_unref', 'udev_enumerate_add_match_subsystem',
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc index 24c24d6..4659a3f 100644 --- a/build/sanitizers/tsan_suppressions.cc +++ b/build/sanitizers/tsan_suppressions.cc
@@ -251,9 +251,6 @@ // http://crbug.com/364006 "race:gfx::ImageFamily::~ImageFamily\n" -// http://crbug.com/364014 -"race:WTF::Latin1Encoding()::globalLatin1Encoding\n" - // https://code.google.com/p/v8/issues/detail?id=3143 "race:v8::internal::FLAG_track_double_fields\n" @@ -328,9 +325,6 @@ // https://crbug.com/459429 "race:randomnessPid\n" -// https://crbug.com/460243 -"race:IPC::ChannelMojoHost::OnClientLaunched\n" - // https://crbug.com/454655 "race:content::BrowserTestBase::PostTaskToInProcessRendererAndWait\n"
diff --git a/build/toolchain/win/midl.gni b/build/toolchain/win/midl.gni index 30bcbf77..748b0fc 100644 --- a/build/toolchain/win/midl.gni +++ b/build/toolchain/win/midl.gni
@@ -16,6 +16,7 @@ # out_dir (optional) # Directory to write the generated files to. Defaults to target_gen_dir. # +# deps (optional) # visibility (optional) template("midl") { @@ -82,6 +83,10 @@ idl_target_platform, "/Oicf", ] + + if (defined(invoker.deps)) { + deps = invoker.deps + } } source_set(target_name) {
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index 7a97d38..99a8208f 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn
@@ -731,162 +731,160 @@ } } -if (!is_win || link_chrome_on_windows) { - test("cc_unittests") { - sources = [ - "animation/animation_unittest.cc", - "animation/keyframed_animation_curve_unittest.cc", - "animation/layer_animation_controller_unittest.cc", - "animation/scroll_offset_animation_curve_unittest.cc", - "animation/scrollbar_animation_controller_linear_fade_unittest.cc", - "animation/scrollbar_animation_controller_thinning_unittest.cc", - "animation/transform_operations_unittest.cc", - "base/float_quad_unittest.cc", - "base/math_util_unittest.cc", - "base/region_unittest.cc", - "base/rolling_time_delta_history_unittest.cc", - "base/scoped_ptr_vector_unittest.cc", - "base/simple_enclosed_region_unittest.cc", - "base/tiling_data_unittest.cc", - "base/util_unittest.cc", - "debug/frame_timing_tracker_unittest.cc", - "debug/micro_benchmark_controller_unittest.cc", - "input/top_controls_manager_unittest.cc", - "layers/contents_scaling_layer_unittest.cc", - "layers/delegated_frame_provider_unittest.cc", - "layers/delegated_frame_resource_collection_unittest.cc", - "layers/delegated_renderer_layer_impl_unittest.cc", - "layers/delegated_renderer_layer_unittest.cc", - "layers/heads_up_display_layer_impl_unittest.cc", - "layers/heads_up_display_unittest.cc", - "layers/io_surface_layer_impl_unittest.cc", - "layers/layer_impl_unittest.cc", - "layers/layer_iterator_unittest.cc", - "layers/layer_position_constraint_unittest.cc", - "layers/layer_unittest.cc", - "layers/layer_utils_unittest.cc", - "layers/nine_patch_layer_impl_unittest.cc", - "layers/nine_patch_layer_unittest.cc", - "layers/painted_scrollbar_layer_impl_unittest.cc", - "layers/picture_image_layer_impl_unittest.cc", - "layers/picture_image_layer_unittest.cc", - "layers/picture_layer_impl_unittest.cc", - "layers/picture_layer_unittest.cc", - "layers/render_surface_impl_unittest.cc", - "layers/render_surface_unittest.cc", - "layers/scrollbar_layer_unittest.cc", - "layers/solid_color_layer_impl_unittest.cc", - "layers/solid_color_scrollbar_layer_impl_unittest.cc", - "layers/surface_layer_impl_unittest.cc", - "layers/surface_layer_unittest.cc", - "layers/texture_layer_impl_unittest.cc", - "layers/texture_layer_unittest.cc", - "layers/tiled_layer_impl_unittest.cc", - "layers/tiled_layer_unittest.cc", - "layers/ui_resource_layer_impl_unittest.cc", - "layers/ui_resource_layer_unittest.cc", - "layers/video_layer_impl_unittest.cc", - "output/begin_frame_args_unittest.cc", - "output/delegating_renderer_unittest.cc", - "output/filter_operations_unittest.cc", - "output/gl_renderer_unittest.cc", - "output/output_surface_unittest.cc", - "output/overlay_unittest.cc", - "output/renderer_pixeltest.cc", - "output/renderer_unittest.cc", - "output/shader_unittest.cc", - "output/software_renderer_unittest.cc", - "quads/draw_quad_unittest.cc", - "quads/list_container_unittest.cc", - "quads/render_pass_unittest.cc", - "resources/display_item_list_unittest.cc", - "resources/layer_quad_unittest.cc", - "resources/picture_layer_tiling_set_unittest.cc", - "resources/picture_layer_tiling_unittest.cc", - "resources/picture_pile_impl_unittest.cc", - "resources/picture_pile_unittest.cc", - "resources/picture_unittest.cc", - "resources/platform_color_unittest.cc", - "resources/prioritized_resource_unittest.cc", - "resources/resource_provider_unittest.cc", - "resources/resource_update_controller_unittest.cc", - "resources/scoped_gpu_raster_unittest.cc", - "resources/scoped_resource_unittest.cc", - "resources/task_graph_runner_unittest.cc", - "resources/texture_mailbox_deleter_unittest.cc", - "resources/texture_uploader_unittest.cc", - "resources/tile_manager_unittest.cc", - "resources/tile_priority_unittest.cc", - "resources/tile_task_worker_pool_unittest.cc", - "resources/video_resource_updater_unittest.cc", - "scheduler/begin_frame_source_unittest.cc", - "scheduler/delay_based_time_source_unittest.cc", - "scheduler/scheduler_state_machine_unittest.cc", - "scheduler/scheduler_unittest.cc", - "test/layer_tree_json_parser_unittest.cc", - "test/test_web_graphics_context_3d_unittest.cc", - "trees/blocking_task_runner_unittest.cc", - "trees/damage_tracker_unittest.cc", - "trees/layer_sorter_unittest.cc", - "trees/layer_tree_host_common_unittest.cc", - "trees/layer_tree_host_impl_unittest.cc", - "trees/layer_tree_host_pixeltest_blending.cc", - "trees/layer_tree_host_pixeltest_filters.cc", - "trees/layer_tree_host_pixeltest_masks.cc", - "trees/layer_tree_host_pixeltest_readback.cc", - "trees/layer_tree_host_pixeltest_synchronous.cc", - "trees/layer_tree_host_unittest.cc", - "trees/layer_tree_host_unittest_animation.cc", - "trees/layer_tree_host_unittest_context.cc", - "trees/layer_tree_host_unittest_copyrequest.cc", - "trees/layer_tree_host_unittest_damage.cc", - "trees/layer_tree_host_unittest_delegated.cc", - "trees/layer_tree_host_unittest_no_message_loop.cc", - "trees/layer_tree_host_unittest_occlusion.cc", - "trees/layer_tree_host_unittest_picture.cc", - "trees/layer_tree_host_unittest_proxy.cc", - "trees/layer_tree_host_unittest_scroll.cc", - "trees/layer_tree_host_unittest_video.cc", - "trees/layer_tree_impl_unittest.cc", - "trees/occlusion_tracker_unittest.cc", - "trees/occlusion_unittest.cc", - "trees/property_tree_unittest.cc", - "trees/tree_synchronizer_unittest.cc", +test("cc_unittests") { + sources = [ + "animation/animation_unittest.cc", + "animation/keyframed_animation_curve_unittest.cc", + "animation/layer_animation_controller_unittest.cc", + "animation/scroll_offset_animation_curve_unittest.cc", + "animation/scrollbar_animation_controller_linear_fade_unittest.cc", + "animation/scrollbar_animation_controller_thinning_unittest.cc", + "animation/transform_operations_unittest.cc", + "base/float_quad_unittest.cc", + "base/math_util_unittest.cc", + "base/region_unittest.cc", + "base/rolling_time_delta_history_unittest.cc", + "base/scoped_ptr_vector_unittest.cc", + "base/simple_enclosed_region_unittest.cc", + "base/tiling_data_unittest.cc", + "base/util_unittest.cc", + "debug/frame_timing_tracker_unittest.cc", + "debug/micro_benchmark_controller_unittest.cc", + "input/top_controls_manager_unittest.cc", + "layers/contents_scaling_layer_unittest.cc", + "layers/delegated_frame_provider_unittest.cc", + "layers/delegated_frame_resource_collection_unittest.cc", + "layers/delegated_renderer_layer_impl_unittest.cc", + "layers/delegated_renderer_layer_unittest.cc", + "layers/heads_up_display_layer_impl_unittest.cc", + "layers/heads_up_display_unittest.cc", + "layers/io_surface_layer_impl_unittest.cc", + "layers/layer_impl_unittest.cc", + "layers/layer_iterator_unittest.cc", + "layers/layer_position_constraint_unittest.cc", + "layers/layer_unittest.cc", + "layers/layer_utils_unittest.cc", + "layers/nine_patch_layer_impl_unittest.cc", + "layers/nine_patch_layer_unittest.cc", + "layers/painted_scrollbar_layer_impl_unittest.cc", + "layers/picture_image_layer_impl_unittest.cc", + "layers/picture_image_layer_unittest.cc", + "layers/picture_layer_impl_unittest.cc", + "layers/picture_layer_unittest.cc", + "layers/render_surface_impl_unittest.cc", + "layers/render_surface_unittest.cc", + "layers/scrollbar_layer_unittest.cc", + "layers/solid_color_layer_impl_unittest.cc", + "layers/solid_color_scrollbar_layer_impl_unittest.cc", + "layers/surface_layer_impl_unittest.cc", + "layers/surface_layer_unittest.cc", + "layers/texture_layer_impl_unittest.cc", + "layers/texture_layer_unittest.cc", + "layers/tiled_layer_impl_unittest.cc", + "layers/tiled_layer_unittest.cc", + "layers/ui_resource_layer_impl_unittest.cc", + "layers/ui_resource_layer_unittest.cc", + "layers/video_layer_impl_unittest.cc", + "output/begin_frame_args_unittest.cc", + "output/delegating_renderer_unittest.cc", + "output/filter_operations_unittest.cc", + "output/gl_renderer_unittest.cc", + "output/output_surface_unittest.cc", + "output/overlay_unittest.cc", + "output/renderer_pixeltest.cc", + "output/renderer_unittest.cc", + "output/shader_unittest.cc", + "output/software_renderer_unittest.cc", + "quads/draw_quad_unittest.cc", + "quads/list_container_unittest.cc", + "quads/render_pass_unittest.cc", + "resources/display_item_list_unittest.cc", + "resources/layer_quad_unittest.cc", + "resources/picture_layer_tiling_set_unittest.cc", + "resources/picture_layer_tiling_unittest.cc", + "resources/picture_pile_impl_unittest.cc", + "resources/picture_pile_unittest.cc", + "resources/picture_unittest.cc", + "resources/platform_color_unittest.cc", + "resources/prioritized_resource_unittest.cc", + "resources/resource_provider_unittest.cc", + "resources/resource_update_controller_unittest.cc", + "resources/scoped_gpu_raster_unittest.cc", + "resources/scoped_resource_unittest.cc", + "resources/task_graph_runner_unittest.cc", + "resources/texture_mailbox_deleter_unittest.cc", + "resources/texture_uploader_unittest.cc", + "resources/tile_manager_unittest.cc", + "resources/tile_priority_unittest.cc", + "resources/tile_task_worker_pool_unittest.cc", + "resources/video_resource_updater_unittest.cc", + "scheduler/begin_frame_source_unittest.cc", + "scheduler/delay_based_time_source_unittest.cc", + "scheduler/scheduler_state_machine_unittest.cc", + "scheduler/scheduler_unittest.cc", + "test/layer_tree_json_parser_unittest.cc", + "test/test_web_graphics_context_3d_unittest.cc", + "trees/blocking_task_runner_unittest.cc", + "trees/damage_tracker_unittest.cc", + "trees/layer_sorter_unittest.cc", + "trees/layer_tree_host_common_unittest.cc", + "trees/layer_tree_host_impl_unittest.cc", + "trees/layer_tree_host_pixeltest_blending.cc", + "trees/layer_tree_host_pixeltest_filters.cc", + "trees/layer_tree_host_pixeltest_masks.cc", + "trees/layer_tree_host_pixeltest_readback.cc", + "trees/layer_tree_host_pixeltest_synchronous.cc", + "trees/layer_tree_host_unittest.cc", + "trees/layer_tree_host_unittest_animation.cc", + "trees/layer_tree_host_unittest_context.cc", + "trees/layer_tree_host_unittest_copyrequest.cc", + "trees/layer_tree_host_unittest_damage.cc", + "trees/layer_tree_host_unittest_delegated.cc", + "trees/layer_tree_host_unittest_no_message_loop.cc", + "trees/layer_tree_host_unittest_occlusion.cc", + "trees/layer_tree_host_unittest_picture.cc", + "trees/layer_tree_host_unittest_proxy.cc", + "trees/layer_tree_host_unittest_scroll.cc", + "trees/layer_tree_host_unittest_video.cc", + "trees/layer_tree_impl_unittest.cc", + "trees/occlusion_tracker_unittest.cc", + "trees/occlusion_unittest.cc", + "trees/property_tree_unittest.cc", + "trees/tree_synchronizer_unittest.cc", - # Surfaces test files. - "surfaces/surface_aggregator_test_helpers.cc", - "surfaces/surface_aggregator_test_helpers.h", - "surfaces/surface_aggregator_unittest.cc", - "surfaces/surface_unittest.cc", - "surfaces/surfaces_pixeltest.cc", + # Surfaces test files. + "surfaces/surface_aggregator_test_helpers.cc", + "surfaces/surface_aggregator_test_helpers.h", + "surfaces/surface_aggregator_unittest.cc", + "surfaces/surface_unittest.cc", + "surfaces/surfaces_pixeltest.cc", - # Setup. - "test/cc_test_suite.cc", - "test/run_all_unittests.cc", - ] + # Setup. + "test/cc_test_suite.cc", + "test/run_all_unittests.cc", + ] - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] - deps = [ - ":cc", - ":test_support", - "//base/test:test_support", - "//cc/surfaces", - "//cc/surfaces:surface_id", - "//gpu", - "//gpu:test_support", - "//gpu/command_buffer/client:gles2_interface", - "//gpu/command_buffer/common:gles2_utils", - "//media", - "//testing/gmock", - "//testing/gtest", - "//ui/events:events_base", - "//ui/gfx", - "//ui/gfx/geometry", - "//ui/gfx:test_support", - "//ui/gl", - ] - } + deps = [ + ":cc", + ":test_support", + "//base/test:test_support", + "//cc/surfaces", + "//cc/surfaces:surface_id", + "//gpu", + "//gpu:test_support", + "//gpu/command_buffer/client:gles2_interface", + "//gpu/command_buffer/common:gles2_utils", + "//media", + "//testing/gmock", + "//testing/gtest", + "//ui/events:events_base", + "//ui/gfx", + "//ui/gfx/geometry", + "//ui/gfx:test_support", + "//ui/gl", + ] } test("cc_perftests") {
diff --git a/cc/blink/BUILD.gn b/cc/blink/BUILD.gn index b9f86c0..1769efb 100644 --- a/cc/blink/BUILD.gn +++ b/cc/blink/BUILD.gn
@@ -72,7 +72,7 @@ # GYP version: //cc/blink/cc_blink_tests.gyp:cc_blink_unittests # TODO(GYP): make linking work on the mac. -if (!is_mac && (!is_win || link_chrome_on_windows)) { +if (!is_mac) { test("cc_blink_unittests") { sources = [ "web_animation_unittest.cc",
diff --git a/cc/debug/debug_rect_history.cc b/cc/debug/debug_rect_history.cc index cde77653..c257c60 100644 --- a/cc/debug/debug_rect_history.cc +++ b/cc/debug/debug_rect_history.cc
@@ -68,17 +68,21 @@ // not. Therefore we traverse recursively over all layers, not just the render // surface list. - if (!layer->update_rect().IsEmpty() && layer->DrawsContent()) { + Region invalidation_region = layer->GetInvalidationRegion(); + if (!invalidation_region.IsEmpty() && layer->DrawsContent()) { float width_scale = layer->content_bounds().width() / static_cast<float>(layer->bounds().width()); float height_scale = layer->content_bounds().height() / static_cast<float>(layer->bounds().height()); - gfx::Rect update_content_rect = gfx::ScaleToEnclosingRect( - layer->update_rect(), width_scale, height_scale); - debug_rects_.push_back( - DebugRect(PAINT_RECT_TYPE, - MathUtil::MapEnclosingClippedRect( - layer->screen_space_transform(), update_content_rect))); + + for (Region::Iterator it(invalidation_region); it.has_rect(); it.next()) { + gfx::Rect update_content_rect = + gfx::ScaleToEnclosingRect(it.rect(), width_scale, height_scale); + debug_rects_.push_back( + DebugRect(PAINT_RECT_TYPE, + MathUtil::MapEnclosingClippedRect( + layer->screen_space_transform(), update_content_rect))); + } } for (unsigned i = 0; i < layer->children().size(); ++i) @@ -163,10 +167,9 @@ } void DebugRectHistory::SaveTouchEventHandlerRects(LayerImpl* layer) { - LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>( - layer, - base::Bind(&DebugRectHistory::SaveTouchEventHandlerRectsCallback, - base::Unretained(this))); + LayerTreeHostCommon::CallFunctionForSubtree(layer, [this](LayerImpl* layer) { + SaveTouchEventHandlerRectsCallback(layer); + }); } void DebugRectHistory::SaveTouchEventHandlerRectsCallback(LayerImpl* layer) { @@ -183,10 +186,9 @@ } void DebugRectHistory::SaveWheelEventHandlerRects(LayerImpl* layer) { - LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>( - layer, - base::Bind(&DebugRectHistory::SaveWheelEventHandlerRectsCallback, - base::Unretained(this))); + LayerTreeHostCommon::CallFunctionForSubtree(layer, [this](LayerImpl* layer) { + SaveWheelEventHandlerRectsCallback(layer); + }); } void DebugRectHistory::SaveWheelEventHandlerRectsCallback(LayerImpl* layer) { @@ -204,10 +206,9 @@ } void DebugRectHistory::SaveScrollEventHandlerRects(LayerImpl* layer) { - LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>( - layer, - base::Bind(&DebugRectHistory::SaveScrollEventHandlerRectsCallback, - base::Unretained(this))); + LayerTreeHostCommon::CallFunctionForSubtree(layer, [this](LayerImpl* layer) { + SaveScrollEventHandlerRectsCallback(layer); + }); } void DebugRectHistory::SaveScrollEventHandlerRectsCallback(LayerImpl* layer) { @@ -225,10 +226,9 @@ } void DebugRectHistory::SaveNonFastScrollableRects(LayerImpl* layer) { - LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>( - layer, - base::Bind(&DebugRectHistory::SaveNonFastScrollableRectsCallback, - base::Unretained(this))); + LayerTreeHostCommon::CallFunctionForSubtree(layer, [this](LayerImpl* layer) { + SaveNonFastScrollableRectsCallback(layer); + }); } void DebugRectHistory::SaveNonFastScrollableRectsCallback(LayerImpl* layer) {
diff --git a/cc/debug/invalidation_benchmark.cc b/cc/debug/invalidation_benchmark.cc index 1a6a2b8..bb98bcc 100644 --- a/cc/debug/invalidation_benchmark.cc +++ b/cc/debug/invalidation_benchmark.cc
@@ -64,11 +64,7 @@ void InvalidationBenchmark::DidUpdateLayers(LayerTreeHost* host) { LayerTreeHostCommon::CallFunctionForSubtree( host->root_layer(), - base::Bind(&InvalidationBenchmark::Run, base::Unretained(this))); -} - -void InvalidationBenchmark::Run(Layer* layer) { - layer->RunMicroBenchmark(this); + [this](Layer* layer) { layer->RunMicroBenchmark(this); }); } void InvalidationBenchmark::RunOnLayer(PictureLayer* layer) {
diff --git a/cc/debug/invalidation_benchmark.h b/cc/debug/invalidation_benchmark.h index f17fdbd..9423d5d8 100644 --- a/cc/debug/invalidation_benchmark.h +++ b/cc/debug/invalidation_benchmark.h
@@ -31,7 +31,6 @@ private: enum Mode { FIXED_SIZE, LAYER, VIEWPORT, RANDOM }; - void Run(Layer* layer); float LCGRandom(); Mode mode_;
diff --git a/cc/debug/picture_record_benchmark.cc b/cc/debug/picture_record_benchmark.cc index b1b8188..3ef4708 100644 --- a/cc/debug/picture_record_benchmark.cc +++ b/cc/debug/picture_record_benchmark.cc
@@ -57,7 +57,7 @@ void PictureRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) { LayerTreeHostCommon::CallFunctionForSubtree( host->root_layer(), - base::Bind(&PictureRecordBenchmark::Run, base::Unretained(this))); + [this](Layer* layer) { layer->RunMicroBenchmark(this); }); scoped_ptr<base::ListValue> results(new base::ListValue()); for (std::map<std::pair<int, int>, TotalTime>::iterator it = times_.begin(); @@ -83,10 +83,6 @@ NotifyDone(results.Pass()); } -void PictureRecordBenchmark::Run(Layer* layer) { - layer->RunMicroBenchmark(this); -} - void PictureRecordBenchmark::RunOnLayer(PictureLayer* layer) { ContentLayerClient* painter = layer->client(); gfx::Size content_bounds = layer->content_bounds();
diff --git a/cc/debug/picture_record_benchmark.h b/cc/debug/picture_record_benchmark.h index d6330fe1..3710d83b 100644 --- a/cc/debug/picture_record_benchmark.h +++ b/cc/debug/picture_record_benchmark.h
@@ -27,8 +27,6 @@ void RunOnLayer(PictureLayer* layer) override; private: - void Run(Layer* layer); - typedef std::pair<base::TimeDelta, unsigned> TotalTime; std::map<std::pair<int, int>, TotalTime> times_; std::vector<std::pair<int, int>> dimensions_;
diff --git a/cc/debug/rasterize_and_record_benchmark.cc b/cc/debug/rasterize_and_record_benchmark.cc index e56a1e13..e46dcfe 100644 --- a/cc/debug/rasterize_and_record_benchmark.cc +++ b/cc/debug/rasterize_and_record_benchmark.cc
@@ -65,7 +65,7 @@ host_ = host; LayerTreeHostCommon::CallFunctionForSubtree( host->root_layer(), - base::Bind(&RasterizeAndRecordBenchmark::Run, base::Unretained(this))); + [this](Layer* layer) { layer->RunMicroBenchmark(this); }); DCHECK(!results_.get()); results_ = make_scoped_ptr(new base::DictionaryValue); @@ -102,10 +102,6 @@ weak_ptr_factory_.GetWeakPtr()))); } -void RasterizeAndRecordBenchmark::Run(Layer* layer) { - layer->RunMicroBenchmark(this); -} - void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) { DCHECK(host_);
diff --git a/cc/debug/rasterize_and_record_benchmark.h b/cc/debug/rasterize_and_record_benchmark.h index 30dcde0..bed446d 100644 --- a/cc/debug/rasterize_and_record_benchmark.h +++ b/cc/debug/rasterize_and_record_benchmark.h
@@ -37,7 +37,6 @@ scoped_refptr<base::MessageLoopProxy> origin_loop) override; private: - void Run(Layer* layer); void RunOnDisplayListLayer(PictureLayer* layer, const gfx::Rect& visible_content_rect); void RunOnPictureLayer(PictureLayer* layer,
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc index 5a9577b..443db8c 100644 --- a/cc/debug/rasterize_and_record_benchmark_impl.cc +++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -132,9 +132,10 @@ void RasterizeAndRecordBenchmarkImpl::DidCompleteCommit( LayerTreeHostImpl* host) { LayerTreeHostCommon::CallFunctionForSubtree( - host->RootLayer(), - base::Bind(&RasterizeAndRecordBenchmarkImpl::Run, - base::Unretained(this))); + host->RootLayer(), [this](LayerImpl* layer) { + rasterize_results_.total_layers++; + layer->RunMicroBenchmark(this); + }); scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); result->SetDouble("rasterize_time_ms", @@ -157,11 +158,6 @@ NotifyDone(result.Pass()); } -void RasterizeAndRecordBenchmarkImpl::Run(LayerImpl* layer) { - rasterize_results_.total_layers++; - layer->RunMicroBenchmark(this); -} - void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) { rasterize_results_.total_picture_layers++; if (!layer->CanHaveTilings()) {
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.h b/cc/debug/rasterize_and_record_benchmark_impl.h index e9ca27d..ae134ab2 100644 --- a/cc/debug/rasterize_and_record_benchmark_impl.h +++ b/cc/debug/rasterize_and_record_benchmark_impl.h
@@ -31,8 +31,6 @@ void RunOnLayer(PictureLayerImpl* layer) override; private: - void Run(LayerImpl* layer); - struct RasterizeResults { RasterizeResults(); ~RasterizeResults();
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc index 0c6ddf5..0353a78 100644 --- a/cc/layers/layer_impl.cc +++ b/cc/layers/layer_impl.cc
@@ -1590,4 +1590,8 @@ render_surface_.reset(); } +Region LayerImpl::GetInvalidationRegion() { + return Region(update_rect_); +} + } // namespace cc
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 5de0d9a..0357252 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h
@@ -596,6 +596,10 @@ SyncedScrollOffset* synced_scroll_offset() { return scroll_offset_.get(); } + // Get the correct invalidation region instead of conservative Rect + // for layers that provide it. + virtual Region GetInvalidationRegion(); + protected: LayerImpl(LayerTreeImpl* layer_impl, int id,
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index e819afd..93d6581 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -331,8 +331,8 @@ CheckerboardDrawQuad* quad = render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); SkColor color = DebugColors::DefaultCheckerboardColor(); - quad->SetNew( - shared_quad_state, geometry_rect, visible_geometry_rect, color); + quad->SetNew(shared_quad_state, geometry_rect, visible_geometry_rect, + color, draw_properties().device_scale_factor); } else { SkColor color = SafeOpaqueBackgroundColor(); SolidColorDrawQuad* quad = @@ -605,6 +605,15 @@ return raster_source_->GetFlattenedPicture(); } +Region PictureLayerImpl::GetInvalidationRegion() { + // |invalidation_| gives the invalidation contained in the source frame, but + // is not cleared after drawing from the layer. However, update_rect() is + // cleared once the invalidation is drawn, which is useful for debugging + // visualizations. This method intersects the two to give a more exact + // representation of what was invalidated that is cleared after drawing. + return IntersectRegions(invalidation_, update_rect()); +} + scoped_refptr<Tile> PictureLayerImpl::CreateTile( float contents_scale, const gfx::Rect& content_rect) {
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h index 9500e22..397cb62 100644 --- a/cc/layers/picture_layer_impl.h +++ b/cc/layers/picture_layer_impl.h
@@ -61,6 +61,7 @@ void ReleaseResources() override; void RecreateResources() override; skia::RefPtr<SkPicture> GetPicture() override; + Region GetInvalidationRegion() override; // PictureLayerTilingClient overrides. scoped_refptr<Tile> CreateTile(float contents_scale,
diff --git a/cc/layers/tiled_layer_impl.cc b/cc/layers/tiled_layer_impl.cc index 234bd44..b78a1d8 100644 --- a/cc/layers/tiled_layer_impl.cc +++ b/cc/layers/tiled_layer_impl.cc
@@ -241,8 +241,8 @@ CheckerboardDrawQuad* checkerboard_quad = render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); - checkerboard_quad->SetNew( - shared_quad_state, tile_rect, visible_tile_rect, checker_color); + checkerboard_quad->SetNew(shared_quad_state, tile_rect, + visible_tile_rect, checker_color, 1.f); append_quads_data->num_missing_tiles++; continue; }
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index 6142d964..357ea4e6 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc
@@ -559,14 +559,16 @@ SkColorGetB(color) * (1.0f / 255.0f), 1)); - const int checkerboard_width = 16; - float frequency = 1.0f / checkerboard_width; + const int kCheckerboardWidth = 16; + float frequency = 1.0f / kCheckerboardWidth; gfx::Rect tile_rect = quad->rect; - float tex_offset_x = tile_rect.x() % checkerboard_width; - float tex_offset_y = tile_rect.y() % checkerboard_width; - float tex_scale_x = tile_rect.width(); - float tex_scale_y = tile_rect.height(); + float tex_offset_x = + static_cast<int>(tile_rect.x() / quad->scale) % kCheckerboardWidth; + float tex_offset_y = + static_cast<int>(tile_rect.y() / quad->scale) % kCheckerboardWidth; + float tex_scale_x = tile_rect.width() / quad->scale; + float tex_scale_y = tile_rect.height() / quad->scale; GLC(gl_, gl_->Uniform4f(program->fragment_shader().tex_transform_location(), tex_offset_x, @@ -1016,19 +1018,7 @@ highp_threshold_min_, quad->shared_quad_state->visible_content_rect.bottom_right()); - int shader_quad_location = -1; - int shader_edge_location = -1; - int shader_viewport_location = -1; - int shader_mask_sampler_location = -1; - int shader_mask_tex_coord_scale_location = -1; - int shader_mask_tex_coord_offset_location = -1; - int shader_matrix_location = -1; - int shader_alpha_location = -1; - int shader_color_matrix_location = -1; - int shader_color_offset_location = -1; - int shader_tex_transform_location = -1; - int shader_backdrop_location = -1; - int shader_backdrop_rect_location = -1; + ShaderLocations locations; DCHECK_EQ(background_texture || background_image, use_shaders_for_blending); BlendMode shader_blend_mode = use_shaders_for_blending @@ -1039,161 +1029,61 @@ const RenderPassMaskProgramAA* program = GetRenderPassMaskProgramAA( tex_coord_precision, mask_sampler, shader_blend_mode); SetUseProgram(program->program()); - GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); - - shader_quad_location = program->vertex_shader().quad_location(); - shader_edge_location = program->vertex_shader().edge_location(); - shader_viewport_location = program->vertex_shader().viewport_location(); - shader_mask_sampler_location = - program->fragment_shader().mask_sampler_location(); - shader_mask_tex_coord_scale_location = - program->fragment_shader().mask_tex_coord_scale_location(); - shader_mask_tex_coord_offset_location = - program->fragment_shader().mask_tex_coord_offset_location(); - shader_matrix_location = program->vertex_shader().matrix_location(); - shader_alpha_location = program->fragment_shader().alpha_location(); - shader_tex_transform_location = - program->vertex_shader().tex_transform_location(); - shader_backdrop_location = program->fragment_shader().backdrop_location(); - shader_backdrop_rect_location = - program->fragment_shader().backdrop_rect_location(); + program->vertex_shader().FillLocations(&locations); + program->fragment_shader().FillLocations(&locations); + GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); } else if (!use_aa && mask_texture_id && !use_color_matrix) { const RenderPassMaskProgram* program = GetRenderPassMaskProgram( tex_coord_precision, mask_sampler, shader_blend_mode); SetUseProgram(program->program()); - GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); - - shader_mask_sampler_location = - program->fragment_shader().mask_sampler_location(); - shader_mask_tex_coord_scale_location = - program->fragment_shader().mask_tex_coord_scale_location(); - shader_mask_tex_coord_offset_location = - program->fragment_shader().mask_tex_coord_offset_location(); - shader_matrix_location = program->vertex_shader().matrix_location(); - shader_alpha_location = program->fragment_shader().alpha_location(); - shader_tex_transform_location = - program->vertex_shader().tex_transform_location(); - shader_backdrop_location = program->fragment_shader().backdrop_location(); - shader_backdrop_rect_location = - program->fragment_shader().backdrop_rect_location(); + program->vertex_shader().FillLocations(&locations); + program->fragment_shader().FillLocations(&locations); + GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); } else if (use_aa && !mask_texture_id && !use_color_matrix) { const RenderPassProgramAA* program = GetRenderPassProgramAA(tex_coord_precision, shader_blend_mode); SetUseProgram(program->program()); - GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); - - shader_quad_location = program->vertex_shader().quad_location(); - shader_edge_location = program->vertex_shader().edge_location(); - shader_viewport_location = program->vertex_shader().viewport_location(); - shader_matrix_location = program->vertex_shader().matrix_location(); - shader_alpha_location = program->fragment_shader().alpha_location(); - shader_tex_transform_location = - program->vertex_shader().tex_transform_location(); - shader_backdrop_location = program->fragment_shader().backdrop_location(); - shader_backdrop_rect_location = - program->fragment_shader().backdrop_rect_location(); + program->vertex_shader().FillLocations(&locations); + program->fragment_shader().FillLocations(&locations); + GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); } else if (use_aa && mask_texture_id && use_color_matrix) { const RenderPassMaskColorMatrixProgramAA* program = GetRenderPassMaskColorMatrixProgramAA( tex_coord_precision, mask_sampler, shader_blend_mode); SetUseProgram(program->program()); - GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); - - shader_matrix_location = program->vertex_shader().matrix_location(); - shader_quad_location = program->vertex_shader().quad_location(); - shader_tex_transform_location = - program->vertex_shader().tex_transform_location(); - shader_edge_location = program->vertex_shader().edge_location(); - shader_viewport_location = program->vertex_shader().viewport_location(); - shader_alpha_location = program->fragment_shader().alpha_location(); - shader_mask_sampler_location = - program->fragment_shader().mask_sampler_location(); - shader_mask_tex_coord_scale_location = - program->fragment_shader().mask_tex_coord_scale_location(); - shader_mask_tex_coord_offset_location = - program->fragment_shader().mask_tex_coord_offset_location(); - shader_color_matrix_location = - program->fragment_shader().color_matrix_location(); - shader_color_offset_location = - program->fragment_shader().color_offset_location(); - shader_backdrop_location = program->fragment_shader().backdrop_location(); - shader_backdrop_rect_location = - program->fragment_shader().backdrop_rect_location(); + program->vertex_shader().FillLocations(&locations); + program->fragment_shader().FillLocations(&locations); + GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); } else if (use_aa && !mask_texture_id && use_color_matrix) { const RenderPassColorMatrixProgramAA* program = GetRenderPassColorMatrixProgramAA(tex_coord_precision, shader_blend_mode); SetUseProgram(program->program()); - GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); - - shader_matrix_location = program->vertex_shader().matrix_location(); - shader_quad_location = program->vertex_shader().quad_location(); - shader_tex_transform_location = - program->vertex_shader().tex_transform_location(); - shader_edge_location = program->vertex_shader().edge_location(); - shader_viewport_location = program->vertex_shader().viewport_location(); - shader_alpha_location = program->fragment_shader().alpha_location(); - shader_color_matrix_location = - program->fragment_shader().color_matrix_location(); - shader_color_offset_location = - program->fragment_shader().color_offset_location(); - shader_backdrop_location = program->fragment_shader().backdrop_location(); - shader_backdrop_rect_location = - program->fragment_shader().backdrop_rect_location(); + program->vertex_shader().FillLocations(&locations); + program->fragment_shader().FillLocations(&locations); + GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); } else if (!use_aa && mask_texture_id && use_color_matrix) { const RenderPassMaskColorMatrixProgram* program = GetRenderPassMaskColorMatrixProgram( tex_coord_precision, mask_sampler, shader_blend_mode); SetUseProgram(program->program()); - GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); - - shader_matrix_location = program->vertex_shader().matrix_location(); - shader_tex_transform_location = - program->vertex_shader().tex_transform_location(); - shader_mask_sampler_location = - program->fragment_shader().mask_sampler_location(); - shader_mask_tex_coord_scale_location = - program->fragment_shader().mask_tex_coord_scale_location(); - shader_mask_tex_coord_offset_location = - program->fragment_shader().mask_tex_coord_offset_location(); - shader_alpha_location = program->fragment_shader().alpha_location(); - shader_color_matrix_location = - program->fragment_shader().color_matrix_location(); - shader_color_offset_location = - program->fragment_shader().color_offset_location(); - shader_backdrop_location = program->fragment_shader().backdrop_location(); - shader_backdrop_rect_location = - program->fragment_shader().backdrop_rect_location(); + program->vertex_shader().FillLocations(&locations); + program->fragment_shader().FillLocations(&locations); + GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); } else if (!use_aa && !mask_texture_id && use_color_matrix) { const RenderPassColorMatrixProgram* program = GetRenderPassColorMatrixProgram(tex_coord_precision, shader_blend_mode); SetUseProgram(program->program()); - GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); - - shader_matrix_location = program->vertex_shader().matrix_location(); - shader_tex_transform_location = - program->vertex_shader().tex_transform_location(); - shader_alpha_location = program->fragment_shader().alpha_location(); - shader_color_matrix_location = - program->fragment_shader().color_matrix_location(); - shader_color_offset_location = - program->fragment_shader().color_offset_location(); - shader_backdrop_location = program->fragment_shader().backdrop_location(); - shader_backdrop_rect_location = - program->fragment_shader().backdrop_rect_location(); + program->vertex_shader().FillLocations(&locations); + program->fragment_shader().FillLocations(&locations); + GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); } else { const RenderPassProgram* program = GetRenderPassProgram(tex_coord_precision, shader_blend_mode); SetUseProgram(program->program()); - GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); - - shader_matrix_location = program->vertex_shader().matrix_location(); - shader_alpha_location = program->fragment_shader().alpha_location(); - shader_tex_transform_location = - program->vertex_shader().tex_transform_location(); - shader_backdrop_location = program->fragment_shader().backdrop_location(); - shader_backdrop_rect_location = - program->fragment_shader().backdrop_rect_location(); + program->vertex_shader().FillLocations(&locations); + program->fragment_shader().FillLocations(&locations); + GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); } float tex_scale_x = quad->rect.width() / static_cast<float>(contents_texture->size().width()); @@ -1202,22 +1092,22 @@ DCHECK_LE(tex_scale_x, 1.0f); DCHECK_LE(tex_scale_y, 1.0f); - DCHECK(shader_tex_transform_location != -1 || IsContextLost()); + DCHECK(locations.tex_transform != -1 || IsContextLost()); // Flip the content vertically in the shader, as the RenderPass input // texture is already oriented the same way as the framebuffer, but the // projection transform does a flip. GLC(gl_, - gl_->Uniform4f(shader_tex_transform_location, + gl_->Uniform4f(locations.tex_transform, 0.0f, tex_scale_y, tex_scale_x, -tex_scale_y)); GLint last_texture_unit = 0; - if (shader_mask_sampler_location != -1) { - DCHECK_NE(shader_mask_tex_coord_scale_location, 1); - DCHECK_NE(shader_mask_tex_coord_offset_location, 1); - GLC(gl_, gl_->Uniform1i(shader_mask_sampler_location, 1)); + if (locations.mask_sampler != -1) { + DCHECK_NE(locations.mask_tex_coord_scale, 1); + DCHECK_NE(locations.mask_tex_coord_offset, 1); + GLC(gl_, gl_->Uniform1i(locations.mask_sampler, 1)); gfx::RectF mask_uv_rect = quad->MaskUVRect(); if (mask_sampler != SAMPLER_TYPE_2D) { @@ -1229,56 +1119,56 @@ // and the RenderPass contents texture, so we flip the tex coords from the // RenderPass texture to find the mask texture coords. GLC(gl_, - gl_->Uniform2f(shader_mask_tex_coord_offset_location, + gl_->Uniform2f(locations.mask_tex_coord_offset, mask_uv_rect.x(), mask_uv_rect.bottom())); GLC(gl_, - gl_->Uniform2f(shader_mask_tex_coord_scale_location, + gl_->Uniform2f(locations.mask_tex_coord_scale, mask_uv_rect.width() / tex_scale_x, -mask_uv_rect.height() / tex_scale_y)); last_texture_unit = 1; } - if (shader_edge_location != -1) - GLC(gl_, gl_->Uniform3fv(shader_edge_location, 8, edge)); + if (locations.edge != -1) + GLC(gl_, gl_->Uniform3fv(locations.edge, 8, edge)); - if (shader_viewport_location != -1) { + if (locations.viewport != -1) { float viewport[4] = {static_cast<float>(viewport_.x()), static_cast<float>(viewport_.y()), static_cast<float>(viewport_.width()), static_cast<float>(viewport_.height()), }; - GLC(gl_, gl_->Uniform4fv(shader_viewport_location, 1, viewport)); + GLC(gl_, gl_->Uniform4fv(locations.viewport, 1, viewport)); } - if (shader_color_matrix_location != -1) { + if (locations.color_matrix != -1) { float matrix[16]; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) matrix[i * 4 + j] = SkScalarToFloat(color_matrix[j * 5 + i]); } GLC(gl_, - gl_->UniformMatrix4fv(shader_color_matrix_location, 1, false, matrix)); + gl_->UniformMatrix4fv(locations.color_matrix, 1, false, matrix)); } static const float kScale = 1.0f / 255.0f; - if (shader_color_offset_location != -1) { + if (locations.color_offset != -1) { float offset[4]; for (int i = 0; i < 4; ++i) offset[i] = SkScalarToFloat(color_matrix[i * 5 + 4]) * kScale; - GLC(gl_, gl_->Uniform4fv(shader_color_offset_location, 1, offset)); + GLC(gl_, gl_->Uniform4fv(locations.color_offset, 1, offset)); } scoped_ptr<ResourceProvider::ScopedSamplerGL> shader_background_sampler_lock; - if (shader_backdrop_location != -1) { + if (locations.backdrop != -1) { DCHECK(background_texture || background_image); - DCHECK_NE(shader_backdrop_location, 0); - DCHECK_NE(shader_backdrop_rect_location, 0); + DCHECK_NE(locations.backdrop, 0); + DCHECK_NE(locations.backdrop_rect, 0); - GLC(gl_, gl_->Uniform1i(shader_backdrop_location, ++last_texture_unit)); + GLC(gl_, gl_->Uniform1i(locations.backdrop, ++last_texture_unit)); GLC(gl_, - gl_->Uniform4f(shader_backdrop_rect_location, + gl_->Uniform4f(locations.backdrop_rect, background_rect.x(), background_rect.y(), background_rect.width(), @@ -1300,10 +1190,10 @@ } } - SetShaderOpacity(quad->opacity(), shader_alpha_location); - SetShaderQuadF(surface_quad, shader_quad_location); + SetShaderOpacity(quad->opacity(), locations.alpha); + SetShaderQuadF(surface_quad, locations.quad); DrawQuadGeometry( - frame, quad->quadTransform(), quad->rect, shader_matrix_location); + frame, quad->quadTransform(), quad->rect, locations.matrix); // Flush the compositor context before the filter bitmap goes out of // scope, so the draw gets processed before the filter texture gets deleted.
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc index 6ee388a6..5590ec3d 100644 --- a/cc/output/overlay_unittest.cc +++ b/cc/output/overlay_unittest.cc
@@ -234,7 +234,7 @@ const gfx::Rect& rect) { CheckerboardDrawQuad* checkerboard_quad = render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); - checkerboard_quad->SetNew(shared_quad_state, rect, rect, SkColor()); + checkerboard_quad->SetNew(shared_quad_state, rect, rect, SkColor(), 1.f); } void CreateFullscreenCheckeredQuad(ResourceProvider* resource_provider,
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc index 743e1cf..b30b0a5 100644 --- a/cc/output/renderer_pixeltest.cc +++ b/cc/output/renderer_pixeltest.cc
@@ -2493,6 +2493,109 @@ FuzzyPixelOffByOneComparator(true))); } +TYPED_TEST(RendererPixelTest, Checkerboards) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPassId id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + + SharedQuadState* shared_state = + CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); + + // The color's alpha value is not used. + SkColor color1 = SK_ColorGREEN; + color1 = SkColorSetA(color1, 0); + SkColor color2 = SK_ColorBLUE; + color2 = SkColorSetA(color2, 0); + + gfx::Rect content_rect(rect); + + gfx::Rect top_left(content_rect); + gfx::Rect top_right(content_rect); + gfx::Rect bottom_left(content_rect); + gfx::Rect bottom_right(content_rect); + // The format is Inset(left, top, right, bottom). + top_left.Inset(0, 0, content_rect.width() / 2, content_rect.height() / 2); + top_right.Inset(content_rect.width() / 2, 0, 0, content_rect.height() / 2); + bottom_left.Inset(0, content_rect.height() / 2, content_rect.width() / 2, 0); + bottom_right.Inset(content_rect.width() / 2, content_rect.height() / 2, 0, 0); + + // Appends checkerboard quads with a scale of 1. + CheckerboardDrawQuad* quad = + pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); + quad->SetNew(shared_state, top_left, top_left, color1, 1.f); + quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); + quad->SetNew(shared_state, top_right, top_right, color2, 1.f); + quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); + quad->SetNew(shared_state, bottom_left, bottom_left, color2, 1.f); + quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); + quad->SetNew(shared_state, bottom_right, bottom_right, color1, 1.f); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + base::FilePath::StringType path = + IsSoftwareRenderer<TypeParam>() + ? FILE_PATH_LITERAL("four_blue_green_checkers.png") + : FILE_PATH_LITERAL("checkers.png"); + EXPECT_TRUE(this->RunPixelTest(&pass_list, base::FilePath(path), + ExactPixelComparator(true))); +} + +TYPED_TEST(RendererPixelTest, CheckerboardsScaled) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPassId id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + + gfx::Transform scale; + scale.Scale(2.f, 2.f); + + SharedQuadState* shared_state = + CreateTestSharedQuadState(scale, rect, pass.get()); + + // The color's alpha value is not used. + SkColor color1 = SK_ColorGREEN; + color1 = SkColorSetA(color1, 0); + SkColor color2 = SK_ColorBLUE; + color2 = SkColorSetA(color2, 0); + + gfx::Rect content_rect(rect); + content_rect.Inset(0, 0, rect.width() / 2, rect.height() / 2); + + gfx::Rect top_left(content_rect); + gfx::Rect top_right(content_rect); + gfx::Rect bottom_left(content_rect); + gfx::Rect bottom_right(content_rect); + // The format is Inset(left, top, right, bottom). + top_left.Inset(0, 0, content_rect.width() / 2, content_rect.height() / 2); + top_right.Inset(content_rect.width() / 2, 0, 0, content_rect.height() / 2); + bottom_left.Inset(0, content_rect.height() / 2, content_rect.width() / 2, 0); + bottom_right.Inset(content_rect.width() / 2, content_rect.height() / 2, 0, 0); + + // Appends checkerboard quads with a scale of 2, and a shared quad state + // with a scale of 2. The checkers should be scaled by 2 * 2 = 4. + CheckerboardDrawQuad* quad = + pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); + quad->SetNew(shared_state, top_left, top_left, color1, 2.f); + quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); + quad->SetNew(shared_state, top_right, top_right, color2, 2.f); + quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); + quad->SetNew(shared_state, bottom_left, bottom_left, color2, 2.f); + quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); + quad->SetNew(shared_state, bottom_right, bottom_right, color1, 2.f); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + base::FilePath::StringType path = + IsSoftwareRenderer<TypeParam>() + ? FILE_PATH_LITERAL("four_blue_green_checkers.png") + : FILE_PATH_LITERAL("checkers_big.png"); + EXPECT_TRUE(this->RunPixelTest(&pass_list, base::FilePath(path), + ExactPixelComparator(true))); +} + #endif // !defined(OS_ANDROID) } // namespace
diff --git a/cc/output/shader.cc b/cc/output/shader.cc index 1891546..287ffcc 100644 --- a/cc/output/shader.cc +++ b/cc/output/shader.cc
@@ -144,6 +144,9 @@ } // namespace +ShaderLocations::ShaderLocations() { +} + TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context, int* highp_threshold_cache, int highp_threshold_min, @@ -347,6 +350,12 @@ }); } +void VertexShaderPosTexTransform::FillLocations( + ShaderLocations* locations) const { + locations->matrix = matrix_location(); + locations->tex_transform = tex_transform_location(); +} + std::string VertexShaderPosTexIdentity::GetShaderString() const { return VERTEX_SHADER(GetShaderHead(), GetShaderBody()); } @@ -560,6 +569,16 @@ }); } +void VertexShaderQuadTexTransformAA::FillLocations( + ShaderLocations* locations) const { + locations->quad = quad_location(); + locations->edge = edge_location(); + locations->viewport = viewport_location(); + locations->matrix = matrix_location(); + locations->tex_transform = tex_transform_location(); +} + + VertexShaderTile::VertexShaderTile() : matrix_location_(-1), quad_location_(-1), @@ -1105,6 +1124,14 @@ }); } +void FragmentShaderRGBATexAlpha::FillLocations( + ShaderLocations* locations) const { + locations->sampler = sampler_location(); + locations->alpha = alpha_location(); + locations->backdrop = backdrop_location(); + locations->backdrop_rect = backdrop_rect_location(); +} + std::string FragmentShaderRGBATexColorMatrixAlpha::GetShaderString( TexCoordPrecision precision, SamplerType sampler) const { @@ -1136,6 +1163,16 @@ }); } +void FragmentShaderRGBATexColorMatrixAlpha::FillLocations( + ShaderLocations* locations) const { + locations->sampler = sampler_location(); + locations->alpha = alpha_location(); + locations->color_matrix = color_matrix_location(); + locations->color_offset = color_offset_location(); + locations->backdrop = backdrop_location(); + locations->backdrop_rect = backdrop_rect_location(); +} + std::string FragmentShaderRGBATexVaryingAlpha::GetShaderString( TexCoordPrecision precision, SamplerType sampler) const { @@ -1405,6 +1442,14 @@ }); } +void FragmentShaderRGBATexAlphaAA::FillLocations( + ShaderLocations* locations) const { + locations->sampler = sampler_location(); + locations->alpha = alpha_location(); + locations->backdrop = backdrop_location(); + locations->backdrop_rect = backdrop_rect_location(); +} + FragmentTexClampAlphaAABinding::FragmentTexClampAlphaAABinding() : sampler_location_(-1), alpha_location_(-1), @@ -1560,6 +1605,17 @@ }); } +void FragmentShaderRGBATexAlphaMask::FillLocations( + ShaderLocations* locations) const { + locations->sampler = sampler_location(); + locations->mask_sampler = mask_sampler_location(); + locations->mask_tex_coord_scale = mask_tex_coord_scale_location(); + locations->mask_tex_coord_offset = mask_tex_coord_offset_location(); + locations->alpha = alpha_location(); + locations->backdrop = backdrop_location(); + locations->backdrop_rect = backdrop_rect_location(); +} + FragmentShaderRGBATexAlphaMaskAA::FragmentShaderRGBATexAlphaMaskAA() : sampler_location_(-1), mask_sampler_location_(-1), @@ -1630,6 +1686,17 @@ }); } +void FragmentShaderRGBATexAlphaMaskAA::FillLocations( + ShaderLocations* locations) const { + locations->sampler = sampler_location(); + locations->mask_sampler = mask_sampler_location(); + locations->mask_tex_coord_scale = mask_tex_coord_scale_location(); + locations->mask_tex_coord_offset = mask_tex_coord_offset_location(); + locations->alpha = alpha_location(); + locations->backdrop = backdrop_location(); + locations->backdrop_rect = backdrop_rect_location(); +} + FragmentShaderRGBATexAlphaMaskColorMatrixAA:: FragmentShaderRGBATexAlphaMaskColorMatrixAA() : sampler_location_(-1), @@ -1714,6 +1781,19 @@ }); } +void FragmentShaderRGBATexAlphaMaskColorMatrixAA::FillLocations( + ShaderLocations* locations) const { + locations->sampler = sampler_location(); + locations->alpha = alpha_location(); + locations->mask_sampler = mask_sampler_location(); + locations->mask_tex_coord_scale = mask_tex_coord_scale_location(); + locations->mask_tex_coord_offset = mask_tex_coord_offset_location(); + locations->color_matrix = color_matrix_location(); + locations->color_offset = color_offset_location(); + locations->backdrop = backdrop_location(); + locations->backdrop_rect = backdrop_rect_location(); +} + FragmentShaderRGBATexAlphaColorMatrixAA:: FragmentShaderRGBATexAlphaColorMatrixAA() : sampler_location_(-1), @@ -1778,6 +1858,16 @@ }); } +void FragmentShaderRGBATexAlphaColorMatrixAA::FillLocations( + ShaderLocations* locations) const { + locations->sampler = sampler_location(); + locations->alpha = alpha_location(); + locations->color_matrix = color_matrix_location(); + locations->color_offset = color_offset_location(); + locations->backdrop = backdrop_location(); + locations->backdrop_rect = backdrop_rect_location(); +} + FragmentShaderRGBATexAlphaMaskColorMatrix:: FragmentShaderRGBATexAlphaMaskColorMatrix() : sampler_location_(-1), @@ -1855,6 +1945,19 @@ }); } +void FragmentShaderRGBATexAlphaMaskColorMatrix::FillLocations( + ShaderLocations* locations) const { + locations->sampler = sampler_location(); + locations->mask_sampler = mask_sampler_location(); + locations->mask_tex_coord_scale = mask_tex_coord_scale_location(); + locations->mask_tex_coord_offset = mask_tex_coord_offset_location(); + locations->alpha = alpha_location(); + locations->color_matrix = color_matrix_location(); + locations->color_offset = color_offset_location(); + locations->backdrop = backdrop_location(); + locations->backdrop_rect = backdrop_rect_location(); +} + FragmentShaderYUVVideo::FragmentShaderYUVVideo() : y_texture_location_(-1), u_texture_location_(-1),
diff --git a/cc/output/shader.h b/cc/output/shader.h index 93407d4..7ef6ea9a 100644 --- a/cc/output/shader.h +++ b/cc/output/shader.h
@@ -59,6 +59,25 @@ LAST_BLEND_MODE = BLEND_MODE_LUMINOSITY }; +struct ShaderLocations { + ShaderLocations(); + + int sampler = -1; + int quad = -1; + int edge = -1; + int viewport = -1; + int mask_sampler = -1; + int mask_tex_coord_scale = -1; + int mask_tex_coord_offset = -1; + int matrix = -1; + int alpha = -1; + int color_matrix = -1; + int color_offset = -1; + int tex_transform = -1; + int backdrop = -1; + int backdrop_rect = -1; +}; + // Note: The highp_threshold_cache must be provided by the caller to make // the caching multi-thread/context safe in an easy low-overhead manner. // The caller must make sure to clear highp_threshold_cache to 0, so it can be @@ -156,6 +175,7 @@ std::string GetShaderString() const; static std::string GetShaderHead(); static std::string GetShaderBody(); + void FillLocations(ShaderLocations* locations) const; int matrix_location() const { return matrix_location_; } int tex_transform_location() const { return tex_transform_location_; } @@ -228,6 +248,7 @@ std::string GetShaderString() const; static std::string GetShaderHead(); static std::string GetShaderBody(); + void FillLocations(ShaderLocations* locations) const; int matrix_location() const { return matrix_location_; } int viewport_location() const { return viewport_location_; } @@ -460,6 +481,7 @@ TexCoordPrecision precision, SamplerType sampler) const; static std::string GetShaderHead(); static std::string GetShaderBody(); + void FillLocations(ShaderLocations* locations) const; }; class FragmentShaderRGBATexColorMatrixAlpha @@ -469,6 +491,7 @@ SamplerType sampler) const; static std::string GetShaderHead(); static std::string GetShaderBody(); + void FillLocations(ShaderLocations* locations) const; }; class FragmentShaderRGBATexOpaque : public FragmentTexOpaqueBinding { @@ -516,6 +539,7 @@ TexCoordPrecision precision, SamplerType sampler) const; static std::string GetShaderHead(); static std::string GetShaderBody(); + void FillLocations(ShaderLocations* locations) const; int alpha_location() const { return alpha_location_; } int sampler_location() const { return sampler_location_; } @@ -574,7 +598,7 @@ TexCoordPrecision precision, SamplerType sampler) const; static std::string GetShaderHead(); static std::string GetShaderBody(); - + void FillLocations(ShaderLocations* locations) const; void Init(gpu::gles2::GLES2Interface* context, unsigned program, int* base_uniform_index); @@ -605,7 +629,7 @@ TexCoordPrecision precision, SamplerType sampler) const; static std::string GetShaderHead(); static std::string GetShaderBody(); - + void FillLocations(ShaderLocations* locations) const; void Init(gpu::gles2::GLES2Interface* context, unsigned program, int* base_uniform_index); @@ -637,7 +661,7 @@ TexCoordPrecision precision, SamplerType sampler) const; static std::string GetShaderHead(); static std::string GetShaderBody(); - + void FillLocations(ShaderLocations* locations) const; void Init(gpu::gles2::GLES2Interface* context, unsigned program, int* base_uniform_index); @@ -670,7 +694,7 @@ TexCoordPrecision precision, SamplerType sampler) const; static std::string GetShaderHead(); static std::string GetShaderBody(); - + void FillLocations(ShaderLocations* locations) const; void Init(gpu::gles2::GLES2Interface* context, unsigned program, int* base_uniform_index); @@ -693,7 +717,7 @@ TexCoordPrecision precision, SamplerType sampler) const; static std::string GetShaderHead(); static std::string GetShaderBody(); - + void FillLocations(ShaderLocations* locations) const; void Init(gpu::gles2::GLES2Interface* context, unsigned program, int* base_uniform_index);
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc index 5360d594bf..a4b54282 100644 --- a/cc/output/software_renderer.cc +++ b/cc/output/software_renderer.cc
@@ -314,7 +314,7 @@ gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional( QuadVertexRect(), quad->rect, quad->visible_rect); current_paint_.setColor(quad->color); - current_paint_.setAlpha(quad->opacity() * SkColorGetA(quad->color)); + current_paint_.setAlpha(quad->opacity()); current_canvas_->drawRect(gfx::RectFToSkRect(visible_quad_vertex_rect), current_paint_); }
diff --git a/cc/quads/checkerboard_draw_quad.cc b/cc/quads/checkerboard_draw_quad.cc index 2d8957d..db6ad1e 100644 --- a/cc/quads/checkerboard_draw_quad.cc +++ b/cc/quads/checkerboard_draw_quad.cc
@@ -10,17 +10,20 @@ namespace cc { -CheckerboardDrawQuad::CheckerboardDrawQuad() : color(0) {} +CheckerboardDrawQuad::CheckerboardDrawQuad() : color(0), scale(0.f) { +} void CheckerboardDrawQuad::SetNew(const SharedQuadState* shared_quad_state, const gfx::Rect& rect, const gfx::Rect& visible_rect, - SkColor color) { + SkColor color, + float scale) { gfx::Rect opaque_rect = SkColorGetA(color) == 255 ? rect : gfx::Rect(); bool needs_blending = false; DrawQuad::SetAll(shared_quad_state, DrawQuad::CHECKERBOARD, rect, opaque_rect, visible_rect, needs_blending); this->color = color; + this->scale = scale; } void CheckerboardDrawQuad::SetAll(const SharedQuadState* shared_quad_state, @@ -28,10 +31,12 @@ const gfx::Rect& opaque_rect, const gfx::Rect& visible_rect, bool needs_blending, - SkColor color) { + SkColor color, + float scale) { DrawQuad::SetAll(shared_quad_state, DrawQuad::CHECKERBOARD, rect, opaque_rect, visible_rect, needs_blending); this->color = color; + this->scale = scale; } void CheckerboardDrawQuad::IterateResources( @@ -46,6 +51,7 @@ void CheckerboardDrawQuad::ExtendValue( base::trace_event::TracedValue* value) const { value->SetInteger("color", color); + value->SetDouble("scale", scale); } } // namespace cc
diff --git a/cc/quads/checkerboard_draw_quad.h b/cc/quads/checkerboard_draw_quad.h index 1ab6338..9ecf4f0 100644 --- a/cc/quads/checkerboard_draw_quad.h +++ b/cc/quads/checkerboard_draw_quad.h
@@ -19,16 +19,19 @@ void SetNew(const SharedQuadState* shared_quad_state, const gfx::Rect& rect, const gfx::Rect& visible_rect, - SkColor color); + SkColor color, + float scale); void SetAll(const SharedQuadState* shared_quad_state, const gfx::Rect& rect, const gfx::Rect& opaque_rect, const gfx::Rect& visible_rect, bool needs_blending, - SkColor color); + SkColor color, + float scale); SkColor color; + float scale; void IterateResources(const ResourceIteratorCallback& callback) override;
diff --git a/cc/quads/draw_quad_unittest.cc b/cc/quads/draw_quad_unittest.cc index b7c1bdfe..5b5f0b9 100644 --- a/cc/quads/draw_quad_unittest.cc +++ b/cc/quads/draw_quad_unittest.cc
@@ -369,16 +369,19 @@ TEST(DrawQuadTest, CopyCheckerboardDrawQuad) { gfx::Rect visible_rect(40, 50, 30, 20); SkColor color = 0xfabb0011; + float scale = 2.3f; CREATE_SHARED_STATE(); - CREATE_QUAD_2_NEW(CheckerboardDrawQuad, visible_rect, color); + CREATE_QUAD_3_NEW(CheckerboardDrawQuad, visible_rect, color, scale); EXPECT_EQ(DrawQuad::CHECKERBOARD, copy_quad->material); EXPECT_EQ(visible_rect, copy_quad->visible_rect); EXPECT_EQ(color, copy_quad->color); + EXPECT_EQ(scale, copy_quad->scale); - CREATE_QUAD_1_ALL(CheckerboardDrawQuad, color); + CREATE_QUAD_2_ALL(CheckerboardDrawQuad, color, scale); EXPECT_EQ(DrawQuad::CHECKERBOARD, copy_quad->material); EXPECT_EQ(color, copy_quad->color); + EXPECT_EQ(scale, copy_quad->scale); } TEST(DrawQuadTest, CopyDebugBorderDrawQuad) { @@ -736,9 +739,10 @@ TEST_F(DrawQuadIteratorTest, CheckerboardDrawQuad) { gfx::Rect visible_rect(40, 50, 30, 20); SkColor color = 0xfabb0011; + float scale = 3.2f; CREATE_SHARED_STATE(); - CREATE_QUAD_2_NEW(CheckerboardDrawQuad, visible_rect, color); + CREATE_QUAD_3_NEW(CheckerboardDrawQuad, visible_rect, color, scale); EXPECT_EQ(0, IterateAndCount(quad_new)); }
diff --git a/cc/quads/render_pass_unittest.cc b/cc/quads/render_pass_unittest.cc index 8775d81..e6f39bca 100644 --- a/cc/quads/render_pass_unittest.cc +++ b/cc/quads/render_pass_unittest.cc
@@ -92,8 +92,8 @@ CheckerboardDrawQuad* checkerboard_quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); - checkerboard_quad->SetNew( - pass->shared_quad_state_list.back(), gfx::Rect(), gfx::Rect(), SkColor()); + checkerboard_quad->SetNew(pass->shared_quad_state_list.back(), gfx::Rect(), + gfx::Rect(), SkColor(), 1.f); RenderPassId new_id(63, 4); @@ -143,16 +143,14 @@ CheckerboardDrawQuad* checkerboard_quad1 = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); checkerboard_quad1->SetNew(pass->shared_quad_state_list.back(), - gfx::Rect(1, 1, 1, 1), - gfx::Rect(1, 1, 1, 1), - SkColor()); + gfx::Rect(1, 1, 1, 1), gfx::Rect(1, 1, 1, 1), + SkColor(), 1.f); CheckerboardDrawQuad* checkerboard_quad2 = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); checkerboard_quad2->SetNew(pass->shared_quad_state_list.back(), - gfx::Rect(2, 2, 2, 2), - gfx::Rect(2, 2, 2, 2), - SkColor()); + gfx::Rect(2, 2, 2, 2), gfx::Rect(2, 2, 2, 2), + SkColor(), 1.f); // And two quads using another shared state. SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState(); @@ -168,16 +166,14 @@ CheckerboardDrawQuad* checkerboard_quad3 = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); checkerboard_quad3->SetNew(pass->shared_quad_state_list.back(), - gfx::Rect(3, 3, 3, 3), - gfx::Rect(3, 3, 3, 3), - SkColor()); + gfx::Rect(3, 3, 3, 3), gfx::Rect(3, 3, 3, 3), + SkColor(), 1.f); CheckerboardDrawQuad* checkerboard_quad4 = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); checkerboard_quad4->SetNew(pass->shared_quad_state_list.back(), - gfx::Rect(4, 4, 4, 4), - gfx::Rect(4, 4, 4, 4), - SkColor()); + gfx::Rect(4, 4, 4, 4), gfx::Rect(4, 4, 4, 4), + SkColor(), 1.f); // A second render pass with a quad. RenderPassId contrib_id(4, 1); @@ -208,9 +204,8 @@ CheckerboardDrawQuad* contrib_quad = contrib->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); contrib_quad->SetNew(contrib->shared_quad_state_list.back(), - gfx::Rect(3, 3, 3, 3), - gfx::Rect(3, 3, 3, 3), - SkColor()); + gfx::Rect(3, 3, 3, 3), gfx::Rect(3, 3, 3, 3), SkColor(), + 1.f); // And a RenderPassDrawQuad for the contributing pass. scoped_ptr<RenderPassDrawQuad> pass_quad = @@ -267,9 +262,8 @@ CheckerboardDrawQuad* checkerboard_quad1 = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); checkerboard_quad1->SetNew(pass->shared_quad_state_list.back(), - gfx::Rect(1, 1, 1, 1), - gfx::Rect(1, 1, 1, 1), - SkColor()); + gfx::Rect(1, 1, 1, 1), gfx::Rect(1, 1, 1, 1), + SkColor(), 1.f); // A shared state with no quads, they were culled. SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState(); @@ -307,9 +301,8 @@ CheckerboardDrawQuad* checkerboard_quad2 = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); checkerboard_quad2->SetNew(pass->shared_quad_state_list.back(), - gfx::Rect(3, 3, 3, 3), - gfx::Rect(3, 3, 3, 3), - SkColor()); + gfx::Rect(3, 3, 3, 3), gfx::Rect(3, 3, 3, 3), + SkColor(), 1.f); pass_list.push_back(pass.Pass());
diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc index d931543..bd150f4 100644 --- a/cc/resources/picture_layer_tiling_set.cc +++ b/cc/resources/picture_layer_tiling_set.cc
@@ -53,48 +53,53 @@ PictureLayerTilingSet::~PictureLayerTilingSet() { } +void PictureLayerTilingSet::CopyTilingsFromPendingTwin( + const PictureLayerTilingSet* pending_twin_set, + const scoped_refptr<RasterSource>& raster_source) { + if (pending_twin_set->tilings_.empty()) { + // If the twin (pending) tiling set is empty, it was not updated for the + // current frame. So we drop tilings from our set as well, instead of + // leaving behind unshared tilings that are all non-ideal. + RemoveAllTilings(); + } + + for (PictureLayerTiling* pending_twin_tiling : pending_twin_set->tilings_) { + float contents_scale = pending_twin_tiling->contents_scale(); + PictureLayerTiling* this_tiling = FindTilingWithScale(contents_scale); + if (!this_tiling) { + scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create( + contents_scale, raster_source, client_, max_tiles_for_interest_area_, + skewport_target_time_in_seconds_, + skewport_extrapolation_limit_in_content_pixels_); + tilings_.push_back(new_tiling.Pass()); + this_tiling = tilings_.back(); + } + this_tiling->CloneTilesAndPropertiesFrom(*pending_twin_tiling); + } +} + void PictureLayerTilingSet::UpdateTilingsToCurrentRasterSource( scoped_refptr<RasterSource> raster_source, - const PictureLayerTilingSet* twin_set, + const PictureLayerTilingSet* pending_twin_set, const Region& layer_invalidation, float minimum_contents_scale, float maximum_contents_scale) { RemoveTilingsBelowScale(minimum_contents_scale); RemoveTilingsAboveScale(maximum_contents_scale); - // Copy over tilings that are shared with the |twin_set| tiling set (if it - // exists). - if (twin_set) { - if (twin_set->tilings_.empty()) { - // If the twin (pending) tiling set is empty, it was not updated for the - // current frame. So we drop tilings from our set as well, instead of - // leaving behind unshared tilings that are all non-ideal. - RemoveAllTilings(); - } + // Copy over tilings that are shared with the |pending_twin_set| tiling set + // (if it exists). + if (pending_twin_set) + CopyTilingsFromPendingTwin(pending_twin_set, raster_source); - for (PictureLayerTiling* twin_tiling : twin_set->tilings_) { - float contents_scale = twin_tiling->contents_scale(); - DCHECK_GE(contents_scale, minimum_contents_scale); - DCHECK_LE(contents_scale, maximum_contents_scale); - - PictureLayerTiling* this_tiling = FindTilingWithScale(contents_scale); - if (!this_tiling) { - scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create( - contents_scale, raster_source, client_, - max_tiles_for_interest_area_, skewport_target_time_in_seconds_, - skewport_extrapolation_limit_in_content_pixels_); - tilings_.push_back(new_tiling.Pass()); - this_tiling = tilings_.back(); - } - this_tiling->CloneTilesAndPropertiesFrom(*twin_tiling); - } - } - - // For unshared tilings, invalidate tiles and update them to the new raster - // source. + // If the tiling is not shared (FindTilingWithScale returns nullptr) or if + // |this| is the sync set (pending_twin_set is nullptr), then invalidate + // tiles and update them to the new raster source. for (PictureLayerTiling* tiling : tilings_) { - if (twin_set && twin_set->FindTilingWithScale(tiling->contents_scale())) + if (pending_twin_set && + pending_twin_set->FindTilingWithScale(tiling->contents_scale())) { continue; + } tiling->SetRasterSourceAndResize(raster_source); tiling->Invalidate(layer_invalidation); @@ -104,9 +109,9 @@ // raster source. tiling->CreateMissingTilesInLiveTilesRect(); - // If |twin_set| is present, use the resolutions from there. Otherwise leave - // all resolutions as they are. - if (twin_set) + // If |pending_twin_set| is present, then |this| is active and |tiling| is + // not in the pending set, which means it is now NON_IDEAL_RESOLUTION. + if (pending_twin_set) tiling->set_resolution(NON_IDEAL_RESOLUTION); } @@ -126,11 +131,12 @@ DCHECK_LE(NumHighResTilings(), 1); // When commiting from the main thread the high res tiling may get dropped, // but when cloning to the active tree, there should always be one. - if (twin_set) { + if (pending_twin_set) { DCHECK_EQ(1, NumHighResTilings()) << " num tilings on active: " << tilings_.size() - << " num tilings on pending: " << twin_set->tilings_.size() - << " num high res on pending: " << twin_set->NumHighResTilings() + << " num tilings on pending: " << pending_twin_set->tilings_.size() + << " num high res on pending: " + << pending_twin_set->NumHighResTilings() << " are on active tree: " << (client_->GetTree() == ACTIVE_TREE); } }
diff --git a/cc/resources/picture_layer_tiling_set.h b/cc/resources/picture_layer_tiling_set.h index fc1e581..a4c2fd8 100644 --- a/cc/resources/picture_layer_tiling_set.h +++ b/cc/resources/picture_layer_tiling_set.h
@@ -55,9 +55,15 @@ PictureLayerTilingSet* recycled_twin_set); void RemoveNonIdealTilings(); + // This function can be called on both the active and pending tree. + // |pending_twin_set| represents the current pending twin. In situations where + // this is called on the active tree in two trees situations, + // |pending_twin_set| represents the tiling set from the pending twin layer. + // In situations where this is called on the sync tree (whether it's pending + // or active in cases of one tree), |pending_twin_set| should be nullptr. void UpdateTilingsToCurrentRasterSource( scoped_refptr<RasterSource> raster_source, - const PictureLayerTilingSet* twin_set, + const PictureLayerTilingSet* pending_twin_set, const Region& layer_invalidation, float minimum_contents_scale, float maximum_contents_scale); @@ -163,6 +169,10 @@ float skewport_target_time_in_seconds, int skewport_extrapolation_limit_in_content_pixels); + void CopyTilingsFromPendingTwin( + const PictureLayerTilingSet* pending_twin_set, + const scoped_refptr<RasterSource>& raster_source); + // Remove one tiling. void Remove(PictureLayerTiling* tiling);
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index 115238f..805f4d7 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc
@@ -898,11 +898,9 @@ GLES2Interface* gl = ContextGL(); DCHECK(gl); - resource->gl_id = texture_id_allocator_->NextId(); - GLC(gl, gl->BindTexture(resource->target, resource->gl_id)); - GLC(gl, - gl->ConsumeTextureCHROMIUM(resource->mailbox.target(), - resource->mailbox.name())); + resource->gl_id = + GLC(gl, gl->CreateAndConsumeTextureCHROMIUM(resource->mailbox.target(), + resource->mailbox.name())); } if (!resource->pixels && resource->has_shared_bitmap_id && @@ -1595,9 +1593,6 @@ LazyCreate(source); DCHECK(source->gl_id); DCHECK(source->origin == Resource::INTERNAL); - GLC(gl, - gl->BindTexture(resource->mailbox_holder.texture_target, - source->gl_id)); if (source->image_id) { DCHECK(source->dirty_image); BindImageForSampling(source); @@ -1605,9 +1600,10 @@ // This is a resource allocated by the compositor, we need to produce it. // Don't set a sync point, the caller will do it. GLC(gl, gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name)); - GLC(gl, - gl->ProduceTextureCHROMIUM(resource->mailbox_holder.texture_target, - resource->mailbox_holder.mailbox.name)); + GLC(gl, gl->ProduceTextureDirectCHROMIUM( + source->gl_id, resource->mailbox_holder.texture_target, + resource->mailbox_holder.mailbox.name)); + source->mailbox = TextureMailbox(resource->mailbox_holder); } else { DCHECK(source->mailbox.IsTexture());
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc index fdd7fc0..24b91bf 100644 --- a/cc/resources/resource_provider_unittest.cc +++ b/cc/resources/resource_provider_unittest.cc
@@ -97,10 +97,10 @@ MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param)); MOCK_METHOD1(waitSyncPoint, void(GLuint sync_point)); MOCK_METHOD0(insertSyncPoint, GLuint(void)); - MOCK_METHOD2(produceTextureCHROMIUM, - void(GLenum target, const GLbyte* mailbox)); - MOCK_METHOD2(consumeTextureCHROMIUM, - void(GLenum target, const GLbyte* mailbox)); + MOCK_METHOD3(produceTextureDirectCHROMIUM, + void(GLuint texture, GLenum target, const GLbyte* mailbox)); + MOCK_METHOD2(createAndConsumeTextureCHROMIUM, + unsigned(GLenum target, const GLbyte* mailbox)); // Force all textures to be consecutive numbers starting at "1", // so we easily can test for them. @@ -258,25 +258,27 @@ return shared_data_->GenMailbox(mailbox); } - void produceTextureCHROMIUM(GLenum target, const GLbyte* mailbox) override { - CheckTextureIsBound(target); - + void produceTextureDirectCHROMIUM(GLuint texture, + GLenum target, + const GLbyte* mailbox) override { // Delay moving the texture into the mailbox until the next // InsertSyncPoint, so that it is not visible to other contexts that // haven't waited on that sync point. scoped_ptr<PendingProduceTexture> pending(new PendingProduceTexture); memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox)); base::AutoLock lock_for_texture_access(namespace_->lock); - pending->texture = BoundTexture(target); + pending->texture = UnboundTexture(texture); pending_produce_textures_.push_back(pending.Pass()); } - void consumeTextureCHROMIUM(GLenum target, const GLbyte* mailbox) override { - CheckTextureIsBound(target); + GLuint createAndConsumeTextureCHROMIUM(GLenum target, + const GLbyte* mailbox) override { + GLuint texture_id = createTexture(); base::AutoLock lock_for_texture_access(namespace_->lock); scoped_refptr<TestTexture> texture = shared_data_->ConsumeTexture(mailbox, last_waited_sync_point_); - namespace_->textures.Replace(BoundTextureId(target), texture); + namespace_->textures.Replace(texture_id, texture); + return texture_id; } void GetPixels(const gfx::Size& size, @@ -461,9 +463,9 @@ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) { unsigned texture = child_context_->createTexture(); gpu::Mailbox gpu_mailbox; - child_context_->bindTexture(GL_TEXTURE_2D, texture); child_context_->genMailboxCHROMIUM(gpu_mailbox.name); - child_context_->produceTextureCHROMIUM(GL_TEXTURE_2D, gpu_mailbox.name); + child_context_->produceTextureDirectCHROMIUM(texture, GL_TEXTURE_2D, + gpu_mailbox.name); *sync_point = child_context_->insertSyncPoint(); EXPECT_LT(0u, *sync_point); @@ -666,12 +668,11 @@ } GLuint external_texture_id = child_context_->createExternalTexture(); - child_context_->bindTexture(GL_TEXTURE_EXTERNAL_OES, external_texture_id); gpu::Mailbox external_mailbox; child_context_->genMailboxCHROMIUM(external_mailbox.name); - child_context_->produceTextureCHROMIUM(GL_TEXTURE_EXTERNAL_OES, - external_mailbox.name); + child_context_->produceTextureDirectCHROMIUM( + external_texture_id, GL_TEXTURE_EXTERNAL_OES, external_mailbox.name); const GLuint external_sync_point = child_context_->insertSyncPoint(); ResourceProvider::ResourceId id4 = child_resource_provider_->CreateResourceFromTextureMailbox( @@ -1745,9 +1746,8 @@ resource_ids_to_transfer.push_back(id); TransferableResourceArray list; - EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id)); EXPECT_CALL(*child_context, - produceTextureCHROMIUM(GL_TEXTURE_2D, _)); + produceTextureDirectCHROMIUM(_, GL_TEXTURE_2D, _)); EXPECT_CALL(*child_context, insertSyncPoint()); child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list); @@ -1757,8 +1757,9 @@ EXPECT_EQ(static_cast<unsigned>(child_filter), list[0].filter); EXPECT_CALL(*parent_context, - bindTexture(GL_TEXTURE_2D, parent_texture_id)); - EXPECT_CALL(*parent_context, consumeTextureCHROMIUM(GL_TEXTURE_2D, _)); + createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, _)) + .WillOnce(Return(parent_texture_id)); + parent_resource_provider->ReceiveFromChild(child_id, list); { parent_resource_provider->WaitSyncPointIfNeeded(list[0].id); @@ -1842,7 +1843,7 @@ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data); gpu::Mailbox mailbox; context()->genMailboxCHROMIUM(mailbox.name); - context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); + context()->produceTextureDirectCHROMIUM(texture, GL_TEXTURE_2D, mailbox.name); uint32 sync_point = context()->insertSyncPoint(); // All the logic below assumes that the sync points are all positive. @@ -1876,14 +1877,15 @@ EXPECT_EQ(0u, release_sync_point); context()->waitSyncPoint(list[0].mailbox_holder.sync_point); - unsigned other_texture = context()->createTexture(); - context()->bindTexture(GL_TEXTURE_2D, other_texture); - context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); + unsigned other_texture = + context()->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); uint8_t test_data[4] = { 0 }; context()->GetPixels( gfx::Size(1, 1), RGBA_8888, test_data); EXPECT_EQ(0, memcmp(data, test_data, sizeof(data))); - context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); + + context()->produceTextureDirectCHROMIUM(other_texture, GL_TEXTURE_2D, + mailbox.name); context()->deleteTexture(other_texture); list[0].mailbox_holder.sync_point = context()->insertSyncPoint(); EXPECT_LT(0u, list[0].mailbox_holder.sync_point); @@ -1927,14 +1929,15 @@ EXPECT_EQ(0u, release_sync_point); context()->waitSyncPoint(list[0].mailbox_holder.sync_point); - unsigned other_texture = context()->createTexture(); - context()->bindTexture(GL_TEXTURE_2D, other_texture); - context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); + unsigned other_texture = + context()->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); uint8_t test_data[4] = { 0 }; context()->GetPixels( gfx::Size(1, 1), RGBA_8888, test_data); EXPECT_EQ(0, memcmp(data, test_data, sizeof(data))); - context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); + + context()->produceTextureDirectCHROMIUM(other_texture, GL_TEXTURE_2D, + mailbox.name); context()->deleteTexture(other_texture); list[0].mailbox_holder.sync_point = context()->insertSyncPoint(); EXPECT_LT(0u, list[0].mailbox_holder.sync_point); @@ -1955,8 +1958,8 @@ } context()->waitSyncPoint(release_sync_point); - context()->bindTexture(GL_TEXTURE_2D, texture); - context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); + texture = + context()->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); context()->deleteTexture(texture); } @@ -2264,7 +2267,7 @@ context()->bindTexture(GL_TEXTURE_2D, texture); gpu::Mailbox mailbox; context()->genMailboxCHROMIUM(mailbox.name); - context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); + context()->produceTextureDirectCHROMIUM(texture, GL_TEXTURE_2D, mailbox.name); uint32 sync_point = context()->insertSyncPoint(); EXPECT_LT(0u, sync_point); @@ -2644,8 +2647,8 @@ EXPECT_CALL(*context, bindTexture(_, _)).Times(0); EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); EXPECT_CALL(*context, insertSyncPoint()).Times(0); - EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); - EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); + EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0); gpu::Mailbox gpu_mailbox; memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1); @@ -2674,12 +2677,12 @@ resource_provider->WaitSyncPointIfNeeded(id); Mock::VerifyAndClearExpectations(context); - // Using the texture does a consume of the mailbox. - EXPECT_CALL(*context, bindTexture(target, texture_id)).Times(2); - EXPECT_CALL(*context, consumeTextureCHROMIUM(target, _)); + EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(target, _)) + .WillOnce(Return(texture_id)); + EXPECT_CALL(*context, bindTexture(target, texture_id)); EXPECT_CALL(*context, insertSyncPoint()).Times(0); - EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); // The sampler will reset these if |mailbox_nearest_neighbor| does not // match |sampler_filter|. @@ -2698,10 +2701,10 @@ // necessary. EXPECT_CALL(*context, bindTexture(_, _)).Times(0); EXPECT_CALL(*context, insertSyncPoint()); - EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); - EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0); } resource_provider->DeleteResource(id); @@ -2786,15 +2789,14 @@ false, 1)); - unsigned texture_id = 1; uint32 sync_point = 30; unsigned target = GL_TEXTURE_EXTERNAL_OES; EXPECT_CALL(*context, bindTexture(_, _)).Times(0); EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); EXPECT_CALL(*context, insertSyncPoint()).Times(0); - EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); - EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); + EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0); gpu::Mailbox gpu_mailbox; memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1); @@ -2816,12 +2818,13 @@ resource_provider->WaitSyncPointIfNeeded(id); Mock::VerifyAndClearExpectations(context); - // Using the texture does a consume of the mailbox. - EXPECT_CALL(*context, bindTexture(target, texture_id)); - EXPECT_CALL(*context, consumeTextureCHROMIUM(target, _)); + unsigned texture_id = 1; + + EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(target, _)) + .WillOnce(Return(texture_id)); EXPECT_CALL(*context, insertSyncPoint()).Times(0); - EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); ResourceProvider::ScopedReadLockGL lock(resource_provider.get(), id); Mock::VerifyAndClearExpectations(context); @@ -2830,10 +2833,10 @@ // necessary. EXPECT_CALL(*context, bindTexture(_, _)).Times(0); EXPECT_CALL(*context, insertSyncPoint()); - EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); - EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0); } } @@ -2867,8 +2870,8 @@ EXPECT_CALL(*context, bindTexture(_, _)).Times(0); EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); EXPECT_CALL(*context, insertSyncPoint()).Times(0); - EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); - EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); + EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0); gpu::Mailbox gpu_mailbox; memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1); @@ -2926,8 +2929,8 @@ EXPECT_CALL(*context, bindTexture(_, _)).Times(0); EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); EXPECT_CALL(*context, insertSyncPoint()).Times(0); - EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); - EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); + EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0); gpu::Mailbox gpu_mailbox; memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1);
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index ba1af732..70d726d4 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc
@@ -79,7 +79,6 @@ const SchedulerSettings& scheduler_settings, int layer_tree_host_id, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - base::PowerMonitor* power_monitor, scoped_ptr<BeginFrameSource> external_begin_frame_source, SchedulerFrameSourcesConstructor* frame_sources_constructor) : frame_source_(), @@ -93,7 +92,6 @@ client_(client), layer_tree_host_id_(layer_tree_host_id), task_runner_(task_runner), - power_monitor_(power_monitor), state_machine_(scheduler_settings), inside_process_scheduled_actions_(false), inside_action_(SchedulerStateMachine::ACTION_NONE), @@ -132,12 +130,9 @@ unthrottled_frame_source_ = frame_sources_constructor->ConstructUnthrottledFrameSource(this); frame_source_->AddSource(unthrottled_frame_source_); - - SetupPowerMonitoring(); } Scheduler::~Scheduler() { - TeardownPowerMonitoring(); if (frame_source_->NeedsBeginFrames()) frame_source_->SetNeedsBeginFrames(false); } @@ -151,27 +146,6 @@ return now; } -void Scheduler::SetupPowerMonitoring() { - if (settings_.disable_hi_res_timer_tasks_on_battery) { - DCHECK(power_monitor_); - power_monitor_->AddObserver(this); - state_machine_.SetImplLatencyTakesPriorityOnBattery( - power_monitor_->IsOnBatteryPower()); - } -} - -void Scheduler::TeardownPowerMonitoring() { - if (settings_.disable_hi_res_timer_tasks_on_battery) { - DCHECK(power_monitor_); - power_monitor_->RemoveObserver(this); - } -} - -void Scheduler::OnPowerStateChange(bool on_battery_power) { - DCHECK(settings_.disable_hi_res_timer_tasks_on_battery); - state_machine_.SetImplLatencyTakesPriorityOnBattery(on_battery_power); -} - void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, base::TimeDelta interval) { // TODO(brianderson): We should not be receiving 0 intervals.
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h index 370ac25..8ed584a 100644 --- a/cc/scheduler/scheduler.h +++ b/cc/scheduler/scheduler.h
@@ -11,8 +11,6 @@ #include "base/basictypes.h" #include "base/cancelable_callback.h" #include "base/memory/scoped_ptr.h" -#include "base/power_monitor/power_monitor.h" -#include "base/power_monitor/power_observer.h" #include "base/time/time.h" #include "cc/base/cc_export.h" #include "cc/output/begin_frame_args.h" @@ -75,22 +73,19 @@ friend class Scheduler; }; -class CC_EXPORT Scheduler : public BeginFrameObserverMixIn, - public base::PowerObserver { +class CC_EXPORT Scheduler : public BeginFrameObserverMixIn { public: static scoped_ptr<Scheduler> Create( SchedulerClient* client, const SchedulerSettings& scheduler_settings, int layer_tree_host_id, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - base::PowerMonitor* power_monitor, scoped_ptr<BeginFrameSource> external_begin_frame_source) { SchedulerFrameSourcesConstructor frame_sources_constructor; return make_scoped_ptr(new Scheduler(client, scheduler_settings, layer_tree_host_id, task_runner, - power_monitor, external_begin_frame_source.Pass(), &frame_sources_constructor)); } @@ -100,9 +95,6 @@ // BeginFrameObserverMixin bool OnBeginFrameMixInDelegate(const BeginFrameArgs& args) override; - // base::PowerObserver method. - void OnPowerStateChange(bool on_battery_power) override; - const SchedulerSettings& settings() const { return settings_; } void CommitVSyncParameters(base::TimeTicks timebase, @@ -179,7 +171,6 @@ const SchedulerSettings& scheduler_settings, int layer_tree_host_id, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - base::PowerMonitor* power_monitor, scoped_ptr<BeginFrameSource> external_begin_frame_source, SchedulerFrameSourcesConstructor* frame_sources_constructor); @@ -205,8 +196,6 @@ int layer_tree_host_id_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - base::PowerMonitor* power_monitor_; - base::TimeDelta estimated_parent_draw_time_; std::deque<BeginFrameArgs> begin_retro_frame_args_; @@ -243,8 +232,6 @@ void OnBeginImplFrameDeadline(); void PollForAnticipatedDrawTriggers(); void PollToAdvanceCommitState(); - void SetupPowerMonitoring(); - void TeardownPowerMonitoring(); void UpdateActiveFrameSource(); base::TimeDelta EstimatedParentDrawTime() {
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc index 4e6509f..f2f6636 100644 --- a/cc/scheduler/scheduler_state_machine.cc +++ b/cc/scheduler/scheduler_state_machine.cc
@@ -47,7 +47,6 @@ skip_next_begin_main_frame_to_reduce_latency_(false), skip_begin_main_frame_to_reduce_latency_(false), continuous_painting_(false), - impl_latency_takes_priority_on_battery_(false), children_need_begin_frames_(false), defer_commits_(false) { } @@ -236,8 +235,6 @@ state->SetBoolean("skip_next_begin_main_frame_to_reduce_latency", skip_next_begin_main_frame_to_reduce_latency_); state->SetBoolean("continuous_painting", continuous_painting_); - state->SetBoolean("impl_latency_takes_priority_on_battery", - impl_latency_takes_priority_on_battery_); state->SetBoolean("children_need_begin_frames", children_need_begin_frames_); state->SetBoolean("defer_commits", defer_commits_); state->EndDictionary(); @@ -903,11 +900,6 @@ if (impl_latency_takes_priority_) return true; - // If we are on battery power and want to prioritize impl latency because - // we don't trust deadline tasks to execute at the right time. - if (impl_latency_takes_priority_on_battery_) - return true; - return false; }
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h index f77df28..a411022 100644 --- a/cc/scheduler/scheduler_state_machine.h +++ b/cc/scheduler/scheduler_state_machine.h
@@ -254,12 +254,6 @@ bool CouldSendBeginMainFrame() const; - void SetImplLatencyTakesPriorityOnBattery( - bool impl_latency_takes_priority_on_battery) { - impl_latency_takes_priority_on_battery_ = - impl_latency_takes_priority_on_battery; - } - void SetDeferCommits(bool defer_commits); // TODO(zmo): This is temporary for debugging crbug.com/393331. @@ -341,7 +335,6 @@ bool skip_next_begin_main_frame_to_reduce_latency_; bool skip_begin_main_frame_to_reduce_latency_; bool continuous_painting_; - bool impl_latency_takes_priority_on_battery_; bool children_need_begin_frames_; bool defer_commits_;
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index 50cc846c..9346536 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc
@@ -10,8 +10,6 @@ #include "base/logging.h" #include "base/memory/scoped_vector.h" #include "base/message_loop/message_loop.h" -#include "base/power_monitor/power_monitor.h" -#include "base/power_monitor/power_monitor_source.h" #include "base/run_loop.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" @@ -198,21 +196,6 @@ TestScheduler* scheduler_; }; -class FakePowerMonitorSource : public base::PowerMonitorSource { - public: - FakePowerMonitorSource() {} - ~FakePowerMonitorSource() override {} - void GeneratePowerStateEvent(bool on_battery_power) { - on_battery_power_impl_ = on_battery_power; - ProcessPowerEvent(POWER_STATE_EVENT); - base::MessageLoop::current()->RunUntilIdle(); - } - bool IsOnBatteryPowerImpl() override { return on_battery_power_impl_; } - - private: - bool on_battery_power_impl_; -}; - class FakeExternalBeginFrameSource : public BeginFrameSourceMixIn { public: explicit FakeExternalBeginFrameSource(FakeSchedulerClient* client) @@ -240,10 +223,7 @@ SchedulerTest() : now_src_(TestNowSource::Create()), task_runner_(new OrderedSimpleTaskRunner(now_src_, true)), - fake_external_begin_frame_source_(nullptr), - fake_power_monitor_source_(new FakePowerMonitorSource), - power_monitor_(make_scoped_ptr<base::PowerMonitorSource>( - fake_power_monitor_source_)) { + fake_external_begin_frame_source_(nullptr) { // A bunch of tests require Now() to be > BeginFrameArgs::DefaultInterval() now_src_->AdvanceNow(base::TimeDelta::FromMilliseconds(100)); // Fail if we need to run 100 tasks in a row. @@ -261,9 +241,9 @@ fake_external_begin_frame_source_ = fake_external_begin_frame_source.get(); } - scheduler_ = TestScheduler::Create( - now_src_, client_.get(), scheduler_settings_, 0, task_runner_, - &power_monitor_, fake_external_begin_frame_source.Pass()); + scheduler_ = TestScheduler::Create(now_src_, client_.get(), + scheduler_settings_, 0, task_runner_, + fake_external_begin_frame_source.Pass()); DCHECK(scheduler_); client_->set_scheduler(scheduler_.get()); return scheduler_.get(); @@ -386,11 +366,6 @@ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src())); } - base::PowerMonitor* PowerMonitor() { return &power_monitor_; } - FakePowerMonitorSource* PowerMonitorSource() { - return fake_power_monitor_source_; - } - FakeExternalBeginFrameSource* fake_external_begin_frame_source() const { return fake_external_begin_frame_source_; } @@ -412,8 +387,6 @@ scoped_refptr<TestNowSource> now_src_; scoped_refptr<OrderedSimpleTaskRunner> task_runner_; FakeExternalBeginFrameSource* fake_external_begin_frame_source_; - FakePowerMonitorSource* fake_power_monitor_source_; - base::PowerMonitor power_monitor_; SchedulerSettings scheduler_settings_; scoped_ptr<FakeSchedulerClient> client_; scoped_ptr<TestScheduler> scheduler_; @@ -2119,131 +2092,6 @@ EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 2); } -TEST_F(SchedulerTest, SchedulerPowerMonitoring) { - scheduler_settings_.disable_hi_res_timer_tasks_on_battery = true; - SetUpScheduler(true); - - base::TimeTicks before_deadline, after_deadline; - - scheduler_->SetNeedsCommit(); - scheduler_->SetNeedsRedraw(); - client_->Reset(); - - // On non-battery power - EXPECT_FALSE(PowerMonitor()->IsOnBatteryPower()); - - EXPECT_SCOPED(AdvanceFrame()); - client_->Reset(); - - before_deadline = now_src()->Now(); - EXPECT_TRUE( - task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true))); - after_deadline = now_src()->Now(); - - // We post a non-zero deadline task when not on battery - EXPECT_LT(before_deadline, after_deadline); - - // Switch to battery power - PowerMonitorSource()->GeneratePowerStateEvent(true); - EXPECT_TRUE(PowerMonitor()->IsOnBatteryPower()); - - EXPECT_SCOPED(AdvanceFrame()); - scheduler_->SetNeedsCommit(); - scheduler_->SetNeedsRedraw(); - client_->Reset(); - - before_deadline = now_src()->Now(); - EXPECT_TRUE( - task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true))); - after_deadline = now_src()->Now(); - - // We post a zero deadline task when on battery - EXPECT_EQ(before_deadline, after_deadline); - - // Switch to non-battery power - PowerMonitorSource()->GeneratePowerStateEvent(false); - EXPECT_FALSE(PowerMonitor()->IsOnBatteryPower()); - - EXPECT_SCOPED(AdvanceFrame()); - scheduler_->SetNeedsCommit(); - scheduler_->SetNeedsRedraw(); - client_->Reset(); - - // Same as before - before_deadline = now_src()->Now(); - EXPECT_TRUE( - task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true))); - after_deadline = now_src()->Now(); -} - -TEST_F(SchedulerTest, - SimulateWindowsLowResolutionTimerOnBattery_PrioritizeImplLatencyOff) { - scheduler_settings_.use_external_begin_frame_source = true; - SetUpScheduler(true); - - // Set needs commit so that the scheduler tries to wait for the main thread - scheduler_->SetNeedsCommit(); - // Set needs redraw so that the scheduler doesn't wait too long - scheduler_->SetNeedsRedraw(); - client_->Reset(); - - // Switch to battery power - PowerMonitorSource()->GeneratePowerStateEvent(true); - EXPECT_TRUE(PowerMonitor()->IsOnBatteryPower()); - - EXPECT_SCOPED(AdvanceFrame()); - scheduler_->SetNeedsCommit(); - scheduler_->SetNeedsRedraw(); - client_->Reset(); - - // Disable auto-advancing of now_src - task_runner().SetAutoAdvanceNowToPendingTasks(false); - - // Deadline task is pending - EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); - task_runner().RunPendingTasks(); - // Deadline task is still pending - EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); - - // Advance now by 15 ms - same as windows low res timer - now_src()->AdvanceNowMicroseconds(15000); - EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); - task_runner().RunPendingTasks(); - // Deadline task finally completes - EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); -} - -TEST_F(SchedulerTest, - SimulateWindowsLowResolutionTimerOnBattery_PrioritizeImplLatencyOn) { - scheduler_settings_.disable_hi_res_timer_tasks_on_battery = true; - scheduler_settings_.use_external_begin_frame_source = true; - SetUpScheduler(true); - - // Set needs commit so that the scheduler tries to wait for the main thread - scheduler_->SetNeedsCommit(); - // Set needs redraw so that the scheduler doesn't wait too long - scheduler_->SetNeedsRedraw(); - client_->Reset(); - - // Switch to battery power - PowerMonitorSource()->GeneratePowerStateEvent(true); - EXPECT_TRUE(PowerMonitor()->IsOnBatteryPower()); - - EXPECT_SCOPED(AdvanceFrame()); - scheduler_->SetNeedsCommit(); - scheduler_->SetNeedsRedraw(); - client_->Reset(); - - // Disable auto-advancing of now_src - task_runner().SetAutoAdvanceNowToPendingTasks(false); - - // Deadline task is pending - EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); - task_runner().RunPendingTasks(); - // Deadline task runs immediately - EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); -} - // Tests to ensure frame sources can be successfully changed while drawing. TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottled) { scheduler_settings_.use_external_begin_frame_source = true;
diff --git a/cc/test/data/checkers.png b/cc/test/data/checkers.png new file mode 100644 index 0000000..fdd2ee3b --- /dev/null +++ b/cc/test/data/checkers.png Binary files differ
diff --git a/cc/test/data/checkers_big.png b/cc/test/data/checkers_big.png new file mode 100644 index 0000000..48edf608 --- /dev/null +++ b/cc/test/data/checkers_big.png Binary files differ
diff --git a/cc/test/fake_content_layer_client.cc b/cc/test/fake_content_layer_client.cc index ab958e97..ffef555e 100644 --- a/cc/test/fake_content_layer_client.cc +++ b/cc/test/fake_content_layer_client.cc
@@ -71,8 +71,8 @@ const SkPaint& paint = it->second; canvas = skia::SharePtr(recorder.beginRecording(gfx::RectFToSkRect(draw_rect))); - canvas->drawRectCoords(0.f, 0.f, draw_rect.width(), draw_rect.height(), - paint); + canvas->drawRectCoords(draw_rect.x(), draw_rect.y(), draw_rect.width(), + draw_rect.height(), paint); picture = skia::AdoptRef(recorder.endRecording()); list->AppendItem(DrawingDisplayItem::Create(picture)); } @@ -81,7 +81,7 @@ it != draw_bitmaps_.end(); ++it) { canvas = skia::SharePtr( recorder.beginRecording(it->bitmap.width(), it->bitmap.height())); - canvas->drawBitmap(it->bitmap, 0.f, 0.f, &it->paint); + canvas->drawBitmap(it->bitmap, it->point.x(), it->point.y(), &it->paint); picture = skia::AdoptRef(recorder.endRecording()); list->AppendItem(DrawingDisplayItem::Create(picture)); }
diff --git a/cc/test/ordered_texture_map.cc b/cc/test/ordered_texture_map.cc index ee3e2f3b..649700c 100644 --- a/cc/test/ordered_texture_map.cc +++ b/cc/test/ordered_texture_map.cc
@@ -32,7 +32,10 @@ void OrderedTextureMap::Remove(GLuint id) { TextureMap::iterator map_it = textures_.find(id); - DCHECK(map_it != textures_.end()); + // for some test we generate dummy tex id, which are not registered, + // nothing to remove in that case. + if (map_it == textures_.end()) + return; textures_.erase(map_it); TextureList::iterator list_it =
diff --git a/cc/test/render_pass_test_common.cc b/cc/test/render_pass_test_common.cc index 0e3fe22e..3f7f7c0 100644 --- a/cc/test/render_pass_test_common.cc +++ b/cc/test/render_pass_test_common.cc
@@ -94,7 +94,7 @@ CheckerboardDrawQuad* checkerboard_quad = this->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); - checkerboard_quad->SetNew(shared_state, rect, visible_rect, SK_ColorRED); + checkerboard_quad->SetNew(shared_state, rect, visible_rect, SK_ColorRED, 1.f); DebugBorderDrawQuad* debug_border_quad = this->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
diff --git a/cc/test/scheduler_test_common.cc b/cc/test/scheduler_test_common.cc index 94bcf5f9..f25d6eb 100644 --- a/cc/test/scheduler_test_common.cc +++ b/cc/test/scheduler_test_common.cc
@@ -131,14 +131,12 @@ const SchedulerSettings& scheduler_settings, int layer_tree_host_id, const scoped_refptr<OrderedSimpleTaskRunner>& test_task_runner, - base::PowerMonitor* power_monitor, TestSchedulerFrameSourcesConstructor* frame_sources_constructor, scoped_ptr<BeginFrameSource> external_begin_frame_source) : Scheduler(client, scheduler_settings, layer_tree_host_id, test_task_runner, - power_monitor, external_begin_frame_source.Pass(), frame_sources_constructor), now_src_(now_src) {
diff --git a/cc/test/scheduler_test_common.h b/cc/test/scheduler_test_common.h index 00cdd7564..763ccc8 100644 --- a/cc/test/scheduler_test_common.h +++ b/cc/test/scheduler_test_common.h
@@ -164,7 +164,6 @@ const SchedulerSettings& scheduler_settings, int layer_tree_host_id, const scoped_refptr<OrderedSimpleTaskRunner>& task_runner, - base::PowerMonitor* power_monitor, scoped_ptr<BeginFrameSource> external_begin_frame_source) { TestSchedulerFrameSourcesConstructor frame_sources_constructor( task_runner.get(), now_src.get()); @@ -174,7 +173,6 @@ scheduler_settings, layer_tree_host_id, task_runner, - power_monitor, &frame_sources_constructor, external_begin_frame_source.Pass())); } @@ -209,7 +207,6 @@ const SchedulerSettings& scheduler_settings, int layer_tree_host_id, const scoped_refptr<OrderedSimpleTaskRunner>& test_task_runner, - base::PowerMonitor* power_monitor, TestSchedulerFrameSourcesConstructor* frame_sources_constructor, scoped_ptr<BeginFrameSource> external_begin_frame_source);
diff --git a/cc/test/test_web_graphics_context_3d.cc b/cc/test/test_web_graphics_context_3d.cc index 28b16c84..9f20bb80 100644 --- a/cc/test/test_web_graphics_context_3d.cc +++ b/cc/test/test_web_graphics_context_3d.cc
@@ -356,6 +356,13 @@ return namespace_->textures.TextureForId(BoundTextureId(target)); } +scoped_refptr<TestTexture> TestWebGraphicsContext3D::UnboundTexture( + GLuint texture) { + // The caller is expected to lock the namespace for texture access. + namespace_->lock.AssertAcquired(); + return namespace_->textures.TextureForId(texture); +} + void TestWebGraphicsContext3D::CheckTextureIsBound(GLenum target) { DCHECK(BoundTextureId(target)); } @@ -466,7 +473,9 @@ GLuint TestWebGraphicsContext3D::createAndConsumeTextureCHROMIUM( GLenum target, const GLbyte* mailbox) { - return createTexture(); + GLuint texture_id = createTexture(); + consumeTextureCHROMIUM(target, mailbox); + return texture_id; } void TestWebGraphicsContext3D::loseContextCHROMIUM(GLenum current,
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h index c2dee45..d8219f5 100644 --- a/cc/test/test_web_graphics_context_3d.h +++ b/cc/test/test_web_graphics_context_3d.h
@@ -441,6 +441,7 @@ void CreateNamespace(); GLuint BoundTextureId(GLenum target); scoped_refptr<TestTexture> BoundTexture(GLenum target); + scoped_refptr<TestTexture> UnboundTexture(GLuint texture); void CheckTextureIsBound(GLenum target); unsigned context_id_;
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index abc63fc..92e9c259 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -211,10 +211,6 @@ proxy_->SetLayerTreeHostClientReady(); } -static void LayerTreeHostOnOutputSurfaceCreatedCallback(Layer* layer) { - layer->OnOutputSurfaceCreated(); -} - void LayerTreeHost::DeleteContentsTexturesOnImplThread( ResourceProvider* resource_provider) { DCHECK(proxy_->IsImplThread()); @@ -427,7 +423,7 @@ if (root_layer()) { LayerTreeHostCommon::CallFunctionForSubtree( - root_layer(), base::Bind(&LayerTreeHostOnOutputSurfaceCreatedCallback)); + root_layer(), [](Layer* layer) { layer->OnOutputSurfaceCreated(); }); } client_->DidInitializeOutputSurface(); @@ -873,17 +869,12 @@ SetNeedsCommit(); } -static void LayerTreeHostReduceMemoryCallback(Layer* layer) { - layer->ReduceMemoryUsage(); -} - void LayerTreeHost::ReduceMemoryUsage() { if (!root_layer()) return; LayerTreeHostCommon::CallFunctionForSubtree( - root_layer(), - base::Bind(&LayerTreeHostReduceMemoryCallback)); + root_layer(), [](Layer* layer) { layer->ReduceMemoryUsage(); }); } void LayerTreeHost::SetPrioritiesForSurfaces(size_t surface_memory_bytes) {
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc index e80e3a0..e468c07 100644 --- a/cc/trees/layer_tree_host_common.cc +++ b/cc/trees/layer_tree_host_common.cc
@@ -2495,12 +2495,6 @@ std::abs(r1.height() - r2.height()) <= tolerance; } -static bool ApproximatelyEqual(const gfx::Transform& a, - const gfx::Transform& b) { - static const float tolerance = 0.01f; - return gfx::MatrixDistance(a, b) < tolerance; -} - void LayerTreeHostCommon::CalculateDrawProperties( CalcDrawPropsMainInputs* inputs) { UpdateRenderSurfaces(inputs->root_layer, @@ -2562,11 +2556,6 @@ current_layer->visible_rect_from_property_trees()); CHECK(visible_rects_match); - const bool draw_transforms_match = ApproximatelyEqual( - current_layer->draw_transform(), - current_layer->draw_transform_from_property_trees(transform_tree)); - CHECK(draw_transforms_match); - const bool draw_opacities_match = current_layer->draw_opacity() == current_layer->DrawOpacityFromPropertyTrees(opacity_tree);
diff --git a/cc/trees/layer_tree_host_common.h b/cc/trees/layer_tree_host_common.h index 86666176..6c03511 100644 --- a/cc/trees/layer_tree_host_common.h +++ b/cc/trees/layer_tree_host_common.h
@@ -125,10 +125,9 @@ static bool RenderSurfaceContributesToTarget(LayerType*, int target_surface_layer_id); - template <typename LayerType> - static void CallFunctionForSubtree( - LayerType* root_layer, - const base::Callback<void(LayerType* layer)>& function); + template <typename LayerType, typename Function> + static void CallFunctionForSubtree(LayerType* layer, + const Function& function); // Returns a layer with the given id if one exists in the subtree starting // from the given root layer (including mask and replica layers). @@ -205,22 +204,21 @@ return NULL; } -template <typename LayerType> -void LayerTreeHostCommon::CallFunctionForSubtree( - LayerType* root_layer, - const base::Callback<void(LayerType* layer)>& function) { - function.Run(root_layer); +template <typename LayerType, typename Function> +void LayerTreeHostCommon::CallFunctionForSubtree(LayerType* layer, + const Function& function) { + function(layer); - if (LayerType* mask_layer = root_layer->mask_layer()) - function.Run(mask_layer); - if (LayerType* replica_layer = root_layer->replica_layer()) { - function.Run(replica_layer); + if (LayerType* mask_layer = layer->mask_layer()) + function(mask_layer); + if (LayerType* replica_layer = layer->replica_layer()) { + function(replica_layer); if (LayerType* mask_layer = replica_layer->mask_layer()) - function.Run(mask_layer); + function(mask_layer); } - for (size_t i = 0; i < root_layer->children().size(); ++i) { - CallFunctionForSubtree(get_layer_as_raw_ptr(root_layer->children(), i), + for (size_t i = 0; i < layer->children().size(); ++i) { + CallFunctionForSubtree(get_layer_as_raw_ptr(layer->children(), i), function); } }
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index eddbc60..c03f7f79 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -1453,10 +1453,6 @@ return metadata; } -static void LayerTreeHostImplDidBeginTracingCallback(LayerImpl* layer) { - layer->DidBeginTracing(); -} - void LayerTreeHostImpl::DrawLayers(FrameData* frame, base::TimeTicks frame_begin_time) { TRACE_EVENT0("cc", "LayerTreeHostImpl::DrawLayers"); @@ -1506,11 +1502,11 @@ if (pending_tree_) { LayerTreeHostCommon::CallFunctionForSubtree( pending_tree_->root_layer(), - base::Bind(&LayerTreeHostImplDidBeginTracingCallback)); + [](LayerImpl* layer) { layer->DidBeginTracing(); }); } LayerTreeHostCommon::CallFunctionForSubtree( active_tree_->root_layer(), - base::Bind(&LayerTreeHostImplDidBeginTracingCallback)); + [](LayerImpl* layer) { layer->DidBeginTracing(); }); } {
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index 48be5b8..c52132e8 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1440,7 +1440,6 @@ // Verify that used texture is correct. EXPECT_TRUE(context->UsedTexture(context->TextureAt(0))); EXPECT_TRUE(context->UsedTexture(context->TextureAt(1))); - context->ResetUsedTextures(); break; case 1: // Number of textures should be doubled as the first context layer @@ -1458,7 +1457,6 @@ // New textures should have been used. EXPECT_TRUE(context->UsedTexture(context->TextureAt(2))); EXPECT_TRUE(context->UsedTexture(context->TextureAt(3))); - context->ResetUsedTextures(); break; case 2: EndTest(); @@ -2658,8 +2656,8 @@ GLenum type, GLintptr offset)); MOCK_METHOD1(deleteTexture, void(GLenum texture)); - MOCK_METHOD2(produceTextureCHROMIUM, - void(GLenum target, const GLbyte* mailbox)); + MOCK_METHOD3(produceTextureDirectCHROMIUM, + void(GLuint texture, GLenum target, const GLbyte* mailbox)); }; class LayerTreeHostTestIOSurfaceDrawing : public LayerTreeHostTest { @@ -2749,12 +2747,10 @@ resource_provider->TargetForTesting( io_surface_draw_quad->io_surface_resource_id)); - EXPECT_CALL(*mock_context_, bindTexture(GL_TEXTURE_RECTANGLE_ARB, 1)) - .Times(1); if (delegating_renderer()) { // The io surface layer's resource should be sent to the parent. - EXPECT_CALL(*mock_context_, - produceTextureCHROMIUM(GL_TEXTURE_RECTANGLE_ARB, _)).Times(1); + EXPECT_CALL(*mock_context_, produceTextureDirectCHROMIUM( + _, GL_TEXTURE_RECTANGLE_ARB, _)).Times(1); } else { // The io surface layer's texture is drawn. EXPECT_CALL(*mock_context_, activeTexture(GL_TEXTURE0)).Times(AtLeast(1));
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index 62e4cd36..5114fdc 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -121,13 +121,18 @@ } void LayerTreeImpl::ReleaseResources() { - if (root_layer_) - ProcessLayersRecursive(root_layer_.get(), &LayerImpl::ReleaseResources); + if (root_layer_) { + LayerTreeHostCommon::CallFunctionForSubtree( + root_layer_.get(), [](LayerImpl* layer) { layer->ReleaseResources(); }); + } } void LayerTreeImpl::RecreateResources() { - if (root_layer_) - ProcessLayersRecursive(root_layer_.get(), &LayerImpl::RecreateResources); + if (root_layer_) { + LayerTreeHostCommon::CallFunctionForSubtree( + root_layer_.get(), + [](LayerImpl* layer) { layer->RecreateResources(); }); + } } void LayerTreeImpl::SetRootLayer(scoped_ptr<LayerImpl> layer) { @@ -475,10 +480,6 @@ gfx::Rect(layer->content_bounds())); } -static void ApplySentScrollDeltasFromAbortedCommitTo(LayerImpl* layer) { - layer->ApplySentScrollDeltasFromAbortedCommit(); -} - void LayerTreeImpl::ApplySentScrollAndScaleDeltasFromAbortedCommit() { DCHECK(IsActiveTree()); @@ -490,7 +491,9 @@ return; LayerTreeHostCommon::CallFunctionForSubtree( - root_layer(), base::Bind(&ApplySentScrollDeltasFromAbortedCommitTo)); + root_layer(), [](LayerImpl* layer) { + layer->ApplySentScrollDeltasFromAbortedCommit(); + }); } void LayerTreeImpl::SetViewportLayersFromIds( @@ -748,17 +751,6 @@ currently_scrolling_layer_ ? currently_scrolling_layer_->id() : 0)); } -static void DidBecomeActiveRecursive(LayerImpl* layer) { - layer->DidBecomeActive(); - if (layer->mask_layer()) - layer->mask_layer()->DidBecomeActive(); - if (layer->replica_layer() && layer->replica_layer()->mask_layer()) - layer->replica_layer()->mask_layer()->DidBecomeActive(); - - for (size_t i = 0; i < layer->children().size(); ++i) - DidBecomeActiveRecursive(layer->children()[i]); -} - void LayerTreeImpl::DidBecomeActive() { if (next_activation_forces_redraw_) { layer_tree_host_impl_->SetFullRootLayerDamage(); @@ -774,8 +766,10 @@ // if we were in a good state. layer_tree_host_impl_->ResetRequiresHighResToDraw(); - if (root_layer()) - DidBecomeActiveRecursive(root_layer()); + if (root_layer()) { + LayerTreeHostCommon::CallFunctionForSubtree( + root_layer(), [](LayerImpl* layer) { layer->DidBecomeActive(); }); + } devtools_instrumentation::DidActivateLayerTree(layer_tree_host_impl_->id(), source_frame_number_); @@ -1267,18 +1261,6 @@ return layers_with_copy_output_request_; } -void LayerTreeImpl::ProcessLayersRecursive(LayerImpl* current, - void (LayerImpl::*function)()) { - DCHECK(current); - (current->*function)(); - if (current->mask_layer()) - ProcessLayersRecursive(current->mask_layer(), function); - if (current->replica_layer()) - ProcessLayersRecursive(current->replica_layer(), function); - for (size_t i = 0; i < current->children().size(); ++i) - ProcessLayersRecursive(current->children()[i], function); -} - template <typename LayerType> static inline bool LayerClipsSubtree(LayerType* layer) { return layer->masks_to_bounds() || layer->mask_layer();
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h index f7b6ee41..3105e6f4 100644 --- a/cc/trees/layer_tree_impl.h +++ b/cc/trees/layer_tree_impl.h
@@ -335,8 +335,6 @@ scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor, scoped_refptr<SyncedTopControls> top_controls_shown_ratio, scoped_refptr<SyncedElasticOverscroll> elastic_overscroll); - void ProcessLayersRecursive(LayerImpl* current, - void (LayerImpl::*function)()); float ClampPageScaleFactorToLimits(float page_scale_factor) const; void PushPageScaleFactorAndLimits(const float* page_scale_factor, float min_page_scale_factor,
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index e45b182..401a4b8 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc
@@ -104,7 +104,6 @@ scheduler_settings, layer_tree_host_->id(), MainThreadTaskRunner(), - base::PowerMonitor::Get(), external_begin_frame_source_.Pass()); scheduler_on_impl_thread_->SetCanStart(); scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc index 4efb401..8c766f2 100644 --- a/cc/trees/thread_proxy.cc +++ b/cc/trees/thread_proxy.cc
@@ -1171,7 +1171,6 @@ scheduler_settings, impl().layer_tree_host_id, ImplThreadTaskRunner(), - base::PowerMonitor::Get(), impl().external_begin_frame_source.Pass()); impl().scheduler->SetVisible(impl().layer_tree_host_impl->visible()); impl_thread_weak_ptr_ = impl().weak_factory.GetWeakPtr();
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index 8b0e6a3..648524b 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -12,16 +12,7 @@ import("//build/config/android/rules.gni") } -if (is_win && !link_chrome_on_windows) { - # When linking is disabled on Windows, create a dummy Chrome target to - # make targets work that depend on Chrome. - group("chrome") { - } - group("main_dll") { - } -} - -if (!is_android && (!is_win || link_chrome_on_windows)) { +if (!is_android) { # TODO(GYP) for Windows need to the the reorder-imports step which probably # means adding another target and renaming this to chrome_initial like in GYP. executable("chrome") { @@ -153,89 +144,87 @@ } } # !is_android -if (!is_win || link_chrome_on_windows) { - shared_library("main_dll") { - configs += [ "//build/config/compiler:wexit_time_destructors" ] +shared_library("main_dll") { + configs += [ "//build/config/compiler:wexit_time_destructors" ] - deps = [ - ":browser_dependencies", - "//base/allocator", + deps = [ + ":browser_dependencies", + "//base/allocator", + ] + if (is_win) { + output_name = "chrome" + + sources = [ + "//base/win/dllmain.cc", + "app/chrome_command_ids.h", + "app/chrome_dll.rc", + "app/chrome_dll_resource.h", + "app/chrome_main.cc", + "app/chrome_main_delegate.cc", + "app/chrome_main_delegate.h", + "app/close_handle_hook_win.cc", + "app/close_handle_hook_win.h", + "app/delay_load_hook_win.cc", + "app/delay_load_hook_win.h", ] - if (is_win) { - output_name = "chrome" - sources = [ - "//base/win/dllmain.cc", - "app/chrome_command_ids.h", - "app/chrome_dll.rc", - "app/chrome_dll_resource.h", - "app/chrome_main.cc", - "app/chrome_main_delegate.cc", - "app/chrome_main_delegate.h", - "app/close_handle_hook_win.cc", - "app/close_handle_hook_win.h", - "app/delay_load_hook_win.cc", - "app/delay_load_hook_win.h", - ] - - deps += [ - # On Windows, link the dependencies (libraries) that make up actual - # Chromium functionality into this .dll. - ":chrome_version_resources", - "//chrome/app/theme:chrome_unscaled_resources", - "//chrome_elf", - "//content/app/resources", - "//crypto", - "//net:net_resources", - "//third_party/wtl", - "//ui/views", - ] - if (enable_configuration_policy) { - deps += [ "//components/policy" ] - } - if (current_cpu == "x86") { - # Add a dependency to custom import library for user32 delay imports only - # in x86 builds. - #deps += [ 'chrome_user32_delay_imports' ] TODO(GYP) - } - - # TODO(GYP) incremental linking flags in debug builds - #'LinkIncremental': '<(msvs_large_module_debug_link_mode)', - - # TODO(GYP) Lots of VCLinkerTool stuff on Windows. - - # TODO(GYP) chrome_pgo_phase on Windows. + deps += [ + # On Windows, link the dependencies (libraries) that make up actual + # Chromium functionality into this .dll. + ":chrome_version_resources", + "//chrome/app/theme:chrome_unscaled_resources", + "//chrome_elf", + "//content/app/resources", + "//crypto", + "//net:net_resources", + "//third_party/wtl", + "//ui/views", + ] + if (enable_configuration_policy) { + deps += [ "//components/policy" ] + } + if (current_cpu == "x86") { + # Add a dependency to custom import library for user32 delay imports only + # in x86 builds. + #deps += [ 'chrome_user32_delay_imports' ] TODO(GYP) } - if (use_aura) { - deps += [ "//ui/compositor" ] - } + # TODO(GYP) incremental linking flags in debug builds + #'LinkIncremental': '<(msvs_large_module_debug_link_mode)', - #TODO(GYP) add chrome_multiple_dll support - if (false) { #chrome_multiple_dll) { - defines = [ "CHROME_MULTIPLE_DLL_BROWSER" ] - deps += [ "//content/public/app:browser" ] - } else { - deps += [ - ":child_dependencies", - "//content/public/app:both", - ] - } + # TODO(GYP) Lots of VCLinkerTool stuff on Windows. - if (cld_version == 0 || cld_version == 2) { - deps += [ "//third_party/cld_2" ] - } + # TODO(GYP) chrome_pgo_phase on Windows. + } - if (is_mac) { - #['OS=="mac" and component!="shared_library"', { TODO(GYP) - # 'includes': [ 'chrome_dll_bundle.gypi' ], - #}], - # TODO(GYP) Lots of other stuff in the OS=="mac" block. - } + if (use_aura) { + deps += [ "//ui/compositor" ] + } - if (enable_plugins) { - deps += [ "//pdf" ] - } + #TODO(GYP) add chrome_multiple_dll support + if (false) { #chrome_multiple_dll) { + defines = [ "CHROME_MULTIPLE_DLL_BROWSER" ] + deps += [ "//content/public/app:browser" ] + } else { + deps += [ + ":child_dependencies", + "//content/public/app:both", + ] + } + + if (cld_version == 0 || cld_version == 2) { + deps += [ "//third_party/cld_2" ] + } + + if (is_mac) { + #['OS=="mac" and component!="shared_library"', { TODO(GYP) + # 'includes': [ 'chrome_dll_bundle.gypi' ], + #}], + # TODO(GYP) Lots of other stuff in the OS=="mac" block. + } + + if (enable_plugins) { + deps += [ "//pdf" ] } } @@ -498,7 +487,9 @@ } if (is_chromeos) { sources += [ "$root_gen_dir/ui/file_manager/file_manager_resources.pak" ] + sources += [ "$root_gen_dir/ui/oobe/oobe_resources.pak" ] deps += [ "//ui/file_manager:resources" ] + deps += [ "//ui/oobe:resources" ] } if (enable_extensions) { sources += [ @@ -682,6 +673,7 @@ "app/android/chrome_android_initializer.cc", "app/android/chrome_android_initializer.h", "app/android/chrome_jni_onload.cc", + "app/android/chrome_jni_onload.h", "app/android/chrome_main_delegate_android.cc", "app/android/chrome_main_delegate_android.h", "app/chrome_main_delegate.cc", @@ -703,7 +695,7 @@ "//chrome/renderer", "//chrome/utility", "//components/enhanced_bookmarks", - "//content/public/app:browser", + "//content/public/app:both", ] } }
diff --git a/chrome/VERSION b/chrome/VERSION index c42c9fd..bb3eb27 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=43 MINOR=0 -BUILD=2320 +BUILD=2324 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 9f262e33..59a6c5b 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -164,7 +164,7 @@ "//chrome:chrome_android_core", "//base", "//base/allocator", - "//content/public/app:browser", + "//content/public/app:both", "//skia", ] # TODO(GYP): @@ -179,6 +179,7 @@ sources = [ "shell/chrome_main_delegate_chrome_shell_android.cc", "shell/chrome_main_delegate_chrome_shell_android.h", + "shell/chrome_shell_entry_point.cc", ] deps = [ ":chrome_shell_base", @@ -197,6 +198,7 @@ shared_library("chrome_sync_shell") { testonly = true sources = [ + #"shell/chrome_shell_entry_point.cc", #"sync_shell/chrome_main_delegate_chrome_sync_shell_android.cc", #"sync_shell/chrome_main_delegate_chrome_sync_shell_android.h", ]
diff --git a/chrome/android/java/res/drawable-hdpi/infobar_downloading.png b/chrome/android/java/res/drawable-hdpi/infobar_downloading.png new file mode 100644 index 0000000..3e4dd84 --- /dev/null +++ b/chrome/android/java/res/drawable-hdpi/infobar_downloading.png Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/infobar_downloading.png b/chrome/android/java/res/drawable-mdpi/infobar_downloading.png new file mode 100644 index 0000000..1c802f2 --- /dev/null +++ b/chrome/android/java/res/drawable-mdpi/infobar_downloading.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/infobar_downloading.png b/chrome/android/java/res/drawable-xhdpi/infobar_downloading.png new file mode 100644 index 0000000..aae485d --- /dev/null +++ b/chrome/android/java/res/drawable-xhdpi/infobar_downloading.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/infobar_downloading.png b/chrome/android/java/res/drawable-xxhdpi/infobar_downloading.png new file mode 100644 index 0000000..6079e59 --- /dev/null +++ b/chrome/android/java/res/drawable-xxhdpi/infobar_downloading.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/infobar_downloading.png b/chrome/android/java/res/drawable-xxxhdpi/infobar_downloading.png new file mode 100644 index 0000000..3eda0a47e --- /dev/null +++ b/chrome/android/java/res/drawable-xxxhdpi/infobar_downloading.png Binary files differ
diff --git a/chrome/android/java/res/layout/autofill_card_unmask_prompt.xml b/chrome/android/java/res/layout/autofill_card_unmask_prompt.xml index 522ef3f..14429fd 100644 --- a/chrome/android/java/res/layout/autofill_card_unmask_prompt.xml +++ b/chrome/android/java/res/layout/autofill_card_unmask_prompt.xml
@@ -16,6 +16,21 @@ android:orientation="vertical"> <TextView + android:id="@+id/no_retry_error_message" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="16sp" + android:layout_marginTop="10dp" + android:paddingStart="24dp" + android:paddingEnd="10dp" + android:paddingTop="10dp" + android:paddingBottom="10dp" + android:gravity="start" + android:textColor="@color/input_underline_error_color" + android:background="#e0e0e0" + android:visibility="gone" /> + + <TextView android:id="@+id/instructions" android:layout_width="match_parent" android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/layout/fre_choose_account.xml b/chrome/android/java/res/layout/fre_choose_account.xml index b5bcf65..82468b5c 100644 --- a/chrome/android/java/res/layout/fre_choose_account.xml +++ b/chrome/android/java/res/layout/fre_choose_account.xml
@@ -93,6 +93,7 @@ android:layout_gravity="bottom" android:orientation="horizontal" > + <!--suppress ButtonStyle --> <Button android:id="@+id/negative_button" android:layout_width="0dp" @@ -107,6 +108,7 @@ android:textColor="@color/light_normal_color" android:textSize="@dimen/fre_button_text_size" /> + <!--suppress ButtonStyle --> <Button android:id="@+id/positive_button" android:layout_width="0dp"
diff --git a/chrome/android/java/res/layout/homepage_preferences.xml b/chrome/android/java/res/layout/homepage_preferences.xml index b5c04a8..325173bc 100644 --- a/chrome/android/java/res/layout/homepage_preferences.xml +++ b/chrome/android/java/res/layout/homepage_preferences.xml
@@ -20,7 +20,10 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="horizontal" - android:padding="16dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:paddingTop="16dp" + android:paddingBottom="16dp" style="@style/PreferenceLayout" > <TextView @@ -42,6 +45,7 @@ <ImageView android:layout_width="match_parent" android:layout_height="wrap_content" + android:contentDescription="@null" android:src="?android:attr/listDivider" android:scaleType="fitXY" />
diff --git a/chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java b/chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java index e1639c15..85c1213 100644 --- a/chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java +++ b/chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java
@@ -109,6 +109,12 @@ /** Enable begin frame scheduling. */ public static final String ENABLE_BEGIN_FRAME_SCHEDULING = "enable-begin-frame-scheduling"; + /** + * Enable enhanced bookmarks feature. + * Native switch - switches::kEnhancedBookmarksExperiment + */ + public static final String ENABLE_ENHANCED_BOOKMARKS = "enhanced-bookmarks-experiment"; + /** Enable the DOM Distiller. */ public static final String ENABLE_DOM_DISTILLER = "enable-dom-distiller";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BookmarkUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/BookmarkUtils.java index e9b474b..9eaf0bb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/BookmarkUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/BookmarkUtils.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser; +import android.annotation.TargetApi; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; @@ -151,6 +152,7 @@ return bitmap; } + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) private static Bitmap getBitmapFromResourceId(Context context, int id, int density) { Drawable drawable = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BookmarksBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/BookmarksBridge.java index 9314059..07ebf13b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/BookmarksBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/BookmarksBridge.java
@@ -544,8 +544,13 @@ nativeEndGroupingUndos(mNativeBookmarksBridge); } + public static boolean isEditBookmarksEnabled(Profile profile) { + return nativeIsEditBookmarksEnabled(profile); + } + + // TODO(ianwen): Remove this method after rolling. public static boolean isEditBookmarksEnabled() { - return nativeIsEditBookmarksEnabled(); + return true; } public static boolean isEnhancedBookmarksEnabled(Profile profile) { @@ -737,7 +742,7 @@ private native long nativeInit(Profile profile); private native boolean nativeIsDoingExtensiveChanges(long nativeBookmarksBridge); private native void nativeDestroy(long nativeBookmarksBridge); - private static native boolean nativeIsEditBookmarksEnabled(); + private static native boolean nativeIsEditBookmarksEnabled(Profile profile); /** * Simple object representing the bookmark item.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java index 316852a..a162c9e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java
@@ -71,4 +71,5 @@ protected static native boolean nativeIsCapturingAudio(WebContents webContents); protected static native boolean nativeIsCapturingVideo(WebContents webContents); + protected static native boolean nativeHasAudibleAudio(WebContents webContents); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/LollipopTtsPlatformImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/LollipopTtsPlatformImpl.java index c011a6a..423456f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/LollipopTtsPlatformImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/LollipopTtsPlatformImpl.java
@@ -4,7 +4,9 @@ package org.chromium.chrome.browser; +import android.annotation.TargetApi; import android.content.Context; +import android.os.Build; import android.os.Bundle; import android.speech.tts.TextToSpeech; import android.speech.tts.UtteranceProgressListener; @@ -12,6 +14,7 @@ /** * Subclass of TtsPlatformImpl for Lollipop to make use of newer APIs. */ +@TargetApi(Build.VERSION_CODES.LOLLIPOP) class LollipopTtsPlatformImpl extends TtsPlatformImpl { protected LollipopTtsPlatformImpl(long nativeTtsPlatformImplAndroid, Context context) { super(nativeTtsPlatformImplAndroid, context);
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 2c631663..fbe2134 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
@@ -36,6 +36,7 @@ import org.chromium.chrome.browser.dom_distiller.DomDistillerFeedbackReporter; import org.chromium.chrome.browser.fullscreen.FullscreenManager; import org.chromium.chrome.browser.infobar.InfoBarContainer; +import org.chromium.chrome.browser.metrics.UmaUtils; import org.chromium.chrome.browser.printing.TabPrinter; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.SadTabViewFactory; @@ -48,9 +49,10 @@ import org.chromium.content.browser.ContentView; import org.chromium.content.browser.ContentViewClient; import org.chromium.content.browser.ContentViewCore; -import org.chromium.content.browser.WebContentsObserver; +import org.chromium.content_public.browser.InvalidateTypes; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.content_public.common.Referrer; import org.chromium.content_public.common.TopControlsState; import org.chromium.printing.PrintManagerDelegateImpl; @@ -164,7 +166,6 @@ // Content layer Observers and Delegates private ContentViewClient mContentViewClient; private WebContentsObserver mWebContentsObserver; - private VoiceSearchTabHelper mVoiceSearchTabHelper; private TabChromeWebContentsDelegateAndroid mWebContentsDelegate; private DomDistillerFeedbackReporter mDomDistillerFeedbackReporter; @@ -387,10 +388,10 @@ @Override public void navigationStateChanged(int flags) { - if ((flags & INVALIDATE_TYPE_TITLE) != 0) { + if ((flags & InvalidateTypes.TITLE) != 0) { for (TabObserver observer : mObservers) observer.onTitleUpdated(Tab.this); } - if ((flags & INVALIDATE_TYPE_URL) != 0) { + if ((flags & InvalidateTypes.URL) != 0) { for (TabObserver observer : mObservers) observer.onUrlUpdated(Tab.this); } } @@ -1435,7 +1436,6 @@ mWebContentsDelegate = createWebContentsDelegate(); mWebContentsObserver = new TabWebContentsObserver(mContentViewCore.getWebContents()); - mVoiceSearchTabHelper = new VoiceSearchTabHelper(mContentViewCore.getWebContents()); if (mContentViewClient != null) mContentViewCore.setContentViewClient(mContentViewClient); @@ -1872,12 +1872,10 @@ mWebContentsDelegate = null; if (mWebContentsObserver != null) { - mWebContentsObserver.detachFromWebContents(); + mWebContentsObserver.destroy(); mWebContentsObserver = null; } - mVoiceSearchTabHelper = null; - assert mNativeTabAndroid != 0; nativeDestroyWebContents(mNativeTabAndroid, deleteNativeWebContents); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/UmaBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/UmaBridge.java deleted file mode 100644 index 48a7f9c..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/UmaBridge.java +++ /dev/null
@@ -1,107 +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. - -package org.chromium.chrome.browser; - -import org.chromium.chrome.browser.preferences.bandwidth.BandwidthReductionPreferences; -import org.chromium.chrome.browser.preferences.bandwidth.DataReductionPromoScreen; - -/** - * Static methods to record user actions. - * - * We have a different native method for each action as we want to use c++ code to - * extract user command keys from code and show them in the dashboard. - * See: chromium/src/content/browser/user_metrics.h for more details. - */ -public class UmaBridge { - - /** - * Record that the user opened the menu. - */ - public static void menuShow() { - nativeRecordMenuShow(); - } - - /** - * Record that the user opened the menu through software menu button. - * @param isByHwButton - * @param isDragging - */ - public static void usingMenu(boolean isByHwButton, boolean isDragging) { - nativeRecordUsingMenu(isByHwButton, isDragging); - } - - // Android beam - - public static void beamCallbackSuccess() { - nativeRecordBeamCallbackSuccess(); - } - - public static void beamInvalidAppState() { - nativeRecordBeamInvalidAppState(); - } - - // Data Saver - - /** - * Record that Data Saver was turned on. - */ - public static void dataReductionProxyTurnedOn() { - nativeRecordDataReductionProxyTurnedOn(); - } - - /** - * Record that Data Saver was turned off. - */ - public static void dataReductionProxyTurnedOff() { - nativeRecordDataReductionProxyTurnedOff(); - } - - /** - * Record that Data Saver was turned on immediately after the user viewed the promo screen. - */ - public static void dataReductionProxyTurnedOnFromPromo() { - nativeRecordDataReductionProxyTurnedOnFromPromo(); - } - - /** - * Record the DataReductionProxy.PromoAction histogram. - * @param action User action at the promo screen - */ - public static void dataReductionProxyPromoAction(int action) { - assert action >= 0 && action < DataReductionPromoScreen.ACTION_INDEX_BOUNDARY; - nativeRecordDataReductionProxyPromoAction( - action, DataReductionPromoScreen.ACTION_INDEX_BOUNDARY); - } - - /** - * Record that the Data Saver promo was displayed. - */ - public static void dataReductionProxyPromoDisplayed() { - nativeRecordDataReductionProxyPromoDisplayed(); - } - - /** - * Record the DataReductionProxy.SettingsConversion histogram. - * @param statusChange ON/OFF change at the data saver setting menu - */ - public static void dataReductionProxySettings(int statusChange) { - assert statusChange >= 0 - && statusChange < BandwidthReductionPreferences.DATA_REDUCTION_INDEX_BOUNDARY; - nativeRecordDataReductionProxySettings( - statusChange, BandwidthReductionPreferences.DATA_REDUCTION_INDEX_BOUNDARY); - } - - private static native void nativeRecordMenuShow(); - private static native void nativeRecordUsingMenu(boolean isByHwButton, boolean isDragging); - private static native void nativeRecordBeamInvalidAppState(); - private static native void nativeRecordBeamCallbackSuccess(); - private static native void nativeRecordDataReductionProxyTurnedOn(); - private static native void nativeRecordDataReductionProxyTurnedOff(); - private static native void nativeRecordDataReductionProxyTurnedOnFromPromo(); - private static native void nativeRecordDataReductionProxyPromoAction(int action, int boundary); - private static native void nativeRecordDataReductionProxyPromoDisplayed(); - private static native void nativeRecordDataReductionProxySettings(int statusChange, - int boundary); -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/UmaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/UmaUtils.java deleted file mode 100644 index ff2e9d5..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/UmaUtils.java +++ /dev/null
@@ -1,54 +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. - -package org.chromium.chrome.browser; - -import org.chromium.base.CalledByNative; - -/** - * Utilities to support startup metrics - Android version. - */ -public class UmaUtils { - - private static long sApplicationStartWallClockMs; - - private static boolean sRunningApplicationStart; - - /** - * Record the time at which the activity started. This should be called asap after - * the start of the activity's onCreate function. - */ - public static void recordMainEntryPointTime() { - // We can't simply pass this down through a JNI call, since the JNI for chrome - // isn't initialized until we start the native content browser component, and we - // then need the start time in the C++ side before we return to Java. As such we - // save it in a static that the C++ can fetch once it has initialized the JNI. - sApplicationStartWallClockMs = System.currentTimeMillis(); - } - - /** - * Whether the application is in the early stage since the browser process start. The - * "application start" ends right after the last histogram related to browser startup is - * recorded. Currently, the very first navigation commit in the lifetime of the process ends the - * "application start". - * Must only be called on the UI thread. - */ - public static boolean isRunningApplicationStart() { - return sRunningApplicationStart; - } - - /** - * Marks/unmarks the "application start" stage of the browser process lifetime. - * Must only be called on the UI thread. - */ - public static void setRunningApplicationStart(boolean isAppStart) { - sRunningApplicationStart = isAppStart; - } - - @CalledByNative - private static long getMainEntryPointTime() { - return sApplicationStartWallClockMs; - } - -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/VoiceSearchTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/VoiceSearchTabHelper.java deleted file mode 100644 index 4f524b0..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/VoiceSearchTabHelper.java +++ /dev/null
@@ -1,32 +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. - -package org.chromium.chrome.browser; - -import org.chromium.content.browser.WebContentsObserver; -import org.chromium.content_public.browser.WebContents; - -/** - * Tab helper to toggle media autoplay for voice URL searches. - */ -public class VoiceSearchTabHelper extends WebContentsObserver { - private final WebContents mWebContents; - - /** - * Create an instance of VoiceSearchTabHelper. - * - * @param webContents WebContents to update media autoplay status. - */ - public VoiceSearchTabHelper(WebContents webContents) { - super(webContents); - mWebContents = webContents; - } - - @Override - public void navigationEntryCommitted() { - nativeUpdateAutoplayStatus(mWebContents); - } - - private native void nativeUpdateAutoplayStatus(WebContents webContents); -}
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 9b19c53..6b6d07a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java
@@ -37,8 +37,8 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.toolbar.ToolbarModel; import org.chromium.chrome.browser.ui.toolbar.ToolbarModelSecurityLevel; -import org.chromium.content.browser.WebContentsObserver; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.ui.base.Clipboard; import org.chromium.ui.base.DeviceFormFactor; @@ -273,7 +273,7 @@ @Override public void onDismiss(DialogInterface dialog) { assert mNativeWebsiteSettingsPopup != 0; - webContentsObserver.detachFromWebContents(); + webContentsObserver.destroy(); nativeDestroy(mNativeWebsiteSettingsPopup); } });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java index 9b87940..bc1bcf1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.appmenu; import android.animation.Animator; +import android.animation.Animator.AnimatorListener; import android.animation.AnimatorSet; import android.content.Context; import android.content.res.Resources; @@ -27,6 +28,7 @@ import android.widget.PopupWindow; import android.widget.PopupWindow.OnDismissListener; +import org.chromium.base.AnimationFrameTimeHistogram; import org.chromium.base.SysUtils; import org.chromium.chrome.R; @@ -53,6 +55,9 @@ private AppMenuHandler mHandler; private int mCurrentScreenRotation = -1; private boolean mIsByHardwareButton; + private AnimatorSet mMenuItemEnterAnimator; + private AnimatorListener mAnimationHistogramRecorder = AnimationFrameTimeHistogram + .getAnimatorRecorder("WrenchMenu.OpeningAnimationFrameTimes"); /** * Creates and sets up the App Menu. @@ -140,6 +145,10 @@ if (mPopup.getAnchorView() instanceof ImageButton) { ((ImageButton) mPopup.getAnchorView()).setSelected(false); } + + if (mMenuItemEnterAnimator != null) mMenuItemEnterAnimator.cancel(); + + mHandler.appMenuDismissed(); mHandler.onMenuVisibilityChanged(false); } }); @@ -299,7 +308,6 @@ * Dismisses the app menu and cancels the drag-to-scroll if it is taking place. */ void dismiss() { - mHandler.appMenuDismissed(); if (isShowing()) { mPopup.dismiss(); } @@ -361,7 +369,7 @@ } private void runMenuItemEnterAnimations() { - AnimatorSet animation = new AnimatorSet(); + mMenuItemEnterAnimator = new AnimatorSet(); AnimatorSet.Builder builder = null; ViewGroup list = mPopup.getListView(); @@ -370,13 +378,14 @@ Object animatorObject = view.getTag(R.id.menu_item_enter_anim_id); if (animatorObject != null) { if (builder == null) { - builder = animation.play((Animator) animatorObject); + builder = mMenuItemEnterAnimator.play((Animator) animatorObject); } else { builder.with((Animator) animatorObject); } } } - animation.start(); + mMenuItemEnterAnimator.addListener(mAnimationHistogramRecorder); + mMenuItemEnterAnimator.start(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuButtonHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuButtonHelper.java index e6b58dcd..4471c971 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuButtonHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuButtonHelper.java
@@ -9,7 +9,7 @@ import android.view.View; import android.view.View.OnTouchListener; -import org.chromium.chrome.browser.UmaBridge; +import org.chromium.chrome.browser.metrics.UmaBridge; /** * A helper class for a menu button to decide when to show the app menu and forward touch
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuDragHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuDragHelper.java index 99d34c3..b41006cc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuDragHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuDragHelper.java
@@ -18,7 +18,7 @@ import android.widget.ListView; import org.chromium.chrome.R; -import org.chromium.chrome.browser.UmaBridge; +import org.chromium.chrome.browser.metrics.UmaBridge; import java.util.ArrayList;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java index 7229fc6..10e0ef55 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java
@@ -17,7 +17,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; -import org.chromium.chrome.browser.UmaBridge; +import org.chromium.chrome.browser.metrics.UmaBridge; import java.util.ArrayList;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java index a503d2b..0ad8f62 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java
@@ -92,10 +92,14 @@ /** * Indicate that verification failed, allow user to retry. + * @param errorMessage The error to display, or null to signal success. + * @param allowRetry If there was an error, indicates whether to allow another attempt. */ @CalledByNative - private void verificationFinished(boolean success) { - if (mCardUnmaskPrompt != null) mCardUnmaskPrompt.verificationFinished(success); + private void verificationFinished(String errorMessage, boolean allowRetry) { + if (mCardUnmaskPrompt != null) { + mCardUnmaskPrompt.verificationFinished(errorMessage, allowRetry); + } } private native void nativePromptDismissed(long nativeCardUnmaskPromptViewAndroid);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java index 9bd2b34..6cfd2ee 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
@@ -12,6 +12,7 @@ import android.graphics.PorterDuffColorFilter; import android.os.Build; import android.os.Handler; +import android.support.v4.view.ViewCompat; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater; @@ -38,13 +39,14 @@ private final boolean mShouldRequestExpirationDate; private final int mThisYear; + private final TextView mNoRetryErrorMessage; private final EditText mCardUnmaskInput; private final EditText mMonthInput; private final EditText mYearInput; private final View mExpirationContainer; private final TextView mErrorMessage; private final CheckBox mStoreLocallyCheckbox; - private final View mMainContents; + private final ViewGroup mMainContents; private final View mVerificationOverlay; private final ProgressBar mVerificationProgressBar; private final TextView mVerificationView; @@ -83,6 +85,7 @@ View v = inflater.inflate(R.layout.autofill_card_unmask_prompt, null); ((TextView) v.findViewById(R.id.instructions)).setText(instructions); + mNoRetryErrorMessage = (TextView) v.findViewById(R.id.no_retry_error_message); mCardUnmaskInput = (EditText) v.findViewById(R.id.card_unmask_input); mMonthInput = (EditText) v.findViewById(R.id.expiration_month); mYearInput = (EditText) v.findViewById(R.id.expiration_year); @@ -90,7 +93,7 @@ mErrorMessage = (TextView) v.findViewById(R.id.error_message); mStoreLocallyCheckbox = (CheckBox) v.findViewById(R.id.store_locally_checkbox); mStoreLocallyCheckbox.setChecked(defaultToStoringLocally); - mMainContents = v.findViewById(R.id.main_contents); + mMainContents = (ViewGroup) v.findViewById(R.id.main_contents); mVerificationOverlay = v.findViewById(R.id.verification_overlay); mVerificationProgressBar = (ProgressBar) v.findViewById(R.id.verification_progress_bar); mVerificationView = (TextView) v.findViewById(R.id.verification_message); @@ -101,8 +104,8 @@ .setView(v) .setNegativeButton(R.string.cancel, null) .setPositiveButton(R.string.card_unmask_confirm_button, null) - .setOnDismissListener(this) .create(); + mDialog.setOnDismissListener(this); mShouldRequestExpirationDate = shouldRequestExpirationDate; mThisYear = Calendar.getInstance().get(Calendar.YEAR); @@ -146,32 +149,35 @@ public void disableAndWaitForVerification() { setInputsEnabled(false); + setOverlayVisibility(View.VISIBLE); mVerificationProgressBar.setVisibility(View.VISIBLE); // TODO(estade): l10n mVerificationView.setText("Verifying card"); setInputError(null); } - public void verificationFinished(boolean success) { - if (!success) { - setInputsEnabled(true); - setInputError("Credit card could not be verified. Try again."); - // TODO(estade): depending on the type of error, we may not want to disable the - // verify button. But for the common case, where unmasking failed due to a bad - // value, verify should be disabled until the user makes some change. - mDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); - setInitialFocus(); - // TODO(estade): UI decision - should we clear the input? + public void verificationFinished(String errorMessage, boolean allowRetry) { + if (errorMessage != null) { + setOverlayVisibility(View.GONE); + if (allowRetry) { + setInputError(errorMessage); + setInputsEnabled(true); + setInitialFocus(); + } else { + setInputError(null); + setNoRetryError(errorMessage); + } } else { mVerificationProgressBar.setVisibility(View.GONE); mDialog.findViewById(R.id.verification_success).setVisibility(View.VISIBLE); mVerificationView.setText("Your card is verified"); Handler h = new Handler(); h.postDelayed(new Runnable() { + @Override public void run() { dismiss(); } - }, 500); + }, 1000); } } @@ -222,16 +228,24 @@ mCardUnmaskInput.setEnabled(enabled); mMonthInput.setEnabled(enabled); mYearInput.setEnabled(enabled); - mMainContents.setAlpha(enabled ? 1.0f : 0.15f); - mMainContents.setImportantForAccessibility( - enabled ? View.IMPORTANT_FOR_ACCESSIBILITY_AUTO - : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - ((ViewGroup) mMainContents).setDescendantFocusability( - enabled ? ViewGroup.FOCUS_BEFORE_DESCENDANTS - : ViewGroup.FOCUS_BLOCK_DESCENDANTS); + mStoreLocallyCheckbox.setEnabled(enabled); mDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled); + } - mVerificationOverlay.setVisibility(enabled ? View.GONE : View.VISIBLE); + /** + * Updates the verification overlay and main contents such that the overlay has |visibility|. + * @param visibility A View visibility enumeration value. + */ + private void setOverlayVisibility(int visibility) { + mVerificationOverlay.setVisibility(visibility); + boolean contentsShowing = visibility == View.GONE; + mMainContents.setAlpha(contentsShowing ? 1.0f : 0.15f); + ViewCompat.setImportantForAccessibility(mMainContents, + contentsShowing ? View.IMPORTANT_FOR_ACCESSIBILITY_AUTO + : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + mMainContents.setDescendantFocusability( + contentsShowing ? ViewGroup.FOCUS_BEFORE_DESCENDANTS + : ViewGroup.FOCUS_BLOCK_DESCENDANTS); } /** @@ -260,6 +274,14 @@ } /** + * Displays an error that indicates the user can't retry. + */ + private void setNoRetryError(String message) { + mNoRetryErrorMessage.setText(message); + mNoRetryErrorMessage.setVisibility(View.VISIBLE); + } + + /** * Sets the stroke color for the given input. * @param input The input to modify. * @param filter The color filter to apply to the background.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java index d03d98f..e9b89d7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java
@@ -18,6 +18,7 @@ import android.webkit.URLUtil; import android.widget.Toast; +import org.chromium.base.CalledByNative; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; import org.chromium.chrome.browser.Tab; @@ -307,11 +308,65 @@ } /** + * Launch an info bar if the file name already exists for the download. + * @param info The information of the file we are about to download. + * @return Whether an info bar has been launched or not. + */ + private boolean launchInfoBarIfFileExists(final DownloadInfo info) { + // Checks if file exists. + final String fileName = info.getFileName(); + File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); + if (!dir.mkdir() && !dir.isDirectory()) return false; + String dirName = dir.getName(); + final File file = new File(dir, info.getFileName()); + String fullDirPath = file.getParent(); + if (!file.exists()) return false; + if (TextUtils.isEmpty(fileName) || TextUtils.isEmpty(dirName) + || TextUtils.isEmpty(fullDirPath)) { + return false; + } + + nativeLaunchDownloadOverwriteInfoBar( + this, mTab, info, info.getFileName(), dirName, fullDirPath); + return true; + } + + /** * Sends the download request to Android download manager. * * @param info Download information about the download. */ protected void enqueueDownloadManagerRequest(final DownloadInfo info) { + if (!launchInfoBarIfFileExists(info)) { + enqueueDownloadManagerRequestInternal(info); + } + } + + /** + * Enqueue download manager request, only from native side. + * + * @param overwrite Whether or not we will overwrite the file. + * @param downloadInfo The download info. + */ + @CalledByNative + private void enqueueDownloadManagerRequestFromNative( + boolean overwrite, DownloadInfo downloadInfo) { + // Android DownloadManager does not have an overwriting option. + // We remove the file here instead. + if (overwrite) deleteFileForOverwrite(downloadInfo); + enqueueDownloadManagerRequestInternal(downloadInfo); + } + + private void deleteFileForOverwrite(DownloadInfo info) { + File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); + if (!dir.isDirectory()) return; + final File file = new File(dir, info.getFileName()); + if (!file.delete()) { + Log.e(LOGTAG, "Failed to delete a file." + info.getFileName()); + } + } + + private void enqueueDownloadManagerRequestInternal(final DownloadInfo info) { DownloadManagerService.getDownloadManagerService( mContext.getApplicationContext()).enqueueDownloadManagerRequest(info, true); closeBlankTab(); @@ -495,4 +550,7 @@ private static native boolean nativeIsDownloadDangerous(String filename); private static native void nativeDangerousDownloadValidated( Object tab, int downloadId, boolean accept); + private static native void nativeLaunchDownloadOverwriteInfoBar(ChromeDownloadDelegate delegate, + Tab tab, DownloadInfo downloadInfo, String fileName, String dirName, + String dirFullPath); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java index d8c73406..d56113e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -654,8 +654,8 @@ @Override protected void onPostExecute(Boolean result) { - boolean isPendingOMADownload = mOMADownloadHandler.isPendingOMADownload( - (long) mDownloadInfo.getDownloadId()); + boolean isPendingOMADownload = + mOMADownloadHandler.isPendingOMADownload(mDownloadInfo.getDownloadId()); if (!result) { Toast.makeText(mContext, mErrorId, Toast.LENGTH_SHORT).show(); if (isPendingOMADownload) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModel.java b/chrome/android/java/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModel.java index 2f5107ca..d18ee50 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModel.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.enhanced_bookmarks; import org.chromium.base.ObserverList; +import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.BookmarksBridge; import org.chromium.chrome.browser.BookmarksBridge.BookmarkItem; import org.chromium.chrome.browser.BookmarksBridge.BookmarkModelObserver; @@ -58,9 +59,10 @@ mEnhancedBookmarksBridge = new EnhancedBookmarksBridge(originalProfile); } - // TODO(ianwen): remove this constructor. - public EnhancedBookmarksModel(int cacheSize) { - this(); + @VisibleForTesting + public EnhancedBookmarksModel(Profile profile) { + mBookmarksBridge = new BookmarksBridge(profile); + mEnhancedBookmarksBridge = new EnhancedBookmarksBridge(profile); } /** @@ -275,7 +277,8 @@ } /** - * @see EnhancedBookmarksBridge#moveBookmark(BookmarkId, BookmarkId) + * Calls {@link EnhancedBookmarksBridge#moveBookmark(BookmarkId, BookmarkId)} in a reversed + * order of the list, in order to let the last item appear at the top. */ public void moveBookmarks(List<BookmarkId> bookmarkIds, BookmarkId newParentId) { for (int i = bookmarkIds.size() - 1; i >= 0; i--) { @@ -394,4 +397,12 @@ public void removeSearchObserver(SearchServiceObserver observer) { mEnhancedBookmarksBridge.removeSearchObserver(observer); } + + /** + * @see BookmarksBridge#loadEmptyPartnerBookmarkShimForTesting() + */ + @VisibleForTesting + public void loadEmptyPartnerBookmarkShimForTesting() { + mBookmarksBridge.loadEmptyPartnerBookmarkShimForTesting(); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunPageDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunPageDelegate.java index 926ea11..0d79ef2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunPageDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunPageDelegate.java
@@ -90,9 +90,14 @@ void openAccountAdder(Fragment fragment); /** - * Opens Chrome Preferences on a given page. - * @param fragment A fragment that requested the service. - * @param pageClassName The preferences fragment class name. + * Show an EmbedContentViewActivity with a given title and a URL. + * @param title Resource id for the title of the EmbedContentViewActivity. + * @param url Resource id for the URL of the EmbedContentViewActivity. */ - void openChromePreferencesPage(Fragment fragment, String pageClassName); -} + void showEmbedContentViewActivity(int title, int url); + + /** + * Opens Chrome preferences for document mode. + */ + void openDocumentModeSettings(); +} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java index e9141cf..97cf293 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
@@ -72,7 +72,7 @@ private float mBrowserControlOffset = Float.NaN; private float mRendererControlOffset = Float.NaN; private float mRendererContentOffset; - private float mPreviousContentOffset; + private float mPreviousContentOffset = Float.NaN; private float mControlOffset; private float mPreviousControlOffset; private boolean mIsEnteringPersistentModeState;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java index 77b19ea..2725ec3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java
@@ -9,6 +9,7 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; +import android.annotation.TargetApi; import android.os.Build; import android.view.View; import android.view.ViewTreeObserver; @@ -217,6 +218,7 @@ mTargetWrapperView.startTransition(); } + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public void onAnimationEnd(Animator animation) { mTargetWrapperView.finishTransition();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBar.java index 2f62227..970a51c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBar.java
@@ -7,6 +7,7 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; +import android.support.v4.view.ViewCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -107,9 +108,9 @@ } // Hide uninteresting views from accessibility. - ratingView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + ViewCompat.setImportantForAccessibility(ratingView, View.IMPORTANT_FOR_ACCESSIBILITY_NO); if (mIconView != null) { - mIconView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + ViewCompat.setImportantForAccessibility(mIconView, View.IMPORTANT_FOR_ACCESSIBILITY_NO); } // Set up clicking on the controls to bring up the app details.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DownloadOverwriteInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DownloadOverwriteInfoBar.java new file mode 100644 index 0000000..c16e0ea --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DownloadOverwriteInfoBar.java
@@ -0,0 +1,136 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.infobar; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.Typeface; +import android.net.Uri; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.style.ClickableSpan; +import android.text.style.StyleSpan; +import android.view.View; + +import org.chromium.base.CalledByNative; +import org.chromium.chrome.R; + +import java.util.List; + +/** + * An infobar to ask whether to overwrite an existing file with a new download. + */ +public class DownloadOverwriteInfoBar extends InfoBar { + private static final String TAG = "DownloadOverwriteInfoBar"; + + private final String mFileName; + private final String mDirName; + private final String mDirFullPath; + + @CalledByNative + private static InfoBar createInfoBar( + long nativeInfoBar, String fileName, String dirName, String dirFullPath) { + return new DownloadOverwriteInfoBar(nativeInfoBar, fileName, dirName, dirFullPath); + } + + /** + * Constructs DownloadOverwriteInfoBar. + * @param nativeInfoBarPtr Pointer value of the native infobar. + * @param fileName The file name. ex) example.jpg + * @param dirName The dir name. ex) Downloads + * @param dirFullPath The full dir path. ex) sdcards/Downloads + */ + private DownloadOverwriteInfoBar( + long nativeInfoBarPtr, String fileName, String dirName, String dirFullPath) { + super(null, R.drawable.infobar_downloading, null, null); + mFileName = fileName; + mDirName = dirName; + mDirFullPath = dirFullPath; + setNativeInfoBar(nativeInfoBarPtr); + } + + @Override + public void onCloseButtonClicked() { + if (mNativeInfoBarPtr != 0) nativeOnCloseButtonClicked(mNativeInfoBarPtr); + } + + @Override + public void onButtonClicked(boolean isPrimaryButton) { + int action = isPrimaryButton ? InfoBar.ACTION_TYPE_OVERWRITE + : InfoBar.ACTION_TYPE_CREATE_NEW_FILE; + if (mNativeInfoBarPtr != 0) nativeOnButtonClicked(mNativeInfoBarPtr, action, ""); + } + + private CharSequence getMessageText(Context context) { + String template = context.getString(R.string.download_overwrite_infobar_text); + Intent intent = getIntentForDirectoryLaunch(mDirFullPath); + return formatInfoBarMessage(context, template, mFileName, mDirName, intent); + } + + /** + * @param dirFullPath The full path of the directory to be launched. + * @return An Android intent that can launch the directory. + */ + private static Intent getIntentForDirectoryLaunch(String dirFullPath) { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + Uri uri = Uri.parse(dirFullPath); + if (uri == null) { + return null; + } + intent.setDataAndType(uri, "*/*"); + return intent; + } + + @Override + public void createContent(InfoBarLayout layout) { + Context context = layout.getContext(); + layout.setMessage(getMessageText(context)); + layout.setButtons( + context.getString(R.string.download_overwrite_infobar_replace_file_button), + context.getString(R.string.download_overwrite_infobar_create_new_file_button)); + } + + /** + * Create infobar message in the form of CharSequence. + * + * @param context The context. + * @param template The template CharSequence. + * @param fileName The file name. + * @param dirName The directory name. + * @param dirNameIntent The intent to be launched when user touches the directory name link. + * @return CharSequence formatted message for InfoBar. + */ + private static CharSequence formatInfoBarMessage(final Context context, String template, + String fileName, String dirName, final Intent dirNameIntent) { + SpannableString formattedFileName = new SpannableString(fileName); + formattedFileName.setSpan(new StyleSpan(Typeface.BOLD), 0, fileName.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + SpannableString formattedDirName = new SpannableString(dirName); + if (canResolveIntent(context, dirNameIntent)) { + formattedDirName.setSpan(new ClickableSpan() { + @Override + public void onClick(View view) { + context.startActivity(dirNameIntent); + } + }, 0, dirName.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + return TextUtils.expandTemplate(template, formattedFileName, formattedDirName); + } + + private static boolean canResolveIntent(Context context, Intent intent) { + if (context == null || intent == null) { + return false; + } + final PackageManager packageManager = context.getPackageManager(); + List<ResolveInfo> resolveInfoList = + packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); + return resolveInfoList.size() > 0; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java index 3405852..26c1a29 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java
@@ -36,6 +36,10 @@ public static final int ACTION_TYPE_TRANSLATE = 3; public static final int ACTION_TYPE_TRANSLATE_SHOW_ORIGINAL = 4; + // Download Overwrite InfoBar + public static final int ACTION_TYPE_OVERWRITE = 5; + public static final int ACTION_TYPE_CREATE_NEW_FILE = 6; + private final int mIconDrawableId; private final Bitmap mIconBitmap; private final CharSequence mMessage;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java index 1e94673..d7927eda 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -15,6 +15,8 @@ import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.OnPreDrawListener; +import org.chromium.chrome.browser.metrics.MemoryUma; + /** * An activity that talks with application and activity level delegates for async initialization. */ @@ -30,6 +32,7 @@ private Bundle mSavedInstanceState; private boolean mDestroyed; private NativeInitializationController mNativeInitializationController; + private MemoryUma mMemoryUma; public AsyncInitializationActivity() { mHandler = new Handler(); @@ -71,6 +74,7 @@ @Override public void finishNativeInitialization() { + mMemoryUma = new MemoryUma(); mNativeInitializationController.onNativeInitializationComplete(); } @@ -146,6 +150,7 @@ @Override public void onStop() { super.onStop(); + if (mMemoryUma != null) mMemoryUma.onStop(); mNativeInitializationController.onStop(); } @@ -196,6 +201,19 @@ return false; } + @Override + public void onLowMemory() { + super.onLowMemory(); + if (mMemoryUma != null) mMemoryUma.onLowMemory(); + } + + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + if (mMemoryUma != null) mMemoryUma.onTrimMemory(level); + } + + /** * Extending classes should implement this and call {@link Activity#setContentView(int)} in it. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/MemoryUma.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/MemoryUma.java new file mode 100644 index 0000000..5deefaa --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/MemoryUma.java
@@ -0,0 +1,89 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.metrics; + +import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_COMPLETE; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; + +import android.os.Build; +import android.os.SystemClock; + +import org.chromium.base.metrics.RecordHistogram; + +import java.util.concurrent.TimeUnit; + +/** + * Centralizes UMA data collection for Android-specific memory conditions. + */ +public class MemoryUma { + // AndroidMemoryNotificationBackground defined in tools/metrics/histograms/histograms.xml. + private static final int BACKGROUND_TRIM_UI_HIDDEN = 0; + private static final int BACKGROUND_TRIM_BACKGROUND = 1; + private static final int BACKGROUND_TRIM_MODERATE = 2; + private static final int BACKGROUND_TRIM_COMPLETE = 3; + private static final int BACKGROUND_MAX = 4; + + // AndroidMemoryNotificationForeground defined in tools/metrics/histograms/histograms.xml. + private static final int FOREGROUND_TRIM_MODERATE = 0; + private static final int FOREGROUND_TRIM_LOW = 1; + private static final int FOREGROUND_TRIM_CRITICAL = 2; + private static final int FOREGROUND_LOW = 3; + private static final int FOREGROUND_MAX = 4; + + // Timestamp of the last time we received a LowMemory call since Chrome is in foreground. + private long mLastLowMemoryMsec = -1; + + public void onStop() { + mLastLowMemoryMsec = -1; + } + + public void onLowMemory() { + memoryNotificationForeground(FOREGROUND_LOW); + long now = SystemClock.elapsedRealtime(); + if (mLastLowMemoryMsec >= 0) { + RecordHistogram.recordCustomTimesHistogram("MemoryAndroid.LowMemoryTimeBetween", + now - mLastLowMemoryMsec, 0, TimeUnit.MINUTES.toMillis(10), + TimeUnit.MILLISECONDS, 50); + } + mLastLowMemoryMsec = now; + } + + public void onTrimMemory(int level) { + if (level >= TRIM_MEMORY_COMPLETE) { + memoryNotificationBackground(BACKGROUND_TRIM_COMPLETE); + } else if (level >= TRIM_MEMORY_MODERATE) { + memoryNotificationBackground(BACKGROUND_TRIM_MODERATE); + } else if (level >= TRIM_MEMORY_BACKGROUND) { + memoryNotificationBackground(BACKGROUND_TRIM_BACKGROUND); + } else if (level >= TRIM_MEMORY_UI_HIDDEN) { + memoryNotificationBackground(BACKGROUND_TRIM_UI_HIDDEN); + } else if (level >= TRIM_MEMORY_RUNNING_CRITICAL) { + memoryNotificationForeground(FOREGROUND_TRIM_CRITICAL); + } else if (level >= TRIM_MEMORY_RUNNING_LOW) { + memoryNotificationForeground(FOREGROUND_TRIM_LOW); + } else if (level >= TRIM_MEMORY_RUNNING_MODERATE) { + memoryNotificationForeground(FOREGROUND_TRIM_MODERATE); + } + } + + private static void memoryNotificationForeground(int notification) { + assert notification >= 0 && notification < FOREGROUND_MAX; + // Before Jelly Bean we have only LowMemory foreground notification. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return; + RecordHistogram.recordEnumeratedHistogram("MemoryAndroid.NotificationForeground", + notification, FOREGROUND_MAX); + } + + private static void memoryNotificationBackground(int notification) { + assert notification >= 0 && notification < BACKGROUND_MAX; + RecordHistogram.recordEnumeratedHistogram("MemoryAndroid.NotificationBackground", + notification, BACKGROUND_MAX); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaBridge.java new file mode 100644 index 0000000..75bad02 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaBridge.java
@@ -0,0 +1,107 @@ +// 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. + +package org.chromium.chrome.browser.metrics; + +import org.chromium.chrome.browser.preferences.bandwidth.BandwidthReductionPreferences; +import org.chromium.chrome.browser.preferences.bandwidth.DataReductionPromoScreen; + +/** + * Static methods to record user actions. + * + * We have a different native method for each action as we want to use c++ code to + * extract user command keys from code and show them in the dashboard. + * See: chromium/src/content/browser/user_metrics.h for more details. + */ +public class UmaBridge { + + /** + * Record that the user opened the menu. + */ + public static void menuShow() { + nativeRecordMenuShow(); + } + + /** + * Record that the user opened the menu through software menu button. + * @param isByHwButton + * @param isDragging + */ + public static void usingMenu(boolean isByHwButton, boolean isDragging) { + nativeRecordUsingMenu(isByHwButton, isDragging); + } + + // Android beam + + public static void beamCallbackSuccess() { + nativeRecordBeamCallbackSuccess(); + } + + public static void beamInvalidAppState() { + nativeRecordBeamInvalidAppState(); + } + + // Data Saver + + /** + * Record that Data Saver was turned on. + */ + public static void dataReductionProxyTurnedOn() { + nativeRecordDataReductionProxyTurnedOn(); + } + + /** + * Record that Data Saver was turned off. + */ + public static void dataReductionProxyTurnedOff() { + nativeRecordDataReductionProxyTurnedOff(); + } + + /** + * Record that Data Saver was turned on immediately after the user viewed the promo screen. + */ + public static void dataReductionProxyTurnedOnFromPromo() { + nativeRecordDataReductionProxyTurnedOnFromPromo(); + } + + /** + * Record the DataReductionProxy.PromoAction histogram. + * @param action User action at the promo screen + */ + public static void dataReductionProxyPromoAction(int action) { + assert action >= 0 && action < DataReductionPromoScreen.ACTION_INDEX_BOUNDARY; + nativeRecordDataReductionProxyPromoAction( + action, DataReductionPromoScreen.ACTION_INDEX_BOUNDARY); + } + + /** + * Record that the Data Saver promo was displayed. + */ + public static void dataReductionProxyPromoDisplayed() { + nativeRecordDataReductionProxyPromoDisplayed(); + } + + /** + * Record the DataReductionProxy.SettingsConversion histogram. + * @param statusChange ON/OFF change at the data saver setting menu + */ + public static void dataReductionProxySettings(int statusChange) { + assert statusChange >= 0 + && statusChange < BandwidthReductionPreferences.DATA_REDUCTION_INDEX_BOUNDARY; + nativeRecordDataReductionProxySettings( + statusChange, BandwidthReductionPreferences.DATA_REDUCTION_INDEX_BOUNDARY); + } + + private static native void nativeRecordMenuShow(); + private static native void nativeRecordUsingMenu(boolean isByHwButton, boolean isDragging); + private static native void nativeRecordBeamInvalidAppState(); + private static native void nativeRecordBeamCallbackSuccess(); + private static native void nativeRecordDataReductionProxyTurnedOn(); + private static native void nativeRecordDataReductionProxyTurnedOff(); + private static native void nativeRecordDataReductionProxyTurnedOnFromPromo(); + private static native void nativeRecordDataReductionProxyPromoAction(int action, int boundary); + private static native void nativeRecordDataReductionProxyPromoDisplayed(); + private static native void nativeRecordDataReductionProxySettings(int statusChange, + int boundary); +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java new file mode 100644 index 0000000..e3de19b --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java
@@ -0,0 +1,189 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.metrics; + +import android.app.Activity; +import android.content.ComponentCallbacks; +import android.content.Context; +import android.content.res.Configuration; + +import org.chromium.base.ActivityState; +import org.chromium.base.ApplicationStatus; +import org.chromium.chrome.browser.Tab; +import org.chromium.chrome.browser.preferences.privacy.CrashReportingPermissionManager; +import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; +import org.chromium.content_public.browser.WebContents; +import org.chromium.net.NetworkChangeNotifier; + +/** + * Mainly sets up session stats for chrome. A session is defined as the duration when the + * application is in the foreground. Also used to communicate information between Chrome + * and the framework's MetricService. + */ +public class UmaSessionStats implements NetworkChangeNotifier.ConnectionTypeObserver { + private static final String SAMSUNG_MULTWINDOW_PACKAGE = "com.sec.feature.multiwindow"; + + private static long sNativeUmaSessionStats = 0; + + // TabModelSelector is needed to get the count of open tabs. We want to log the number of open + // tabs on every page load. + private TabModelSelector mTabModelSelector; + private TabModelSelectorTabObserver mTabModelSelectorTabObserver; + + private final Context mContext; + private final boolean mIsMultiWindowCapable; + private ComponentCallbacks mComponentCallbacks; + + private boolean mKeyboardConnected = false; + private final CrashReportingPermissionManager mReportingPermissionManager; + + public UmaSessionStats(Context context) { + mContext = context; + mIsMultiWindowCapable = context.getPackageManager().hasSystemFeature( + SAMSUNG_MULTWINDOW_PACKAGE); + mReportingPermissionManager = PrivacyPreferencesManager.getInstance(context); + } + + private void recordPageLoadStats(int tabId) { + Tab tab = mTabModelSelector.getTabById(tabId); + if (tab == null) return; + WebContents webContents = tab.getWebContents(); + boolean isDesktopUserAgent = webContents != null + && webContents.getNavigationController().getUseDesktopUserAgent(); + nativeRecordPageLoaded(isDesktopUserAgent); + if (mKeyboardConnected) { + nativeRecordPageLoadedWithKeyboard(); + } + + TabModel regularModel = mTabModelSelector.getModel(false); + nativeRecordTabCountPerLoad(getTabCountFromModel(regularModel)); + } + + private int getTabCountFromModel(TabModel model) { + return model == null ? 0 : model.getCount(); + } + + /** + * Starts a new session for logging. + * @param tabModelSelector A TabModelSelector instance for recording tab counts on page loads. + * If null, UmaSessionStats does not record page loads and tab counts. + */ + public void startNewSession(TabModelSelector tabModelSelector) { + ensureNativeInitialized(); + + mTabModelSelector = tabModelSelector; + if (mTabModelSelector != null) { + mComponentCallbacks = new ComponentCallbacks() { + @Override + public void onLowMemory() { + // Not required + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + mKeyboardConnected = newConfig.keyboard != Configuration.KEYBOARD_NOKEYS; + } + }; + mContext.registerComponentCallbacks(mComponentCallbacks); + mKeyboardConnected = mContext.getResources().getConfiguration() + .keyboard != Configuration.KEYBOARD_NOKEYS; + mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(mTabModelSelector) { + @Override + public void onPageLoadFinished(Tab tab) { + recordPageLoadStats(tab.getId()); + } + }; + } + + nativeUmaResumeSession(sNativeUmaSessionStats); + NetworkChangeNotifier.addConnectionTypeObserver(this); + updateMetricsServiceState(); + } + + private static void ensureNativeInitialized() { + // Lazily create the native object and the notification handler. These objects are never + // destroyed. + if (sNativeUmaSessionStats == 0) { + sNativeUmaSessionStats = nativeInit(); + } + } + + /** + * Logs screen ratio on Samsung MultiWindow devices. + */ + public void logMultiWindowStats(int windowArea, int displayArea, int instanceCount) { + if (mIsMultiWindowCapable) { + if (displayArea == 0) return; + int areaPercent = (windowArea * 100) / displayArea; + int safePercent = areaPercent > 0 ? areaPercent : 0; + nativeRecordMultiWindowSession(safePercent, instanceCount); + } + } + + /** + * Logs the current session. + */ + public void logAndEndSession() { + if (mTabModelSelector != null) { + mContext.unregisterComponentCallbacks(mComponentCallbacks); + mTabModelSelectorTabObserver.destroy(); + mTabModelSelector = null; + } + + nativeUmaEndSession(sNativeUmaSessionStats); + NetworkChangeNotifier.removeConnectionTypeObserver(this); + } + + public static void logRendererCrash(Activity activity) { + int activityState = ApplicationStatus.getStateForActivity(activity); + nativeLogRendererCrash( + activityState == ActivityState.PAUSED + || activityState == ActivityState.STOPPED + || activityState == ActivityState.DESTROYED); + } + + /** + * Updates the state of the MetricsService to account for the user's preferences. + */ + public void updateMetricsServiceState() { + boolean mayRecordStats = !PrivacyPreferencesManager.getInstance(mContext) + .isNeverUploadCrashDump(); + boolean mayUploadStats = mReportingPermissionManager.isUploadPermitted(); + + // Re-start the MetricsService with the given parameters. + nativeUpdateMetricsServiceState(mayRecordStats, mayUploadStats); + } + + @Override + public void onConnectionTypeChanged(int connectionType) { + updateMetricsServiceState(); + } + + public static void registerExternalExperiment(int studyId, int experimentId) { + nativeRegisterExternalExperiment(studyId, experimentId); + } + + public static void registerSyntheticFieldTrial(String trialName, String groupName) { + nativeRegisterSyntheticFieldTrial(trialName, groupName); + } + + private static native long nativeInit(); + private native void nativeUpdateMetricsServiceState(boolean mayRecord, boolean mayUpload); + private native void nativeUmaResumeSession(long nativeUmaSessionStats); + private native void nativeUmaEndSession(long nativeUmaSessionStats); + private static native void nativeLogRendererCrash(boolean isPaused); + private static native void nativeRegisterExternalExperiment(int studyId, + int experimentId); + private static native void nativeRegisterSyntheticFieldTrial( + String trialName, String groupName); + private static native void nativeRecordMultiWindowSession(int areaPercent, int instanceCount); + private static native void nativeRecordTabCountPerLoad(int numTabsOpen); + private static native void nativeRecordPageLoaded(boolean isDesktopUserAgent); + private static native void nativeRecordPageLoadedWithKeyboard(); + +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java new file mode 100644 index 0000000..5dc4d296 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
@@ -0,0 +1,54 @@ +// 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. + +package org.chromium.chrome.browser.metrics; + +import org.chromium.base.CalledByNative; + +/** + * Utilities to support startup metrics - Android version. + */ +public class UmaUtils { + + private static long sApplicationStartWallClockMs; + + private static boolean sRunningApplicationStart; + + /** + * Record the time at which the activity started. This should be called asap after + * the start of the activity's onCreate function. + */ + public static void recordMainEntryPointTime() { + // We can't simply pass this down through a JNI call, since the JNI for chrome + // isn't initialized until we start the native content browser component, and we + // then need the start time in the C++ side before we return to Java. As such we + // save it in a static that the C++ can fetch once it has initialized the JNI. + sApplicationStartWallClockMs = System.currentTimeMillis(); + } + + /** + * Whether the application is in the early stage since the browser process start. The + * "application start" ends right after the last histogram related to browser startup is + * recorded. Currently, the very first navigation commit in the lifetime of the process ends the + * "application start". + * Must only be called on the UI thread. + */ + public static boolean isRunningApplicationStart() { + return sRunningApplicationStart; + } + + /** + * Marks/unmarks the "application start" stage of the browser process lifetime. + * Must only be called on the UI thread. + */ + public static void setRunningApplicationStart(boolean isAppStart) { + sRunningApplicationStart = isAppStart; + } + + @CalledByNative + private static long getMainEntryPointTime() { + return sApplicationStartWallClockMs; + } + +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/OWNERS new file mode 100644 index 0000000..845f1d7b --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/OWNERS
@@ -0,0 +1 @@ +bengr@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/nfc/BeamCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/nfc/BeamCallback.java index 4811d20..5603de7a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/nfc/BeamCallback.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/nfc/BeamCallback.java
@@ -18,7 +18,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.chrome.R; -import org.chromium.chrome.browser.UmaBridge; +import org.chromium.chrome.browser.metrics.UmaBridge; import java.net.MalformedURLException; import java.net.URL;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java index d67a1eb0..7665c5f0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java
@@ -303,12 +303,11 @@ res.getDimensionPixelSize(android.R.dimen.notification_large_icon_height); return new RoundedIconGenerator( - appContext, - (int) (widthPx / density), - (int) (heightPx / density), - (int) (Math.min(widthPx, heightPx) / density / 2), + widthPx, + heightPx, + Math.min(widthPx, heightPx) / 2, NOTIFICATION_ICON_BG_COLOR, - NOTIFICATION_TEXT_SIZE_DP); + NOTIFICATION_TEXT_SIZE_DP * density); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/AboutChromePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/AboutChromePreferences.java index d93219c..92ea42c0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/AboutChromePreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/AboutChromePreferences.java
@@ -6,6 +6,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Build; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceFragment; @@ -16,7 +17,6 @@ import org.chromium.chrome.browser.ChromeVersionInfo; import org.chromium.chrome.browser.preferences.PrefServiceBridge.AboutVersionStrings; import org.chromium.chrome.browser.preferences.PrefServiceBridge.ProfilePathCallback; -import org.chromium.chrome.browser.util.FeatureUtilities; import java.util.Calendar; @@ -40,7 +40,7 @@ getActivity().setTitle(R.string.prefs_about_chrome); addPreferencesFromResource(R.xml.about_chrome_preferences); - if (!FeatureUtilities.isApplicationUpdateSupported()) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { ChromeBasePreference deprecationWarning = new ChromeBasePreference( new ContextThemeWrapper(getActivity(), R.style.DeprecationWarningPreferenceTheme));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPreferences.java index 1eb5516..b84dbdb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPreferences.java
@@ -37,6 +37,8 @@ private static final String PREF_AUTOFILL_CREDIT_CARDS = "autofill_credit_cards"; private static final String PREF_AUTOFILL_WALLET = "autofill_wallet"; + ChromeBasePreference mWalletPref; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -57,23 +59,13 @@ } }); - ChromeBasePreference walletPref = - (ChromeBasePreference) findPreference(PREF_AUTOFILL_WALLET); - if (!PersonalDataManager.isWalletImportFeatureAvailable()) { - getPreferenceScreen().removePreference(walletPref); - autofillSwitch.setDrawDivider(true); - } else { - walletPref.setSummary(getResources().getString( - PersonalDataManager.isWalletImportEnabled() ? R.string.text_on - : R.string.text_off)); - } - + mWalletPref = (ChromeBasePreference) findPreference(PREF_AUTOFILL_WALLET); setPreferenceCategoryIcons(); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { - rebuildLists(); + refreshState(); return true; } @@ -92,9 +84,10 @@ } /** - * Rebuild all the profile and credit card lists. + * Refresh state (profile and credit card lists, preference summaries, etc.). */ - private void rebuildLists() { + private void refreshState() { + updateSummaries(); rebuildProfileList(); rebuildCreditCardList(); } @@ -140,6 +133,24 @@ } } + private void updateSummaries() { + ChromeSwitchPreference autofillSwitch = + (ChromeSwitchPreference) findPreference(PREF_AUTOFILL_SWITCH); + if (!PersonalDataManager.isWalletImportFeatureAvailable()) { + getPreferenceScreen().removePreference(mWalletPref); + autofillSwitch.setDrawDivider(true); + } else { + if (getPreferenceScreen().findPreference(PREF_AUTOFILL_WALLET) == null) { + getPreferenceScreen().addPreference(mWalletPref); + } + + mWalletPref.setSummary(getResources().getString( + PersonalDataManager.isWalletImportEnabled() ? R.string.text_on + : R.string.text_off)); + autofillSwitch.setDrawDivider(false); + } + } + @Override public void onResume() { super.onResume(); @@ -147,12 +158,12 @@ // detect if profiles are added or deleted (GUID list // changes), the profile summary (name+addr) might be // different. To be safe, we update all. - rebuildLists(); + refreshState(); } @Override public void onPersonalDataChanged() { - rebuildLists(); + refreshState(); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/BandwidthReductionPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/BandwidthReductionPreferences.java index abe2309..43d89378 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/BandwidthReductionPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/BandwidthReductionPreferences.java
@@ -16,9 +16,9 @@ import android.text.format.DateUtils; import org.chromium.chrome.R; -import org.chromium.chrome.browser.UmaBridge; import org.chromium.chrome.browser.firstrun.FirstRunStatus; import org.chromium.chrome.browser.infobar.DataReductionProxyInfoBar; +import org.chromium.chrome.browser.metrics.UmaBridge; import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings; import org.chromium.chrome.browser.preferences.ChromeSwitchPreference; import org.chromium.chrome.browser.preferences.ManagedPreferenceDelegate;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/DataReductionPromoScreen.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/DataReductionPromoScreen.java index 60a379c..a3b3e753 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/DataReductionPromoScreen.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/DataReductionPromoScreen.java
@@ -19,7 +19,7 @@ import org.chromium.base.ApplicationStatus; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromiumApplication; -import org.chromium.chrome.browser.UmaBridge; +import org.chromium.chrome.browser.metrics.UmaBridge; import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings; import org.chromium.chrome.browser.preferences.PreferencesLauncher;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ManageSavedPasswordsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ManageSavedPasswordsPreferences.java index bb6bffde..5290cf3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ManageSavedPasswordsPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ManageSavedPasswordsPreferences.java
@@ -272,7 +272,8 @@ } private void displayManageAccountLink() { - if (PasswordUIView.shouldDisplayManageAccountLink() + boolean shouldDisplayLink = PasswordUIView.shouldDisplayManageAccountLink(); + if (shouldDisplayLink && getPreferenceScreen().findPreference(PREF_MANAGE_ACCOUNT_LINK) == null) { if (mLinkPref == null) { ForegroundColorSpan colorSpan = new ForegroundColorSpan( @@ -287,10 +288,9 @@ mLinkPref.setOrder(ORDER_MANAGE_ACCOUNT_LINK); } getPreferenceScreen().addPreference(mLinkPref); - } else { - // Draw a divider only if the preference after mSavePasswordsSwitch is not selectable, - // in which case the ListView itself doesn't draw a divider. - mSavePasswordsSwitch.setDrawDivider(true); } + // Draw a divider only if the preference after mSavePasswordsSwitch is not selectable, + // in which case the ListView itself doesn't draw a divider. + mSavePasswordsSwitch.setDrawDivider(!shouldDisplayLink); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/AddExceptionPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/AddExceptionPreference.java index 3cd23a4..be8e2d6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/AddExceptionPreference.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/AddExceptionPreference.java
@@ -16,14 +16,12 @@ import android.preference.Preference.OnPreferenceClickListener; import android.provider.Settings; import android.text.Editable; -import android.text.Spannable; -import android.text.SpannableString; import android.text.TextWatcher; -import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.EditText; +import android.widget.TextView; import android.widget.Toast; import org.chromium.chrome.R; @@ -36,6 +34,7 @@ public class AddExceptionPreference extends Preference implements OnPreferenceClickListener { // The callback to notify when the user adds a site. private SiteAddedCallback mSiteAddedCallback; + private int mPrefAccentColor; /** * An interface to implement to get a callback when a site has been added. @@ -57,20 +56,22 @@ setKey(key); Resources resources = getContext().getResources(); + mPrefAccentColor = resources.getColor(R.color.pref_accent_color); + Drawable plusIcon = resources.getDrawable(R.drawable.plus); plusIcon.mutate(); - plusIcon.setColorFilter( - resources.getColor(R.color.pref_accent_color), - PorterDuff.Mode.SRC_IN); + plusIcon.setColorFilter(mPrefAccentColor, PorterDuff.Mode.SRC_IN); setIcon(plusIcon); - SpannableString titleSpan = new SpannableString( - resources.getString( - R.string.website_settings_add_site).toUpperCase()); - titleSpan.setSpan(new ForegroundColorSpan( - resources.getColor(R.color.pref_accent_color)), 0, titleSpan.length(), - Spannable.SPAN_INCLUSIVE_INCLUSIVE); - setTitle(titleSpan); + setTitle(resources.getString(R.string.website_settings_add_site)); + } + + @Override + protected void onBindView(View view) { + super.onBindView(view); + TextView titleView = (TextView) view.findViewById(android.R.id.title); + titleView.setAllCaps(true); + titleView.setTextColor(mPrefAccentColor); } @Override @@ -89,6 +90,7 @@ final EditText input = (EditText) view.findViewById(R.id.site); DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() { + @Override public void onClick(DialogInterface dialog, int button) { if (button == AlertDialog.BUTTON_POSITIVE) { String hostname = input.getText().toString().trim();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java index 2417954..5a11bae9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
@@ -391,8 +391,13 @@ new Website.StoredDataClearedCallback() { @Override public void onStoredDataCleared() { - getPreferenceScreen().removePreference( - getPreferenceScreen().findPreference(PREF_CLEAR_DATA)); + PreferenceScreen preferenceScreen = getPreferenceScreen(); + preferenceScreen.removePreference( + preferenceScreen.findPreference(PREF_CLEAR_DATA)); + if (!hasUsagePreferences()) { + preferenceScreen.removePreference( + preferenceScreen.findPreference(PREF_USAGE)); + } popBackIfNoSettings(); } });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreference.java index 2158617..d4d0016 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreference.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreference.java
@@ -14,7 +14,6 @@ import android.text.format.Formatter; import android.view.View; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; import org.chromium.base.annotations.SuppressFBWarnings; @@ -46,12 +45,9 @@ // Metrics for favicon processing. private static final int FAVICON_CORNER_RADIUS_DP = 2; private static final int FAVICON_SIZE_DP = 16; - private static final int FAVICON_TEXT_SIZE_SP = 10; + private static final int FAVICON_PADDING_DP = 4; + private static final int FAVICON_TEXT_SIZE_DP = 10; private static final int FAVICON_BACKGROUND_COLOR = 0xff969696; - // The minimum width of the preference icon parent field. - private static final int FAVICON_PARENT_MINWIDTH_DP = 55; - // The padding for the preference icon parent field. - private static final int FAVICON_PARENT_PADDING_DP = 12; WebsitePreference(Context context, Website site, String categoryFilter) { super(context); @@ -61,15 +57,11 @@ setWidgetLayoutResource(R.layout.website_features); // To make sure the layout stays stable throughout, we assign a - // transparent drawable of the same size as the favicon. This is so that + // transparent drawable as the icon initially. This is so that // we can fetch the favicon in the background and not have to worry // about the title appearing to jump (http://crbug.com/453626) when the // favicon becomes available. - ColorDrawable drawable = new ColorDrawable(Color.TRANSPARENT); - int size = Math.round(FAVICON_SIZE_DP - * getContext().getResources().getDisplayMetrics().density); - drawable.setBounds(0, 0, size, size); - setIcon(drawable); + setIcon(new ColorDrawable(Color.TRANSPARENT)); refresh(); } @@ -94,7 +86,7 @@ RoundedIconGenerator faviconGenerator = new RoundedIconGenerator( getContext(), FAVICON_SIZE_DP, FAVICON_SIZE_DP, FAVICON_CORNER_RADIUS_DP, FAVICON_BACKGROUND_COLOR, - FAVICON_TEXT_SIZE_SP); + FAVICON_TEXT_SIZE_DP); image = faviconGenerator.generateIconForUrl(faviconUrl()); } @@ -146,8 +138,8 @@ TextView usageText = (TextView) view.findViewById(R.id.usage_text); usageText.setVisibility(View.GONE); - long totalUsage = mSite.getTotalUsage(); if (mFilter.showStorageSites(mCategoryFilter)) { + long totalUsage = mSite.getTotalUsage(); if (totalUsage > 0) { usageText.setText(Formatter.formatShortFileSize(getContext(), totalUsage)); usageText.setTextSize(TEXT_SIZE_SP); @@ -181,15 +173,9 @@ mFaviconFetched = true; } - ImageView icon = (ImageView) view.findViewById(android.R.id.icon); - View parent = (View) icon.getParent(); - if (parent instanceof LinearLayout) { - LinearLayout parentLayout = (LinearLayout) parent; - int minWidth = Math.round(FAVICON_PARENT_MINWIDTH_DP * density); - int padding = Math.round(FAVICON_PARENT_PADDING_DP * density); - parentLayout.setMinimumWidth(minWidth); - parentLayout.setPadding(padding, 0, padding, 0); - } + int iconPadding = Math.round(FAVICON_PADDING_DP * density); + View iconView = view.findViewById(android.R.id.icon); + iconView.setPadding(iconPadding, iconPadding, iconPadding, iconPadding); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreferences.java index 5e2e3bf1c..33afc82 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreferences.java
@@ -521,6 +521,8 @@ LocationSettings.getInstance().isChromeLocationSettingEnabled()); } else if (mFilter.showCameraMicSites(mCategoryFilter)) { globalToggle.setChecked(PrefServiceBridge.getInstance().isCameraMicEnabled()); + } else if (mFilter.showJavaScriptSites(mCategoryFilter)) { + globalToggle.setChecked(PrefServiceBridge.getInstance().javaScriptEnabled()); } else if (mFilter.showPopupSites(mCategoryFilter)) { globalToggle.setChecked(PrefServiceBridge.getInstance().popupsEnabled()); } else if (mFilter.showPushNotificationsSites(mCategoryFilter)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java index 5fcad3e7..d41e668 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java
@@ -17,6 +17,7 @@ import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.AsyncTask; import android.preference.PreferenceManager; import android.util.Log; @@ -119,7 +120,7 @@ */ private static void showShareDialog(final Activity activity, final String title, final String url, final Bitmap screenshot) { - Intent intent = getShareIntent(activity, title, url, null); + Intent intent = getShareIntent(title, url, null); PackageManager manager = activity.getPackageManager(); List<ResolveInfo> resolveInfoList = manager.queryIntentActivities(intent, 0); assert resolveInfoList.size() > 0; @@ -166,21 +167,46 @@ private static void makeIntentAndShare(final Activity activity, final String title, final String url, final Bitmap screenshot, final ComponentName component) { if (screenshot == null) { - activity.startActivity( - getDirectShareIntentForComponent(activity, title, url, null, component)); + activity.startActivity(getDirectShareIntentForComponent(title, url, null, component)); } else { - new AsyncTask<Void, Void, Intent>() { + new AsyncTask<Void, Void, File>() { @Override - protected Intent doInBackground(Void... params) { - return getDirectShareIntentForComponent( - activity, title, url, screenshot, component); + protected File doInBackground(Void... params) { + FileOutputStream fOut = null; + try { + File path = new File(UiUtils.getDirectoryForImageCapture(activity), + SCREENSHOT_DIRECTORY_NAME); + if (path.exists() || path.mkdir()) { + File saveFile = File.createTempFile( + String.valueOf(System.currentTimeMillis()), ".jpg", path); + fOut = new FileOutputStream(saveFile); + screenshot.compress(Bitmap.CompressFormat.JPEG, 85, fOut); + fOut.flush(); + fOut.close(); + + return saveFile; + } + } catch (IOException ie) { + if (fOut != null) { + try { + fOut.close(); + } catch (IOException e) { + // Ignore exception. + } + } + } + + return null; } @Override - protected void onPostExecute(Intent intent) { + protected void onPostExecute(File saveFile) { if (ApplicationStatus.getStateForApplication() != ApplicationState.HAS_DESTROYED_ACTIVITIES) { - activity.startActivity(intent); + Uri screenshotUri = saveFile == null + ? null : UiUtils.getUriForImageCaptureFile(activity, saveFile); + activity.startActivity(getDirectShareIntentForComponent( + title, url, screenshotUri, component)); } } }.execute(); @@ -217,47 +243,20 @@ } @VisibleForTesting - public static Intent getShareIntent( - Context context, String title, String url, Bitmap screenshot) { + public static Intent getShareIntent(String title, String url, Uri screenshotUri) { url = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url); Intent intent = new Intent(Intent.ACTION_SEND); intent.addFlags(ApiCompatibilityUtils.getActivityNewDocumentFlag()); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_SUBJECT, title); intent.putExtra(Intent.EXTRA_TEXT, url); - if (screenshot != null) { - FileOutputStream fOut = null; - try { - File path = new File( - UiUtils.getDirectoryForImageCapture(context), SCREENSHOT_DIRECTORY_NAME); - if (path.exists() || path.mkdir()) { - File saveFile = File.createTempFile( - String.valueOf(System.currentTimeMillis()), ".jpg", path); - fOut = new FileOutputStream(saveFile); - screenshot.compress(Bitmap.CompressFormat.JPEG, 85, fOut); - fOut.flush(); - fOut.close(); - - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - intent.putExtra(Intent.EXTRA_STREAM, - UiUtils.getUriForImageCaptureFile(context, saveFile)); - } - } catch (IOException ie) { - if (fOut != null) { - try { - fOut.close(); - } catch (IOException e) { - // Ignore exception. - } - } - } - } + if (screenshotUri != null) intent.putExtra(Intent.EXTRA_STREAM, screenshotUri); return intent; } private static Intent getDirectShareIntentForComponent( - Context context, String title, String url, Bitmap screenshot, ComponentName component) { - Intent intent = getShareIntent(context, title, url, screenshot); + String title, String url, Uri screenshotUri, ComponentName component) { + Intent intent = getShareIntent(title, url, screenshotUri); intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); intent.setComponent(component);
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 ed2586ec..0b2bf0c 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
@@ -25,6 +25,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.invalidation.InvalidationController; +import org.chromium.chrome.browser.notifications.GoogleServicesNotificationController; import org.chromium.chrome.browser.sync.ProfileSyncService; import org.chromium.sync.AndroidSyncSettings; import org.chromium.sync.internal_api.pub.base.ModelType; @@ -66,6 +67,8 @@ private final ObserverList<SignInAllowedObserver> mSignInAllowedObservers = new ObserverList<SignInAllowedObserver>(); + private final SigninNotificationController mSigninNotificationController; + private Activity mSignInActivity; private Account mSignInAccount; private SignInFlowObserver mSignInFlowObserver; @@ -164,6 +167,13 @@ mContext = context.getApplicationContext(); mNativeSigninManagerAndroid = nativeInit(); mSigninAllowedByPolicy = nativeIsSigninAllowedByPolicy(mNativeSigninManagerAndroid); + + // Setup notification system for Google services. This includes both sign-in and sync. + GoogleServicesNotificationController controller = + GoogleServicesNotificationController.get(mContext); + mSigninNotificationController = new SigninNotificationController( + mContext, controller, AccountManagementFragment.class); + ChromeSigninController.get(mContext).addListener(mSigninNotificationController); } /** @@ -230,6 +240,13 @@ } /** + * Return the SigninNotificationController. + */ + public SigninNotificationController getSigninNotificationController() { + return mSigninNotificationController; + } + + /** * Starts the sign-in flow, and executes the callback when ready to proceed. * <p/> * This method checks with the native side whether the account has management enabled, and may
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java index e87d454488..087b230 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
@@ -10,6 +10,7 @@ import android.util.Log; import org.chromium.base.ThreadUtils; +import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory; import org.chromium.chrome.browser.invalidation.InvalidationController; import org.chromium.chrome.browser.signin.SigninManager; import org.chromium.chrome.browser.signin.SigninManager.SignInFlowObserver; @@ -60,6 +61,9 @@ mProfileSyncService = ProfileSyncService.get(mContext); mProfileSyncService.addSyncStateChangedListener(this); mChromeSigninController.ensureGcmIsInitialized(); + // Set the sessions ID using the generator that was registered for GENERATOR_ID. + mProfileSyncService.setSessionsId( + UniqueIdentificationGeneratorFactory.getInstance(GENERATOR_ID)); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModel.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModel.java index ff7e1e6..87303e5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModel.java
@@ -163,12 +163,6 @@ /** * Adds the given Tab to this TabModel. - * @param tab Tab to add. - */ - void addTab(Tab tab); - - /** - * Adds the given Tab to this TabModel. * @param intent Intent of the DocumentActivity. * @param tab Tab to add. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java index 1d70e46..574047cc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java
@@ -864,13 +864,6 @@ } @Override - public void addTab(Tab tab) { - int parentIndex = indexOf(tab.getParentId()); - int index = parentIndex == -1 ? getCount() : parentIndex + 1; - addTab(tab, index, tab.getLaunchType()); - } - - @Override public void addTab(Intent intent, Tab tab) { int parentIndex = indexOf(tab.getParentId()); int index = parentIndex == -1 ? getCount() : parentIndex + 1;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/OffTheRecordDocumentTabModel.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/OffTheRecordDocumentTabModel.java index a85fc7e..1e8944e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/OffTheRecordDocumentTabModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/OffTheRecordDocumentTabModel.java
@@ -108,12 +108,6 @@ } @Override - public void addTab(Tab tab) { - ensureTabModelImpl(); - getDelegateDocumentTabModel().addTab(tab); - } - - @Override public void addTab(Intent intent, Tab tab) { ensureTabModelImpl(); getDelegateDocumentTabModel().addTab(intent, tab);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java index fb05f13..9bd9d83 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -121,9 +121,5 @@ nativeSetDocumentModeEnabled(enabled); } - public static boolean isApplicationUpdateSupported() { - return true; - } - private static native void nativeSetDocumentModeEnabled(boolean enabled); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ButtonCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ButtonCompat.java index 93b3c81..1385f1ad 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ButtonCompat.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ButtonCompat.java
@@ -38,6 +38,7 @@ * Note: To ensure the button's shadow is fully visible, you may need to set * android:clipToPadding="false" on the button's parent view. */ +@TargetApi(Build.VERSION_CODES.LOLLIPOP) public class ButtonCompat extends Button { private static final float PRE_L_PRESSED_BRIGHTNESS = 0.85f;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/RoundedIconGenerator.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/RoundedIconGenerator.java index f615ebf7..e60b2f15 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/RoundedIconGenerator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/RoundedIconGenerator.java
@@ -14,7 +14,6 @@ import android.text.TextPaint; import android.text.TextUtils; import android.util.Log; -import android.util.TypedValue; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.UrlConstants; @@ -51,17 +50,16 @@ * @param iconWidthDp The width of the generated icon in dp. * @param iconHeightDp The height of the generated icon in dp. * @param cornerRadiusDp The radius of the corners in the icon in dp. - * @param backgroundColor Color at which the rounded rectangle should be drawn. - * @param textSizeSp Size at which the text should be drawn in dp. + * @param backgroundColor Color with which the rounded rectangle should be drawn. + * @param textSizeDp Size at which the text should be drawn in dp. */ public RoundedIconGenerator(Context context, int iconWidthDp, int iconHeightDp, - int cornerRadiusDp, int backgroundColor, int textSizeSp) { + int cornerRadiusDp, int backgroundColor, int textSizeDp) { this((int) (context.getResources().getDisplayMetrics().density * iconWidthDp), (int) (context.getResources().getDisplayMetrics().density * iconHeightDp), (int) (context.getResources().getDisplayMetrics().density * cornerRadiusDp), backgroundColor, - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, textSizeSp, - context.getResources().getDisplayMetrics())); + (int) (context.getResources().getDisplayMetrics().density * textSizeDp)); } /**
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 5d2944b..b06634dc 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -890,6 +890,17 @@ Choose an account from your Google Smart Lock. </message> + <!-- DownloadOverwriteInfoBar --> + <message name="IDS_DOWNLOAD_OVERWRITE_INFOBAR_TEXT" desc="Prompt text for the confirmation dialog asking whether the user really wants to replace a file when there already exists a file with the same name"> + Do you want to replace the existing <ph name="FILE_NAME">^1<ex>specialfile.pdf</ex></ph> in your <ph name="DIRECTORY_NAME">^2<ex>Downloads</ex></ph> directory? + </message> + <message name="IDS_DOWNLOAD_OVERWRITE_INFOBAR_REPLACE_FILE_BUTTON" desc="Label for choosing 'Replace file' in the prompt for replacing a file.[CHAR-LIMIT=32]"> + Replace file + </message> + <message name="IDS_DOWNLOAD_OVERWRITE_INFOBAR_CREATE_NEW_FILE_BUTTON" desc="Label for choosing 'Create new file' in the prompt for replacing a file. [CHAR-LIMIT=32]"> + Create new file + </message> + <!-- TranslateInfoBar --> <message name="IDS_TRANSLATE_INFOBAR_TEXT" desc="Text to display on the translate infobar to offer a translate. [CHAR-LIMIT=64]" meaning="Android"> This page is in <ph name="SOURCE_LANGUAGE">^1<ex>English</ex></ph>. Translate it to <ph name="TARGET_LANGUAGE">^2<ex>FRENCH</ex></ph>?
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModelTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModelTest.java new file mode 100644 index 0000000..c4630fd --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModelTest.java
@@ -0,0 +1,229 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.enhanced_bookmarks; + +import android.test.UiThreadTest; +import android.test.suitebuilder.annotation.SmallTest; + +import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.BookmarksBridge.BookmarkItem; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.shell.ChromeShellActivity; +import org.chromium.chrome.shell.ChromeShellTab; +import org.chromium.chrome.shell.ChromeShellTestBase; +import org.chromium.components.bookmarks.BookmarkId; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Stack; + +/** + * Tests for {@link EnhancedBookmarksModel}, the data layer of Enhanced Bookmarks. + */ +public class EnhancedBookmarksModelTest extends ChromeShellTestBase{ + + private ChromeShellActivity mActivity; + private EnhancedBookmarksModel mBookmarksModel; + private BookmarkId mMobileNode; + private BookmarkId mOtherNode; + private BookmarkId mDesktopNode; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mActivity = launchChromeShellWithBlankPage(); + assertTrue(waitForActiveShellToBeDoneLoading()); + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + ChromeShellTab tab = mActivity.getActiveTab(); + Profile profile = tab.getProfile(); + mBookmarksModel = new EnhancedBookmarksModel(profile); + mBookmarksModel.loadEmptyPartnerBookmarkShimForTesting(); + mMobileNode = mBookmarksModel.getMobileFolderId(); + mDesktopNode = mBookmarksModel.getDesktopFolderId(); + mOtherNode = mBookmarksModel.getOtherFolderId(); + } + }); + } + + @UiThreadTest + @SmallTest + @Feature({"Bookmark"}) + public void testGetAllBookmarkIDsOrderedByCreationDate() throws InterruptedException { + BookmarkId folderA = mBookmarksModel.addFolder(mMobileNode, 0, "a"); + BookmarkId folderB = mBookmarksModel.addFolder(mDesktopNode, 0, "b"); + + Stack<BookmarkId> stack = new Stack<BookmarkId>(); + stack.push(mBookmarksModel.addBookmark(folderA, 0, "a", "http://www.medium.com")); + // If add bookmarks too fast, eventually some bookmarks will have the same timestamp, which + // confuses the bookmark model. + Thread.sleep(20); + stack.push(mBookmarksModel.addBookmark(folderB, 0, "b", "http://aurimas.com")); + Thread.sleep(20); + stack.push(mBookmarksModel.addBookmark(mMobileNode, 0, "c", "http://www.aurimas.com")); + Thread.sleep(20); + stack.push(mBookmarksModel.addBookmark(mDesktopNode, 0, "d", "http://www.aurimas.org")); + Thread.sleep(20); + stack.push(mBookmarksModel.addBookmark(mOtherNode, 0, "e", "http://www.google.com")); + Thread.sleep(20); + stack.push(mBookmarksModel.addBookmark(folderA, 0, "f", "http://www.newt.com")); + Thread.sleep(20); + stack.push(mBookmarksModel.addBookmark(folderB, 0, "g", "http://kkimlabs.com")); + + List<BookmarkId> bookmarks = mBookmarksModel.getAllBookmarkIDsOrderedByCreationDate(); + assertEquals(bookmarks.size(), stack.size()); + for (BookmarkId returnedBookmark : bookmarks) { + assertEquals(stack.pop(), returnedBookmark); + } + } + + @UiThreadTest + @SmallTest + @Feature({"Bookmark"}) + public void testBookmarkPropertySetters() { + BookmarkId folderA = mBookmarksModel.addFolder(mMobileNode, 0, "a"); + + BookmarkId bookmarkA = mBookmarksModel.addBookmark(mDesktopNode, 0, "a", "http://a.com"); + BookmarkId bookmarkB = mBookmarksModel.addBookmark(mMobileNode, 0, "a", "http://a.com"); + BookmarkId bookmarkC = mBookmarksModel.addBookmark(mOtherNode, 0, "a", "http://a.com"); + BookmarkId bookmarkD = mBookmarksModel.addBookmark(folderA, 0, "a", "http://a.com"); + + mBookmarksModel.setBookmarkTitle(folderA, "hauri"); + assertEquals("hauri", mBookmarksModel.getBookmarkTitle(folderA)); + + mBookmarksModel.setBookmarkTitle(bookmarkA, "auri"); + mBookmarksModel.setBookmarkUrl(bookmarkA, "http://auri.org/"); + mBookmarksModel.setBookmarkDescription(bookmarkA, "auri"); + verifyBookmark(bookmarkA, "auri", "http://auri.org/", false, mDesktopNode, "auri"); + + mBookmarksModel.setBookmarkTitle(bookmarkB, "lauri"); + mBookmarksModel.setBookmarkUrl(bookmarkB, "http://lauri.org/"); + mBookmarksModel.setBookmarkDescription(bookmarkB, "lauri"); + verifyBookmark(bookmarkB, "lauri", "http://lauri.org/", false, mMobileNode, "lauri"); + + mBookmarksModel.setBookmarkTitle(bookmarkC, "mauri"); + mBookmarksModel.setBookmarkUrl(bookmarkC, "http://mauri.org/"); + mBookmarksModel.setBookmarkDescription(bookmarkC, "mauri"); + verifyBookmark(bookmarkC, "mauri", "http://mauri.org/", false, mOtherNode, "mauri"); + + mBookmarksModel.setBookmarkTitle(bookmarkD, "kauri"); + mBookmarksModel.setBookmarkUrl(bookmarkD, "http://kauri.org/"); + mBookmarksModel.setBookmarkDescription(bookmarkD, "kauri"); + verifyBookmark(bookmarkD, "kauri", "http://kauri.org/", false, folderA, "kauri"); + } + + @UiThreadTest + @SmallTest + @Feature({"Bookmark"}) + public void testMoveBookmarks() { + BookmarkId bookmarkA = mBookmarksModel.addBookmark(mDesktopNode, 0, "a", "http://a.com"); + BookmarkId bookmarkB = mBookmarksModel.addBookmark(mOtherNode, 0, "b", "http://b.com"); + BookmarkId bookmarkC = mBookmarksModel.addBookmark(mMobileNode, 0, "c", "http://c.com"); + BookmarkId folderA = mBookmarksModel.addFolder(mOtherNode, 0, "fa"); + BookmarkId folderB = mBookmarksModel.addFolder(mDesktopNode, 0, "fb"); + BookmarkId folderC = mBookmarksModel.addFolder(mMobileNode, 0, "fc"); + BookmarkId bookmarkAA = mBookmarksModel.addBookmark(folderA, 0, "aa", "http://aa.com"); + BookmarkId bookmarkCA = mBookmarksModel.addBookmark(folderC, 0, "ca", "http://ca.com"); + BookmarkId folderAA = mBookmarksModel.addFolder(folderA, 0, "faa"); + + HashSet<BookmarkId> movedBookmarks = new HashSet<BookmarkId>(6); + movedBookmarks.add(bookmarkA); + movedBookmarks.add(bookmarkB); + movedBookmarks.add(bookmarkC); + movedBookmarks.add(folderC); + movedBookmarks.add(folderB); + movedBookmarks.add(bookmarkAA); + mBookmarksModel.moveBookmarks(new ArrayList<BookmarkId>(movedBookmarks), folderAA); + + // Order of the moved bookmarks is not tested. + verifyBookmarkListNoOrder(mBookmarksModel.getChildIDs(folderAA, true, true), + movedBookmarks); + } + + @UiThreadTest + @SmallTest + @Feature({"Bookmark"}) + public void testGetChildIDs() { + BookmarkId folderA = mBookmarksModel.addFolder(mMobileNode, 0, "fa"); + HashSet<BookmarkId> expectedChildren = new HashSet<>(); + expectedChildren.add(mBookmarksModel.addBookmark(folderA, 0, "a", "http://a.com")); + expectedChildren.add(mBookmarksModel.addBookmark(folderA, 0, "a", "http://a.com")); + expectedChildren.add(mBookmarksModel.addBookmark(folderA, 0, "a", "http://a.com")); + expectedChildren.add(mBookmarksModel.addBookmark(folderA, 0, "a", "http://a.com")); + BookmarkId folderAA = mBookmarksModel.addFolder(folderA, 0, "faa"); + // urls only + verifyBookmarkListNoOrder(mBookmarksModel.getChildIDs(folderA, false, true), + expectedChildren); + // folders only + verifyBookmarkListNoOrder(mBookmarksModel.getChildIDs(folderA, true, false), + new HashSet<BookmarkId>(Arrays.asList(folderAA))); + // folders and urls + expectedChildren.add(folderAA); + verifyBookmarkListNoOrder(mBookmarksModel.getChildIDs(folderA, true, true), + expectedChildren); + } + + // Moved from BookmarksBridgeTest + @UiThreadTest + @SmallTest + @Feature({"Bookmark"}) + public void testAddBookmarksAndFolders() { + BookmarkId bookmarkA = mBookmarksModel.addBookmark(mDesktopNode, 0, "a", "http://a.com"); + verifyBookmark(bookmarkA, "a", "http://a.com/", false, mDesktopNode, ""); + + BookmarkId bookmarkB = mBookmarksModel.addBookmark(mOtherNode, 0, "b", "http://b.com"); + verifyBookmark(bookmarkB, "b", "http://b.com/", false, mOtherNode, ""); + + BookmarkId bookmarkC = mBookmarksModel.addBookmark(mMobileNode, 0, "c", "http://c.com"); + verifyBookmark(bookmarkC, "c", "http://c.com/", false, mMobileNode, ""); + + BookmarkId folderA = mBookmarksModel.addFolder(mOtherNode, 0, "fa"); + verifyBookmark(folderA, "fa", null, true, mOtherNode, ""); + + BookmarkId folderB = mBookmarksModel.addFolder(mDesktopNode, 0, "fb"); + verifyBookmark(folderB, "fb", null, true, mDesktopNode, ""); + + BookmarkId folderC = mBookmarksModel.addFolder(mMobileNode, 0, "fc"); + verifyBookmark(folderC, "fc", null, true, mMobileNode, ""); + + BookmarkId bookmarkAA = mBookmarksModel.addBookmark(folderA, 0, "aa", "http://aa.com"); + verifyBookmark(bookmarkAA, "aa", "http://aa.com/", false, folderA, ""); + + BookmarkId folderAA = mBookmarksModel.addFolder(folderA, 0, "faa"); + verifyBookmark(folderAA, "faa", null, true, folderA, ""); + } + + private void verifyBookmark(BookmarkId idToVerify, String expectedTitle, + String expectedUrl, boolean isFolder, BookmarkId expectedParent, + String expectedDescription) { + assertNotNull(idToVerify); + BookmarkItem item = mBookmarksModel.getBookmarkById(idToVerify); + assertEquals(expectedTitle, item.getTitle()); + assertEquals(isFolder, item.isFolder()); + if (!isFolder) assertEquals(expectedUrl, item.getUrl()); + assertEquals(expectedParent, item.getParentId()); + assertEquals(expectedDescription, mBookmarksModel.getBookmarkDescription(idToVerify)); + } + + /** + * Before using this helper method, always make sure @param listToVerify does not contain + * duplicates. + */ + private void verifyBookmarkListNoOrder(List<BookmarkId> listToVerify, + HashSet<BookmarkId> expectedIds) { + HashSet<BookmarkId> expectedIdsCopy = new HashSet<>(expectedIds); + assertEquals(expectedIdsCopy.size(), listToVerify.size()); + for (BookmarkId id : listToVerify) { + assertNotNull(id); + assertTrue("List contains wrong element: ", expectedIdsCopy.contains(id)); + expectedIdsCopy.remove(id); + } + assertTrue("List does not contain some expected bookmarks: ", expectedIdsCopy.isEmpty()); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java index 5201bd10..072c91369 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java
@@ -7,6 +7,7 @@ import android.app.Notification; import android.graphics.Bitmap; import android.os.Build; +import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; import android.util.SparseArray; @@ -34,7 +35,6 @@ public class NotificationUIManagerTest extends ChromeShellTestBase { private static final String NOTIFICATION_TEST_PAGE = TestHttpServerClient.getUrl("chrome/test/data/notifications/android_test.html"); - private static final String PERMISSION_GRANTED = "\"granted\""; private MockNotificationManagerProxy mMockNotificationManager; @@ -48,7 +48,8 @@ /** * Sets the permission to use Web Notifications for the test HTTP server's origin to |setting|. */ - private void setNotificationContentSettingForCurrentOrigin(final ContentSetting setting) { + private void setNotificationContentSettingForCurrentOrigin(final ContentSetting setting) + throws InterruptedException, TimeoutException { final String origin = getOrigin(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @@ -59,6 +60,15 @@ pushNotificationInfo.setContentSetting(setting); } }); + + String permission = runJavaScriptCodeInCurrentTab("Notification.permission"); + if (setting == ContentSetting.ALLOW) { + assertEquals("\"granted\"", permission); + } else if (setting == ContentSetting.BLOCK) { + assertEquals("\"denied\"", permission); + } else { + assertEquals("\"default\"", permission); + } } /** @@ -133,10 +143,8 @@ @Feature({"Browser", "Notifications"}) public void testDefaultNotificationProperties() throws Exception { setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); - assertEquals(PERMISSION_GRANTED, runJavaScriptCodeInCurrentTab("Notification.permission")); Notification notification = showAndGetNotification("MyNotification", "{ body: 'Hello' }"); - assertNotNull(notification); // Validate the contents of the notification. assertEquals("MyNotification", notification.extras.getString(Notification.EXTRA_TITLE)); @@ -165,10 +173,8 @@ @Feature({"Browser", "Notifications"}) public void testShowNotificationWithIcon() throws Exception { setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); - assertEquals(PERMISSION_GRANTED, runJavaScriptCodeInCurrentTab("Notification.permission")); Notification notification = showAndGetNotification("MyNotification", "{icon: 'icon.png'}"); - assertNotNull(notification); assertEquals("MyNotification", notification.extras.getString(Notification.EXTRA_TITLE)); assertNotNull(notification.largeIcon); @@ -187,10 +193,8 @@ @Feature({"Browser", "Notifications"}) public void testShowNotificationWithoutIcon() throws Exception { setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); - assertEquals(PERMISSION_GRANTED, runJavaScriptCodeInCurrentTab("Notification.permission")); Notification notification = showAndGetNotification("NoIconNotification", "{}"); - assertNotNull(notification); assertEquals("NoIconNotification", notification.extras.getString(Notification.EXTRA_TITLE)); assertNotNull(notification.largeIcon); @@ -207,4 +211,72 @@ assertEquals(generatedIcon.getWidth(), notification.largeIcon.getWidth()); assertEquals(generatedIcon.getHeight(), notification.largeIcon.getHeight()); } + + /* + * Verifies that starting the PendingIntent stored as the notification's delete intent will + * close the notification. + */ + @MediumTest + @Feature({"Browser", "Notifications"}) + public void testNotificationDeleteIntentClosesNotification() throws Exception { + setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); + + Notification notification = showAndGetNotification("MyNotification", "{}"); + assertEquals(1, mMockNotificationManager.getNotifications().size()); + + // Sending the PendingIntent simulates dismissing (swiping away) the notification. + assertNotNull(notification.deleteIntent); + notification.deleteIntent.send(); + // The deleteIntent should trigger a call to cancel() in the NotificationManager. + assertTrue(waitForNotificationManagerMutation()); + + assertEquals(0, mMockNotificationManager.getNotifications().size()); + } + + /* + * Verifies that starting the PendingIntent stored as the notification's content intent will + * start up the associated Service Worker, where the JavaScript code will close the notification + * by calling event.notification.close(). + */ + @LargeTest + @Feature({"Browser", "Notifications"}) + public void testNotificationContentIntentClosesNotification() throws Exception { + setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); + + Notification notification = showAndGetNotification("MyNotification", "{}"); + + // Sending the PendingIntent resembles activating the notification. + assertNotNull(notification.contentIntent); + notification.contentIntent.send(); + + // The Service Worker will close the notification upon receiving the notificationclick + // event. This will eventually bubble up to a call to cancel() in the NotificationManager. + assertTrue(waitForNotificationManagerMutation()); + + SparseArray<Notification> notifications = mMockNotificationManager.getNotifications(); + assertEquals(0, notifications.size()); + } + + /** + * Verifies that creating a notification with an associated "tag" will cause any previous + * notification with the same tag to be dismissed prior to being shown. + */ + @MediumTest + @Feature({"Browser", "Notifications"}) + public void testNotificationTagReplacement() throws Exception { + setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); + + Notification notification = showAndGetNotification("MyNotification", "{tag: 'myTag'}"); + + // Show the second notification with the same tag. We can't use showAndGetNotification for + // this purpose since a second notification would be shown. + runJavaScriptCodeInCurrentTab("showNotification('SecondNotification', {tag: 'myTag'});"); + assertTrue(waitForNotificationManagerMutation()); + + // Verify that the notification was successfully replaced. + SparseArray<Notification> notifications = mMockNotificationManager.getNotifications(); + assertEquals(1, notifications.size()); + assertEquals("SecondNotification", + notifications.valueAt(0).extras.getString(Notification.EXTRA_TITLE)); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTest.java index 9d071cf..9b18925 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTest.java
@@ -9,6 +9,7 @@ import android.net.Uri; import android.test.AndroidTestCase; +import org.chromium.base.CommandLine; import org.chromium.chrome.test.partnercustomizations.TestPartnerBrowserCustomizationsDelayedProvider; import org.chromium.chrome.test.partnercustomizations.TestPartnerBrowserCustomizationsProvider; @@ -50,6 +51,12 @@ } @Override + protected void setUp() throws Exception { + super.setUp(); + CommandLine.init(null); + } + + @Override public Context getContext() { ContextWrapper context = new ContextWrapper(super.getContext()) { @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareUrlTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareUrlTest.java index 8a77bd4..1d78f7d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareUrlTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareUrlTest.java
@@ -26,8 +26,7 @@ } private void assertCorrectUrl(String originalUrl, String sharedUrl) { - Intent intent = ShareHelper.getShareIntent( - getInstrumentation().getTargetContext(), "", sharedUrl, null); + Intent intent = ShareHelper.getShareIntent("", sharedUrl, null); assert (intent.hasExtra(Intent.EXTRA_TEXT)); String url = intent.getStringExtra(Intent.EXTRA_TEXT); assertEquals(originalUrl, url);
diff --git a/chrome/android/shell/chrome_shell_entry_point.cc b/chrome/android/shell/chrome_shell_entry_point.cc new file mode 100644 index 0000000..43880321 --- /dev/null +++ b/chrome/android/shell/chrome_shell_entry_point.cc
@@ -0,0 +1,29 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/android/jni_android.h" +#include "base/bind.h" +#include "chrome/app/android/chrome_jni_onload.h" + +namespace { + +bool RegisterJNI(JNIEnv* env) { + return true; +} + +bool Init() { + return true; +} + +} // namespace + +// This is called by the VM when the shared library is first loaded, +// and used by chrome_shell and chrome_sync_shell. +JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { + if (!chrome::android::OnJNIOnLoadRegisterJNI(vm, base::Bind(&RegisterJNI)) || + !chrome::android::OnJNIOnLoadInit(base::Bind(&Init))) { + return -1; + } + return JNI_VERSION_1_4; +}
diff --git a/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java b/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java index d1fd4ee..687fe99 100644 --- a/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java +++ b/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java
@@ -36,8 +36,6 @@ import org.chromium.chrome.browser.appmenu.AppMenuHandler; import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate; import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils; -import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory; -import org.chromium.chrome.browser.identity.UuidBasedUniqueIdentificationGenerator; import org.chromium.chrome.browser.nfc.BeamController; import org.chromium.chrome.browser.nfc.BeamProvider; import org.chromium.chrome.browser.notifications.NotificationUIManager; @@ -45,7 +43,6 @@ import org.chromium.chrome.browser.printing.PrintingControllerFactory; import org.chromium.chrome.browser.printing.TabPrinter; import org.chromium.chrome.browser.share.ShareHelper; -import org.chromium.chrome.browser.sync.ProfileSyncService; import org.chromium.chrome.browser.sync.SyncController; import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabModelSelector; @@ -70,8 +67,6 @@ public class ChromeShellActivity extends ActionBarActivity implements AppMenuPropertiesDelegate { private static final String TAG = "ChromeShellActivity"; - private static final String SESSIONS_UUID_PREF_KEY = "chromium.sync.sessions.id"; - /** * Factory used to set up a mock ActivityWindowAndroid for testing. */ @@ -195,8 +190,6 @@ mPrintingController = PrintingControllerFactory.create(this); - setupSessionSyncId(); - mSyncController = SyncController.get(this); // In case this method is called after the first onStart(), we need to inform the // SyncController that we have started. @@ -484,19 +477,6 @@ sAppMenuHandlerFactory = factory; } - private void setupSessionSyncId() { - // Ensure that sync uses the correct UniqueIdentificationGenerator, but do not force the - // registration, in case a test case has already overridden it. - UuidBasedUniqueIdentificationGenerator generator = - new UuidBasedUniqueIdentificationGenerator(this, SESSIONS_UUID_PREF_KEY); - UniqueIdentificationGeneratorFactory.registerGenerator( - UuidBasedUniqueIdentificationGenerator.GENERATOR_ID, generator, false); - // Since we do not override the UniqueIdentificationGenerator, we get it from the factory, - // instead of using the instance we just created. - ProfileSyncService.get(this).setSessionsId(UniqueIdentificationGeneratorFactory - .getInstance(UuidBasedUniqueIdentificationGenerator.GENERATOR_ID)); - } - /** * Open a dialog that gives the user the option to sign in from a list of available accounts. *
diff --git a/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellApplication.java b/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellApplication.java index b5abe35..c99e84e9 100644 --- a/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellApplication.java +++ b/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellApplication.java
@@ -11,10 +11,10 @@ import org.chromium.base.ResourceExtractor; import org.chromium.chrome.browser.ChromiumApplication; import org.chromium.chrome.browser.PKCS11AuthenticationManager; -import org.chromium.chrome.browser.UmaUtils; import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory; import org.chromium.chrome.browser.identity.UuidBasedUniqueIdentificationGenerator; import org.chromium.chrome.browser.invalidation.UniqueIdInvalidationClientNameGenerator; +import org.chromium.chrome.browser.metrics.UmaUtils; import org.chromium.chrome.browser.sync.SyncController; import org.chromium.chrome.shell.preferences.ChromeShellPreferences;
diff --git a/chrome/android/shell/res/drawable/progress_bar.xml b/chrome/android/shell/res/drawable/progress_bar.xml deleted file mode 100644 index 58f6b54..0000000 --- a/chrome/android/shell/res/drawable/progress_bar.xml +++ /dev/null
@@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright 2015 The Chromium Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. ---> - -<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:id="@android:id/secondaryProgress"> - <clip android:gravity="left"> - <shape> - <solid android:color="@color/material_deep_teal_200" /> - </shape> - </clip> - </item> - <item android:id="@android:id/progress"> - <clip android:gravity="left"> - <shape> - <solid android:color="@color/material_deep_teal_500" /> - </shape> - </clip> - </item> -</layer-list> \ No newline at end of file
diff --git a/chrome/android/sync_shell/chrome_main_delegate_chrome_sync_shell_android.cc b/chrome/android/sync_shell/chrome_main_delegate_chrome_sync_shell_android.cc index 5016dc88..bcf45e5 100644 --- a/chrome/android/sync_shell/chrome_main_delegate_chrome_sync_shell_android.cc +++ b/chrome/android/sync_shell/chrome_main_delegate_chrome_sync_shell_android.cc
@@ -20,15 +20,20 @@ ~ChromeMainDelegateChromeSyncShellAndroid() { } -bool -ChromeMainDelegateChromeSyncShellAndroid::RegisterApplicationNativeMethods( - JNIEnv* env) { - return ChromeMainDelegateAndroid::RegisterApplicationNativeMethods(env) && - FakeServerHelperAndroid::Register(env); -} - bool ChromeMainDelegateChromeSyncShellAndroid::BasicStartupComplete( int* exit_code) { return ChromeMainDelegateAndroid::BasicStartupComplete(exit_code); } +int ChromeMainDelegateChromeSyncShellAndroid::RunProcess( + const std::string& process_type, + const content::MainFunctionParams& main_function_params) { + if (process_type.empty()) { + // This JNI registration can not be moved to JNI_OnLoad because + // FakeServerHelper seems not known by class loader when shared library + // is loaded. + FakeServerHelperAndroid::Register(base::android::AttachCurrentThread()); + } + return ChromeMainDelegateAndroid::RunProcess(process_type, + main_function_params); +}
diff --git a/chrome/android/sync_shell/chrome_main_delegate_chrome_sync_shell_android.h b/chrome/android/sync_shell/chrome_main_delegate_chrome_sync_shell_android.h index bec75bf0..651a269 100644 --- a/chrome/android/sync_shell/chrome_main_delegate_chrome_sync_shell_android.h +++ b/chrome/android/sync_shell/chrome_main_delegate_chrome_sync_shell_android.h
@@ -13,9 +13,10 @@ ChromeMainDelegateChromeSyncShellAndroid(); ~ChromeMainDelegateChromeSyncShellAndroid() override; - bool RegisterApplicationNativeMethods(JNIEnv* env) override; - bool BasicStartupComplete(int* exit_code) override; + int RunProcess( + const std::string& process_type, + const content::MainFunctionParams& main_function_params) override; private: DISALLOW_COPY_AND_ASSIGN(ChromeMainDelegateChromeSyncShellAndroid);
diff --git a/chrome/app/android/chrome_jni_onload.cc b/chrome/app/android/chrome_jni_onload.cc index a2052da..124e3c2 100644 --- a/chrome/app/android/chrome_jni_onload.cc +++ b/chrome/app/android/chrome_jni_onload.cc
@@ -2,35 +2,48 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/android/jni_android.h" +#include "chrome/app/android/chrome_jni_onload.h" + +#include "base/android/library_loader/library_loader_hooks.h" #include "base/bind.h" #include "chrome/app/android/chrome_android_initializer.h" +#include "chrome/browser/android/chrome_jni_registrar.h" #include "content/public/app/content_jni_onload.h" +namespace chrome { +namespace android { + namespace { bool RegisterJNI(JNIEnv* env) { + if (base::android::GetLibraryProcessType(env) == + base::android::PROCESS_BROWSER) { + return RegisterBrowserJNI(env); + } return true; } bool Init() { - // TODO(michaelbai): Move the JNI registration from RunChrome() to - // RegisterJNI(). return RunChrome(); } } // namespace - -// This is called by the VM when the shared library is first loaded. -JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { +bool OnJNIOnLoadRegisterJNI( + JavaVM* vm, + base::android::RegisterCallback callback) { std::vector<base::android::RegisterCallback> register_callbacks; + register_callbacks.push_back(callback); register_callbacks.push_back(base::Bind(&RegisterJNI)); - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(base::Bind(&Init)); - if (!content::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || - !content::android::OnJNIOnLoadInit(init_callbacks)) { - return -1; - } - return JNI_VERSION_1_4; + return content::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks); } + +bool OnJNIOnLoadInit(base::android::InitCallback callback) { + std::vector<base::android::InitCallback> init_callbacks; + init_callbacks.push_back(callback); + init_callbacks.push_back(base::Bind(&Init)); + return content::android::OnJNIOnLoadInit(init_callbacks); +} + +} // namespace android +} // namespace chrome
diff --git a/chrome/app/android/chrome_jni_onload.h b/chrome/app/android/chrome_jni_onload.h new file mode 100644 index 0000000..7700af8a --- /dev/null +++ b/chrome/app/android/chrome_jni_onload.h
@@ -0,0 +1,22 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_APP_ANDROID_CHROME_JNI_ONLOAD_H_ +#define CHROME_APP_ANDROID_CHROME_JNI_ONLOAD_H_ + +#include "base/android/base_jni_onload.h" + +namespace chrome { +namespace android { + +bool OnJNIOnLoadRegisterJNI( + JavaVM* vm, + base::android::RegisterCallback callback); + +bool OnJNIOnLoadInit(base::android::InitCallback callback); + +} // namespace android +} // namespace chrome + +#endif // CHROME_APP_ANDROID_CHROME_JNI_ONLOAD_H_
diff --git a/chrome/app/android/chrome_main_delegate_android.cc b/chrome/app/android/chrome_main_delegate_android.cc index e0bd8e4..81cf6db 100644 --- a/chrome/app/android/chrome_main_delegate_android.cc +++ b/chrome/app/android/chrome_main_delegate_android.cc
@@ -6,9 +6,8 @@ #include "base/android/jni_android.h" #include "base/trace_event/trace_event.h" -#include "chrome/browser/android/chrome_jni_registrar.h" #include "chrome/browser/android/chrome_startup_flags.h" -#include "chrome/browser/android/uma_utils.h" +#include "chrome/browser/android/metrics/uma_utils.h" #include "components/startup_metric_utils/startup_metric_utils.h" #include "content/public/browser/browser_main_runner.h" @@ -31,9 +30,6 @@ const content::MainFunctionParams& main_function_params) { TRACE_EVENT0("startup", "ChromeMainDelegateAndroid::RunProcess") if (process_type.empty()) { - JNIEnv* env = base::android::AttachCurrentThread(); - RegisterApplicationNativeMethods(env); - // Because the browser process can be started asynchronously as a series of // UI thread tasks a second request to start it can come in while the // first request is still being processed. Chrome must keep the same @@ -55,7 +51,3 @@ SetChromeSpecificCommandLineFlags(); return ChromeMainDelegate::BasicStartupComplete(exit_code); } - -bool ChromeMainDelegateAndroid::RegisterApplicationNativeMethods(JNIEnv* env) { - return chrome::android::RegisterJni(env); -}
diff --git a/chrome/app/android/chrome_main_delegate_android.h b/chrome/app/android/chrome_main_delegate_android.h index 450e53a..d03019c8 100644 --- a/chrome/app/android/chrome_main_delegate_android.h +++ b/chrome/app/android/chrome_main_delegate_android.h
@@ -13,10 +13,6 @@ public: static ChromeMainDelegateAndroid* Create(); - // Set up the JNI bindings. Tie the Java methods with their native - // counterparts. Override to add more JNI bindings. - virtual bool RegisterApplicationNativeMethods(JNIEnv* env); - protected: ChromeMainDelegateAndroid(); ~ChromeMainDelegateAndroid() override;
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index a34c349..f8b04723 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -1985,9 +1985,6 @@ <message name="IDS_OPTIONS_SETTINGS_STORAGE_DESCRIPTION" desc="The 'Storage' button on the chrome://settings page."> Stored data... </message> - <message name="IDS_OPTIONS_SETTINGS_TIME_SYNCED_EXPLANATION" desc="In the settings tab, the text indicating that the date and time are set automatically."> - Date and time are set automatically. - </message> <message name="IDS_OPTIONS_SETTINGS_SET_TIME_BUTTON" desc="In the settings tab, the prompt on the button to open a dialog to set date and time."> Set date and time </message> @@ -6086,4 +6083,7 @@ <message name="IDS_OPTIONS_RESOLVE_TIMEZONE_BY_GEOLOCATION_DESCRIPTION" desc="Label for checkbox to allow automatic timezone update by user geolocation."> Set time zone automatically using your location </message> + <message name="IDS_OPTIONS_CAPTIVE_PORTAL_BYPASS_PROXY_LABEL" desc="Option in chrome://settings that allows Captive Portal authorization pages to ignore proxy settings."> + Allow captive portal sign-in page to bypass proxy servers + </message> </grit-part>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 0e02897d..aff13852 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -1857,10 +1857,26 @@ desc="When starting a download, let the user know we're starting the download."> Starting... </message> + <message name="IDS_DOWNLOAD_STATUS_IN_PROGRESS_TITLE" + desc="."> + Downloading <ph name="FILE_NAME">$1<ex>somedocument.pdf</ex></ph> + </message> + <message name="IDS_DOWNLOAD_STATUS_DOWNLOADED_TITLE" + desc="."> + <ph name="FILE_NAME">$1<ex>somedocument.pdf</ex></ph> downloaded + </message> + <message name="IDS_DOWNLOAD_STATUS_DOWNLOAD_FAILED_TITLE" + desc="."> + <ph name="FILE_NAME">$1<ex>somedocument.pdf</ex></ph> download unsuccessful + </message> <message name="IDS_DOWNLOAD_STATUS_IN_PROGRESS" desc="Size and units downloaded, time remaining."> <ph name="DOWNLOAD_RECEIVED">$1<ex>54/154 MB</ex></ph>, <ph name="TIME_LEFT">$2<ex>5s</ex></ph> </message> + <message name="IDS_DOWNLOAD_STATUS_IN_PROGRESS_WITH_DOMAIN" + desc="Size and units downloaded, time remaining."> + <ph name="DOWNLOAD_RECEIVED">$1<ex>54/154 MB</ex></ph> from <ph name="DOWNLOAD_DOMAIN">$2<ex>example.com</ex></ph>, <ph name="TIME_LEFT">$3<ex>5s</ex></ph> + </message> <message name="IDS_DOWNLOAD_STATUS_SIZES" desc="Size and units downloaded."> <ph name="DOWNLOAD_RECEIVED">$1<ex>54kB</ex></ph>/<ph name="DOWNLOAD_TOTAL">$2<ex>154MB</ex></ph> @@ -6174,12 +6190,6 @@ <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_ENABLE_SWIPE_TO_CLOSE_IN_OVERVIEW_MODE_NAME" desc="Title for the flag to enable swipe gestures to close windows while in overview mode."> - Swipe to dismiss windows in overview mode. - </message> - <message name="IDS_FLAGS_ASH_ENABLE_SWIPE_TO_CLOSE_IN_OVERVIEW_MODE_DESCRIPTION" desc="Description for the flag to enable swipe gestures to close windows while in overview mode."> - Enable swipe gesture to dismiss windows in overview mode. - </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> @@ -6218,6 +6228,12 @@ <message name="IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_DESCRIPTION" desc="Description for the flag to enable the download resume feature."> Allow downloads that have been interrupted to be continued or restarted, using the Resume context menu item. </message> + <message name="IDS_FLAGS_ENABLE_DOWNLOAD_NOTIFICATION_NAME" desc="Title for the flag to enable experimental download notification feature."> + Download Status in Notification Center + </message> + <message name="IDS_FLAGS_ENABLE_DOWNLOAD_NOTIFICATION_DESCRIPTION" desc="Description for the flag to enable experimental download notification feature."> + If enabled, download status is displayed as a notification, instead of an item in download bar. + </message> <message name="IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_NAME" desc="Title for the flag to disable using a software rasterizer."> Disable 3D software rasterizer </message> @@ -9389,7 +9405,7 @@ </message> <message name="IDS_ERRORPAGES_ERROR_CODE" desc="At the bottom of error pages, a non-internationalized string or numeric code is displayed for debugging purposes"> - Error code: <ph name="ERROR_NAME">$1<ex>ERR_FILE_NOT_FOUND</ex></ph> + <ph name="ERROR_NAME">$1<ex>ERR_FILE_NOT_FOUND</ex></ph> </message> <message name="IDS_ERRORPAGES_DETAILS_TIMED_OUT" desc="The error message displayed when a page takes too long to load."> @@ -9998,13 +10014,13 @@ Connect to Wi-Fi </message> <message name="IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_WIRED" desc="The primary explanatory paragraph for the captive portal error page for wired network connections."> - The network you are using may require you to visit <ph name="BEGIN_BOLD"><strong></ph><ph name="LOGIN_URL">$1<ex>example.com</ex></ph><ph name="END_BOLD"><strong></ph>. + The network you are using may require you to visit <ph name="BEGIN_BOLD"><strong></ph><ph name="LOGIN_URL">$1<ex>example.com</ex></ph><ph name="END_BOLD"></strong></ph>. </message> <message name="IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_WIFI" desc="The primary explanatory paragraph for the captive portal error page for Wi-Fi connections."> - The Wi-Fi you are using may require you to visit <ph name="BEGIN_BOLD"><strong></ph><ph name="LOGIN_URL">$1<ex>example.com</ex></ph><ph name="END_BOLD"><strong></ph>. + The Wi-Fi you are using may require you to visit <ph name="BEGIN_BOLD"><strong></ph><ph name="LOGIN_URL">$1<ex>example.com</ex></ph><ph name="END_BOLD"></strong></ph>. </message> <message name="IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_WIFI_SSID" desc="The primary explanatory paragraph for the captive portal error page for Wi-Fi connections, displaying the Wi-Fi name."> - The Wi-Fi you are using (<ph name="WIFI_NAME">$1<ex>Google Guest</ex></ph>) may require you to visit <ph name="BEGIN_BOLD"><strong></ph><ph name="LOGIN_URL">$2<ex>example.com</ex></ph><ph name="END_BOLD"><strong></ph>. + The Wi-Fi you are using (<ph name="WIFI_NAME">$1<ex>Google Guest</ex></ph>) may require you to visit <ph name="BEGIN_BOLD"><strong></ph><ph name="LOGIN_URL">$2<ex>example.com</ex></ph><ph name="END_BOLD"></strong></ph>. </message> <message name="IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_NO_LOGIN_URL_WIRED" desc="The primary explanatory paragraph for the captive portal error page for network connections when the captive portal login url isn't available."> The network you are using may require you to visit its login page. @@ -11185,6 +11201,15 @@ <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_CHECKBOX" desc="Text for checkbox in card unmasking dialog that allows user to store a Wallet card on their local device. If checked, the dialog won't show up again for the given credit card."> Don't ask again for this card </message> + <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_TRY_AGAIN" desc="Error message that encourages the user to try to re-enter their credit card CVC after a previous failed attempt."> + There was a problem verifying your card. Check your information and try again. + </message> + <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_PERMANENT" desc="Error message to show when a credit card cannot be verified and the user isn't allowed to retry."> + Chrome was unable to verify your card at this time. Please try again later. + </message> + <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_NETWORK" desc="Error message to show when a credit card cannot be verified because Wallet servers can't be reached."> + There was a problem verifying your card. Check your internet connection and try again. + </message> <message name="IDS_APPEARANCE_GROUP_NAME" desc="The title of the appearance group"> Appearance
diff --git a/chrome/app/nibs/DownloadItem.xib b/chrome/app/nibs/DownloadItem.xib index a335d69..083ac1e1 100644 --- a/chrome/app/nibs/DownloadItem.xib +++ b/chrome/app/nibs/DownloadItem.xib
@@ -59,7 +59,7 @@ <object class="NSTextField" id="146169749"> <reference key="NSNextResponder" ref="325658281"/> <int key="NSvFlags">290</int> - <string key="NSFrame">{{36, 8}, {261, 22}}</string> + <string key="NSFrame">{{36, 7}, {261, 24}}</string> <reference key="NSSuperview" ref="325658281"/> <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="411206214"/>
diff --git a/chrome/app/theme/default_100_percent/common/downloads/delete-icon.png b/chrome/app/theme/default_100_percent/common/downloads/delete-icon.png new file mode 100644 index 0000000..3b9bdd9 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/downloads/delete-icon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/download-icon.png b/chrome/app/theme/default_100_percent/common/downloads/download-icon.png new file mode 100644 index 0000000..997cd0f --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/downloads/download-icon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/download-small-icon.png b/chrome/app/theme/default_100_percent/common/downloads/download-small-icon.png new file mode 100644 index 0000000..a157ead --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/downloads/download-small-icon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/folder-icon.png b/chrome/app/theme/default_100_percent/common/downloads/folder-icon.png new file mode 100644 index 0000000..a0ef6cf --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/downloads/folder-icon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/incognito-icon.png b/chrome/app/theme/default_100_percent/common/downloads/incognito-icon.png new file mode 100644 index 0000000..5ce64e98 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/downloads/incognito-icon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/malicious-icon.png b/chrome/app/theme/default_100_percent/common/downloads/malicious-icon.png new file mode 100644 index 0000000..01b91159 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/downloads/malicious-icon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/pause-icon.png b/chrome/app/theme/default_100_percent/common/downloads/pause-icon.png new file mode 100644 index 0000000..37218a3 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/downloads/pause-icon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/resume-icon.png b/chrome/app/theme/default_100_percent/common/downloads/resume-icon.png new file mode 100644 index 0000000..318b497 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/downloads/resume-icon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/suspicious-icon.png b/chrome/app/theme/default_100_percent/common/downloads/suspicious-icon.png new file mode 100644 index 0000000..c032111 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/downloads/suspicious-icon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/warning-icon.png b/chrome/app/theme/default_100_percent/common/downloads/warning-icon.png new file mode 100644 index 0000000..36de7cc6 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/downloads/warning-icon.png Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index e10d643a..0e193ffa 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -250,6 +250,15 @@ <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_PROGRESS_FOREGROUND_16" file="common/download_progress_foreground16.png" /> <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_PROGRESS_FOREGROUND_32" file="common/download_progress_foreground32.png" /> <if expr="chromeos"> + <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING" file="common/downloads/download-icon.png" /> + <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_WARNING" file="common/downloads/warning-icon.png" /> + <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MALICIOUS" file="common/downloads/malicious-icon.png" /> + <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_INCOGNITO" file="common/downloads/incognito-icon.png" /> + <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_DELETE" file="common/downloads/delete-icon.png" /> + <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_DOWNLOAD" file="common/downloads/download-small-icon.png" /> + <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_FOLDER" file="common/downloads/folder-icon.png" /> + <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_PAUSE" file="common/downloads/pause-icon.png" /> + <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_RESUME" file="common/downloads/resume-icon.png" /> <structure type="chrome_scaled_image" name="IDR_ENABLE_DEBUGGING_FAILURE" file="cros/enable_debugging_failure.png" /> <structure type="chrome_scaled_image" name="IDR_ENABLE_DEBUGGING_SUCCESS" file="cros/enable_debugging_success.png" /> <structure type="chrome_scaled_image" name="IDR_ENROLL_FAILURE" file="cros/enroll_failure.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 975c68c..a49fd731 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -93,6 +93,7 @@ "//components/enhanced_bookmarks", "//components/favicon_base", "//components/favicon/core", + "//components/feedback", "//components/gcm_driver", "//components/google/core/browser", "//components/handoff", @@ -231,6 +232,7 @@ "//chrome/installer/util", "//components/app_modal", "//components/autofill/content/browser", + "//components/data_reduction_proxy/content/browser", "//components/dom_distiller/content", "//components/history/content/browser", "//components/keyed_service/content", @@ -582,7 +584,6 @@ ".", "//chrome") deps += [ - "//components/feedback", "//device/core", "//device/usb", ] @@ -594,7 +595,6 @@ deps += [ ":jni_headers", "//components/cdm/browser", - "//components/data_reduction_proxy/content/browser", "//components/enhanced_bookmarks", "//components/resources:components_resources", "//components/web_contents_delegate_android", @@ -603,6 +603,7 @@ ] deps -= [ "//third_party/libaddressinput", + "//components/feedback", "//components/storage_monitor", "//components/web_modal", ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 577ad8e..c787e216 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -831,6 +831,13 @@ kOsDesktop, SINGLE_VALUE_TYPE(switches::kEnableDownloadResumption) }, + { + "enable-download-notification", + IDS_FLAGS_ENABLE_DOWNLOAD_NOTIFICATION_NAME, + IDS_FLAGS_ENABLE_DOWNLOAD_NOTIFICATION_DESCRIPTION, + kOsCrOS, + SINGLE_VALUE_TYPE(switches::kEnableDownloadNotification) + }, #if defined(ENABLE_PLUGINS) { "allow-nacl-socket-api", @@ -953,14 +960,6 @@ kOsAll, SINGLE_VALUE_TYPE(ash::switches::kAshDebugShortcuts), }, - { - "ash-enable-swipe-to-close-in-overview-mode", - IDS_FLAGS_ASH_ENABLE_SWIPE_TO_CLOSE_IN_OVERVIEW_MODE_NAME, - IDS_FLAGS_ASH_ENABLE_SWIPE_TO_CLOSE_IN_OVERVIEW_MODE_DESCRIPTION, - // TODO(bruthig): Add kOsWin when http://crbug.com/333758 is resolved. - kOsCrOS, - SINGLE_VALUE_TYPE(ash::switches::kAshEnableSwipeToCloseInOverviewMode), - }, { "ash-enable-touch-view-testing", IDS_FLAGS_ASH_ENABLE_TOUCH_VIEW_TESTING_NAME, IDS_FLAGS_ASH_ENABLE_TOUCH_VIEW_TESTING_DESCRIPTION, @@ -2064,7 +2063,7 @@ IDS_FLAGS_ENABLE_CAPTIVE_PORTAL_BYPASS_PROXY_NAME, IDS_FLAGS_ENABLE_CAPTIVE_PORTAL_BYPASS_PROXY_DESCRIPTION, kOsCrOS, - SINGLE_VALUE_TYPE(chromeos::switches::kEnableCaptivePortalBypassProxy) + SINGLE_VALUE_TYPE(chromeos::switches::kEnableCaptivePortalBypassProxyOption) }, { "disable-roboto-font-ui",
diff --git a/chrome/browser/android/bookmarks/bookmarks_bridge.cc b/chrome/browser/android/bookmarks/bookmarks_bridge.cc index 1ea35d0..8a9a1f3 100644 --- a/chrome/browser/android/bookmarks/bookmarks_bridge.cc +++ b/chrome/browser/android/bookmarks/bookmarks_bridge.cc
@@ -15,7 +15,6 @@ #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_android.h" -#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/undo/bookmark_undo_service.h" #include "chrome/browser/undo/bookmark_undo_service_factory.h" @@ -147,13 +146,15 @@ return IsEnhancedBookmarksEnabled(profile->GetPrefs()); } -static bool IsEditBookmarksEnabled() { - return ProfileManager::GetLastUsedProfile()->GetPrefs()->GetBoolean( +static bool IsEditBookmarksEnabled(Profile* profile) { + return profile->GetPrefs()->GetBoolean( bookmarks::prefs::kEditBookmarksEnabled); } -static jboolean IsEditBookmarksEnabled(JNIEnv* env, jclass clazz) { - return IsEditBookmarksEnabled(); +static jboolean IsEditBookmarksEnabled(JNIEnv* env, + jclass clazz, + jobject j_profile) { + return IsEditBookmarksEnabled(ProfileAndroid::FromProfileAndroid(j_profile)); } void BookmarksBridge::LoadEmptyPartnerBookmarkShimForTesting(JNIEnv* env, @@ -808,7 +809,7 @@ node->type() != BookmarkNode::URL)) { return false; } - if (!IsEditBookmarksEnabled()) + if (!IsEditBookmarksEnabled(profile_)) return false; if (partner_bookmarks_shim_->IsPartnerBookmark(node)) return partner_bookmarks_shim_->IsEditable(node);
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc index 62091e0b6..6e50254 100644 --- a/chrome/browser/android/chrome_jni_registrar.cc +++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -32,6 +32,9 @@ #include "chrome/browser/android/intent_helper.h" #include "chrome/browser/android/location_settings_impl.h" #include "chrome/browser/android/logo_bridge.h" +#include "chrome/browser/android/metrics/uma_bridge.h" +#include "chrome/browser/android/metrics/uma_session_stats.h" +#include "chrome/browser/android/metrics/uma_utils.h" #include "chrome/browser/android/most_visited_sites.h" #include "chrome/browser/android/new_tab_page_prefs.h" #include "chrome/browser/android/omnibox/answers_image_bridge.h" @@ -50,8 +53,6 @@ #include "chrome/browser/android/signin/signin_manager_android.h" #include "chrome/browser/android/tab_android.h" #include "chrome/browser/android/tab_state.h" -#include "chrome/browser/android/uma_bridge.h" -#include "chrome/browser/android/uma_utils.h" #include "chrome/browser/android/url_utilities.h" #include "chrome/browser/android/voice_search_tab_helper.h" #include "chrome/browser/autofill/android/personal_data_manager_android.h" @@ -84,6 +85,7 @@ #include "chrome/browser/ui/android/infobars/app_banner_infobar.h" #include "chrome/browser/ui/android/infobars/confirm_infobar.h" #include "chrome/browser/ui/android/infobars/data_reduction_proxy_infobar.h" +#include "chrome/browser/ui/android/infobars/download_overwrite_infobar.h" #include "chrome/browser/ui/android/infobars/generated_password_saved_infobar.h" #include "chrome/browser/ui/android/infobars/infobar_android.h" #include "chrome/browser/ui/android/infobars/infobar_container_android.h" @@ -116,7 +118,7 @@ {"AppMenuDragHelper", RegisterAppMenuDragHelper}, {"Bookmarks", bookmarks::android::RegisterBookmarks}, {"DomDistiller", dom_distiller::android::RegisterDomDistiller}, - {"ChromeDownloadDelegate", RegisterChromeDownloadDeleagte}, + {"ChromeDownloadDelegate", RegisterChromeDownloadDelegate}, {"GCMDriver", gcm::android::RegisterGCMDriverJni}, {"Invalidation", invalidation::android::RegisterInvalidationJni}, {"NavigationInterception", @@ -166,6 +168,8 @@ {"DomDistillerServiceFactory", dom_distiller::android::DomDistillerServiceFactoryAndroid::Register}, {"DomDistillerTabUtils", RegisterDomDistillerTabUtils}, + {"DownloadOverwriteInfoBarDelegate", + RegisterDownloadOverwriteInfoBarDelegate}, {"EnhancedBookmarksBridge", enhanced_bookmarks::android::RegisterEnhancedBookmarksBridge}, {"ExternalPrerenderRequestHandler", @@ -229,9 +233,9 @@ {"TranslateInfoBarDelegate", RegisterTranslateInfoBarDelegate}, {"TtsPlatformImpl", TtsPlatformImplAndroid::Register}, {"UmaBridge", RegisterUmaBridge}, + {"UmaSessionStats", RegisterUmaSessionStats}, {"UrlUtilities", RegisterUrlUtilities}, {"Variations", variations::android::RegisterVariations}, - {"VoiceSearchTabHelper", RegisterVoiceSearchTabHelper}, {"WebsitePreferenceBridge", RegisterWebsitePreferenceBridge}, {"WebsiteSettingsPopupAndroid", WebsiteSettingsPopupAndroid::RegisterWebsiteSettingsPopupAndroid}, @@ -241,7 +245,7 @@ #endif }; -bool RegisterJni(JNIEnv* env) { +bool RegisterBrowserJNI(JNIEnv* env) { TRACE_EVENT0("startup", "chrome_android::RegisterJni"); return RegisterNativeMethods(env, kChromeRegisteredMethods, arraysize(kChromeRegisteredMethods));
diff --git a/chrome/browser/android/chrome_jni_registrar.h b/chrome/browser/android/chrome_jni_registrar.h index da5339b0..ba5871a1 100644 --- a/chrome/browser/android/chrome_jni_registrar.h +++ b/chrome/browser/android/chrome_jni_registrar.h
@@ -10,8 +10,8 @@ namespace chrome { namespace android { -// Register all JNI bindings necessary for chrome. -bool RegisterJni(JNIEnv* env); +// Register all JNI bindings necessary for chrome browser process. +bool RegisterBrowserJNI(JNIEnv* env); } // namespace android } // namespace chrome
diff --git a/chrome/browser/android/chrome_web_contents_delegate_android.cc b/chrome/browser/android/chrome_web_contents_delegate_android.cc index 8194f89d..ecc988d 100644 --- a/chrome/browser/android/chrome_web_contents_delegate_android.cc +++ b/chrome/browser/android/chrome_web_contents_delegate_android.cc
@@ -371,3 +371,10 @@ return indicator->IsCapturingVideo(web_contents); } +jboolean HasAudibleAudio(JNIEnv* env, + jclass clazz, + jobject java_web_contents) { + content::WebContents* web_contents = + content::WebContents::FromJavaWebContents(java_web_contents); + return web_contents->WasRecentlyAudible(); +}
diff --git a/chrome/browser/android/download/android_download_manager_overwrite_infobar_delegate.cc b/chrome/browser/android/download/android_download_manager_overwrite_infobar_delegate.cc new file mode 100644 index 0000000..7340024 --- /dev/null +++ b/chrome/browser/android/download/android_download_manager_overwrite_infobar_delegate.cc
@@ -0,0 +1,81 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/android/download/android_download_manager_overwrite_infobar_delegate.h" + +#include "base/android/jni_string.h" +#include "base/files/file_util.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/stringprintf.h" +#include "chrome/browser/android/download/chrome_download_delegate.h" +#include "chrome/browser/infobars/infobar_service.h" +#include "chrome/browser/ui/android/infobars/download_overwrite_infobar.h" +#include "components/infobars/core/infobar.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/web_contents.h" + +using base::android::ScopedJavaLocalRef; + +namespace chrome { +namespace android { + +AndroidDownloadManagerOverwriteInfoBarDelegate:: + ~AndroidDownloadManagerOverwriteInfoBarDelegate() { +} + +// static +void AndroidDownloadManagerOverwriteInfoBarDelegate::Create( + InfoBarService* infobar_service, + const std::string& file_name, + const std::string& dir_name, + const std::string& dir_full_path, + jobject chrome_download_delegate, + jobject download_info) { + infobar_service->AddInfoBar(DownloadOverwriteInfoBar::CreateInfoBar( + make_scoped_ptr(new AndroidDownloadManagerOverwriteInfoBarDelegate( + file_name, dir_name, dir_full_path, chrome_download_delegate, + download_info)))); +} + +AndroidDownloadManagerOverwriteInfoBarDelegate:: + AndroidDownloadManagerOverwriteInfoBarDelegate( + const std::string& file_name, + const std::string& dir_name, + const std::string& dir_full_path, + jobject chrome_download_delegate, + jobject download_info) + : file_name_(file_name), + dir_name_(dir_name), + dir_full_path_(dir_full_path) { + JNIEnv* env = base::android::AttachCurrentThread(); + chrome_download_delegate_.Reset(env, chrome_download_delegate); + download_info_.Reset(env, download_info); +} + +void AndroidDownloadManagerOverwriteInfoBarDelegate::OverwriteExistingFile() { + ChromeDownloadDelegate::EnqueueDownloadManagerRequest( + chrome_download_delegate_.obj(), true, download_info_.obj()); +} + +void AndroidDownloadManagerOverwriteInfoBarDelegate::CreateNewFile() { + ChromeDownloadDelegate::EnqueueDownloadManagerRequest( + chrome_download_delegate_.obj(), false, download_info_.obj()); +} + +std::string AndroidDownloadManagerOverwriteInfoBarDelegate::GetFileName() + const { + return file_name_; +} + +std::string AndroidDownloadManagerOverwriteInfoBarDelegate::GetDirName() const { + return dir_name_; +} + +std::string AndroidDownloadManagerOverwriteInfoBarDelegate::GetDirFullPath() + const { + return dir_full_path_; +} + +} // namespace android +} // namespace chrome
diff --git a/chrome/browser/android/download/android_download_manager_overwrite_infobar_delegate.h b/chrome/browser/android/download/android_download_manager_overwrite_infobar_delegate.h new file mode 100644 index 0000000..c36d4a7 --- /dev/null +++ b/chrome/browser/android/download/android_download_manager_overwrite_infobar_delegate.h
@@ -0,0 +1,60 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ANDROID_DOWNLOAD_ANDROID_DOWNLOAD_MANAGER_OVERWRITE_INFOBAR_DELEGATE_H_ +#define CHROME_BROWSER_ANDROID_DOWNLOAD_ANDROID_DOWNLOAD_MANAGER_OVERWRITE_INFOBAR_DELEGATE_H_ + +#include "base/android/jni_weak_ref.h" +#include "base/android/scoped_java_ref.h" +#include "base/callback.h" +#include "base/files/file_path.h" +#include "chrome/browser/android/download/download_overwrite_infobar_delegate.h" +#include "components/infobars/core/infobar_delegate.h" + +class InfoBarService; + +namespace chrome { +namespace android { + +// An infobar delegate that is initiated from Java side. +class AndroidDownloadManagerOverwriteInfoBarDelegate + : public DownloadOverwriteInfoBarDelegate { + public: + ~AndroidDownloadManagerOverwriteInfoBarDelegate() override; + + static void Create(InfoBarService* infobar_service, + const std::string& file_name, + const std::string& dir_name, + const std::string& dir_full_path, + jobject chrome_download_delegate, + jobject download_info); + + private: + AndroidDownloadManagerOverwriteInfoBarDelegate( + const std::string& file_name, + const std::string& dir_name, + const std::string& dir_full_path, + jobject chrome_download_delegate, + jobject download_info); + + // DownloadOverwriteInfoBarDelegate: + void OverwriteExistingFile() override; + void CreateNewFile() override; + std::string GetFileName() const override; + std::string GetDirName() const override; + std::string GetDirFullPath() const override; + + std::string file_name_; + std::string dir_name_; + std::string dir_full_path_; + base::android::ScopedJavaGlobalRef<jobject> chrome_download_delegate_; + base::android::ScopedJavaGlobalRef<jobject> download_info_; + + DISALLOW_COPY_AND_ASSIGN(AndroidDownloadManagerOverwriteInfoBarDelegate); +}; + +} // namespace android +} // namespace chrome + +#endif // CHROME_BROWSER_ANDROID_DOWNLOAD_ANDROID_DOWNLOAD_MANAGER_OVERWRITE_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/android/download/chrome_download_delegate.cc b/chrome/browser/android/download/chrome_download_delegate.cc index 9638297..6f731f5a 100644 --- a/chrome/browser/android/download/chrome_download_delegate.cc +++ b/chrome/browser/android/download/chrome_download_delegate.cc
@@ -9,18 +9,19 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" +#include "base/bind.h" +#include "base/callback.h" #include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/android/download/android_download_manager_overwrite_infobar_delegate.h" #include "chrome/browser/android/tab_android.h" #include "chrome/browser/download/download_extensions.h" +#include "chrome/browser/infobars/infobar_service.h" #include "chrome/grit/generated_resources.h" #include "content/public/browser/android/download_controller_android.h" #include "jni/ChromeDownloadDelegate_jni.h" #include "ui/base/l10n/l10n_util.h" -bool RegisterChromeDownloadDeleagte(JNIEnv* env) { - return RegisterNativesImpl(env); -} - // Gets the download warning text for the given file name. static jstring GetDownloadWarningText( JNIEnv* env, jclass clazz, jstring filename) { @@ -45,3 +46,41 @@ content::DownloadControllerAndroid::Get()->DangerousDownloadValidated( tab_android->web_contents(), download_id, accept); } + +// static +void ChromeDownloadDelegate::EnqueueDownloadManagerRequest( + jobject chrome_download_delegate, + bool overwrite, + jobject download_info) { + JNIEnv* env = base::android::AttachCurrentThread(); + + Java_ChromeDownloadDelegate_enqueueDownloadManagerRequestFromNative( + env, chrome_download_delegate, overwrite, download_info); +} + +// Called when we need to interrupt download and ask users whether to overwrite +// an existing file. +static void LaunchDownloadOverwriteInfoBar(JNIEnv* env, + jclass clazz, + jobject delegate, + jobject tab, + jobject download_info, + jstring jfile_name, + jstring jdir_name, + jstring jdir_full_path) { + TabAndroid* tab_android = TabAndroid::GetNativeTab(env, tab); + + std::string file_name = + base::android::ConvertJavaStringToUTF8(env, jfile_name); + std::string dir_name = base::android::ConvertJavaStringToUTF8(env, jdir_name); + std::string dir_full_path = + base::android::ConvertJavaStringToUTF8(env, jdir_full_path); + + chrome::android::AndroidDownloadManagerOverwriteInfoBarDelegate::Create( + InfoBarService::FromWebContents(tab_android->web_contents()), file_name, + dir_name, dir_full_path, delegate, download_info); +} + +bool RegisterChromeDownloadDelegate(JNIEnv* env) { + return RegisterNativesImpl(env); +}
diff --git a/chrome/browser/android/download/chrome_download_delegate.h b/chrome/browser/android/download/chrome_download_delegate.h index d2674d5..b9bdc91 100644 --- a/chrome/browser/android/download/chrome_download_delegate.h +++ b/chrome/browser/android/download/chrome_download_delegate.h
@@ -6,7 +6,16 @@ #define CHROME_BROWSER_ANDROID_DOWNLOAD_CHROME_DOWNLOAD_DELEGATE_H_ #include "base/android/jni_android.h" +#include "base/android/jni_weak_ref.h" +#include "base/android/scoped_java_ref.h" -bool RegisterChromeDownloadDeleagte(JNIEnv* env); +class ChromeDownloadDelegate { + public: + static void EnqueueDownloadManagerRequest(jobject chrome_download_delegate, + bool overwrite, + jobject download_info); +}; + +bool RegisterChromeDownloadDelegate(JNIEnv* env); #endif // CHROME_BROWSER_ANDROID_DOWNLOAD_CHROME_DOWNLOAD_DELEGATE_H_
diff --git a/chrome/browser/android/download/chrome_download_manager_overwrite_infobar_delegate.cc b/chrome/browser/android/download/chrome_download_manager_overwrite_infobar_delegate.cc new file mode 100644 index 0000000..f4002b4 --- /dev/null +++ b/chrome/browser/android/download/chrome_download_manager_overwrite_infobar_delegate.cc
@@ -0,0 +1,89 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/android/download/chrome_download_manager_overwrite_infobar_delegate.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/files/file_util.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/stringprintf.h" +#include "chrome/browser/infobars/infobar_service.h" +#include "chrome/browser/ui/android/infobars/download_overwrite_infobar.h" +#include "components/infobars/core/infobar.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/web_contents.h" + +namespace chrome { +namespace android { + +ChromeDownloadManagerOverwriteInfoBarDelegate:: + ~ChromeDownloadManagerOverwriteInfoBarDelegate() { +} + +// static +void ChromeDownloadManagerOverwriteInfoBarDelegate::Create( + InfoBarService* infobar_service, + const base::FilePath& suggested_path, + const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback) { + infobar_service->AddInfoBar(DownloadOverwriteInfoBar::CreateInfoBar( + make_scoped_ptr(new ChromeDownloadManagerOverwriteInfoBarDelegate( + suggested_path, callback)))); +} + +ChromeDownloadManagerOverwriteInfoBarDelegate:: + ChromeDownloadManagerOverwriteInfoBarDelegate( + const base::FilePath& suggested_download_path, + const DownloadTargetDeterminerDelegate::FileSelectedCallback& + file_selected_callback) + : suggested_download_path_(suggested_download_path), + file_selected_callback_(file_selected_callback) { +} + +void ChromeDownloadManagerOverwriteInfoBarDelegate::OverwriteExistingFile() { + file_selected_callback_.Run(suggested_download_path_); +} + +void ChromeDownloadManagerOverwriteInfoBarDelegate::CreateNewFile() { + content::BrowserThread::PostTask( + content::BrowserThread::FILE, FROM_HERE, + base::Bind( + &ChromeDownloadManagerOverwriteInfoBarDelegate::CreateNewFileInternal, + suggested_download_path_, file_selected_callback_)); +} + +std::string ChromeDownloadManagerOverwriteInfoBarDelegate::GetFileName() const { + return suggested_download_path_.BaseName().value(); +} + +std::string ChromeDownloadManagerOverwriteInfoBarDelegate::GetDirName() const { + return suggested_download_path_.DirName().BaseName().value(); +} + +std::string ChromeDownloadManagerOverwriteInfoBarDelegate::GetDirFullPath() + const { + return suggested_download_path_.DirName().value(); +} + +void ChromeDownloadManagerOverwriteInfoBarDelegate::InfoBarDismissed() { + file_selected_callback_.Run(base::FilePath()); +} + +void ChromeDownloadManagerOverwriteInfoBarDelegate::CreateNewFileInternal( + const base::FilePath& suggested_download_path, + const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); + int uniquifier = base::GetUniquePathNumber(suggested_download_path, + base::FilePath::StringType()); + base::FilePath new_path = suggested_download_path; + if (uniquifier > 0) { + new_path = suggested_download_path.InsertBeforeExtensionASCII( + base::StringPrintf(" (%d)", uniquifier)); + } + content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, + base::Bind(callback, new_path)); +} + +} // namespace android +} // namespace chrome
diff --git a/chrome/browser/android/download/chrome_download_manager_overwrite_infobar_delegate.h b/chrome/browser/android/download/chrome_download_manager_overwrite_infobar_delegate.h new file mode 100644 index 0000000..30b7f40d --- /dev/null +++ b/chrome/browser/android/download/chrome_download_manager_overwrite_infobar_delegate.h
@@ -0,0 +1,68 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ANDROID_DOWNLOAD_CHROME_DOWNLOAD_MANAGER_OVERWRITE_INFOBAR_DELEGATE_H_ +#define CHROME_BROWSER_ANDROID_DOWNLOAD_CHROME_DOWNLOAD_MANAGER_OVERWRITE_INFOBAR_DELEGATE_H_ + +#include "base/android/scoped_java_ref.h" +#include "base/callback.h" +#include "base/files/file_path.h" +#include "chrome/browser/android/download/download_overwrite_infobar_delegate.h" +#include "chrome/browser/download/download_target_determiner_delegate.h" +#include "components/infobars/core/infobar_delegate.h" + +using base::android::ScopedJavaGlobalRef; + +class InfoBarService; + +namespace chrome { +namespace android { + +// An infobar delegate that starts from the given file path. +class ChromeDownloadManagerOverwriteInfoBarDelegate + : public DownloadOverwriteInfoBarDelegate { + public: + ~ChromeDownloadManagerOverwriteInfoBarDelegate() override; + + static void Create( + InfoBarService* infobar_service, + const base::FilePath& suggested_download_path, + const DownloadTargetDeterminerDelegate::FileSelectedCallback& + file_selected_callback); + + private: + ChromeDownloadManagerOverwriteInfoBarDelegate( + const base::FilePath& suggested_path, + const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback); + + // DownloadOverwriteInfoBarDelegate: + void OverwriteExistingFile() override; + void CreateNewFile() override; + std::string GetFileName() const override; + std::string GetDirName() const override; + std::string GetDirFullPath() const override; + void InfoBarDismissed() override; + + // Called on the FILE thread to create a new file. Calls |callback| on the UI + // thread when finished. + static void CreateNewFileInternal( + const base::FilePath& suggested_download_path, + const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback); + + // The suggested download path from download target determiner. This is used + // to show users the file name and the directory that will be used. + base::FilePath suggested_download_path_; + + // A callback to download target determiner to notify that file selection + // is made (or cancelled). + DownloadTargetDeterminerDelegate::FileSelectedCallback + file_selected_callback_; + + DISALLOW_COPY_AND_ASSIGN(ChromeDownloadManagerOverwriteInfoBarDelegate); +}; + +} // namespace android +} // namespace chrome + +#endif // CHROME_BROWSER_ANDROID_DOWNLOAD_CHROME_DOWNLOAD_MANAGER_OVERWRITE_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/android/download/download_overwrite_infobar_delegate.cc b/chrome/browser/android/download/download_overwrite_infobar_delegate.cc new file mode 100644 index 0000000..61727c92 --- /dev/null +++ b/chrome/browser/android/download/download_overwrite_infobar_delegate.cc
@@ -0,0 +1,16 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/android/download/download_overwrite_infobar_delegate.h" + +namespace chrome { +namespace android { + +bool DownloadOverwriteInfoBarDelegate::ShouldExpire( + const NavigationDetails& details) const { + return false; +} + +} // namespace android +} // namespace chrome
diff --git a/chrome/browser/android/download/download_overwrite_infobar_delegate.h b/chrome/browser/android/download/download_overwrite_infobar_delegate.h new file mode 100644 index 0000000..7d990d93 --- /dev/null +++ b/chrome/browser/android/download/download_overwrite_infobar_delegate.h
@@ -0,0 +1,52 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_OVERWRITE_INFOBAR_DELEGATE_H_ +#define CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_OVERWRITE_INFOBAR_DELEGATE_H_ + +#include "base/android/scoped_java_ref.h" +#include "base/callback.h" +#include "base/files/file_path.h" +#include "chrome/browser/download/download_target_determiner_delegate.h" +#include "components/infobars/core/infobar_delegate.h" + +class InfoBarService; + +namespace chrome { +namespace android { + +// An infobar that asks if it is ok to overwrite an +// existing file. Due to limited disk space on Android, two options are +// presented to the user when downloading a file whose name conflicts with an +// already present file: +// +// 1. Overwrite the file. +// 2. Create a new file. +// +// Also, the user can dismiss the infobar to abort the download. +// +// Note that this infobar does not expire if the user subsequently navigates, +// since such navigations won't automatically cancel the underlying download. +class DownloadOverwriteInfoBarDelegate : public infobars::InfoBarDelegate { + public: + // This is called when the user chooses to overwrite the existing file. + virtual void OverwriteExistingFile() = 0; + + // This is called when the user chooses to create a new file. + virtual void CreateNewFile() = 0; + + // Gets the file name to be downloaded. + virtual std::string GetFileName() const = 0; + // Gets the download directory name. + virtual std::string GetDirName() const = 0; + // Gets the full directory path. + virtual std::string GetDirFullPath() const = 0; + + bool ShouldExpire(const NavigationDetails& details) const override; +}; + +} // namespace android +} // namespace chrome + +#endif // CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_OVERWRITE_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/android/metrics/OWNERS b/chrome/browser/android/metrics/OWNERS new file mode 100644 index 0000000..7755f6b --- /dev/null +++ b/chrome/browser/android/metrics/OWNERS
@@ -0,0 +1,4 @@ +asvitkine@chromium.org +dfalcantara@chromium.org +mariakhomenko@chromium.org +
diff --git a/chrome/browser/android/metrics/uma_bridge.cc b/chrome/browser/android/metrics/uma_bridge.cc new file mode 100644 index 0000000..9577106 --- /dev/null +++ b/chrome/browser/android/metrics/uma_bridge.cc
@@ -0,0 +1,91 @@ +// 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/android/metrics/uma_bridge.h" + +#include <jni.h> + +#include "base/metrics/histogram.h" +#include "content/public/browser/user_metrics.h" +#include "jni/UmaBridge_jni.h" + +using base::UserMetricsAction; +using content::RecordAction; +using content::RecordComputedAction; + +static void RecordMenuShow(JNIEnv*, jclass) { + RecordAction(UserMetricsAction("MobileMenuShow")); +} + +static void RecordUsingMenu(JNIEnv*, + jclass, + jboolean is_by_hw_button, + jboolean is_dragging) { + if (is_by_hw_button) { + if (is_dragging) { + NOTREACHED() << "We do not support dragging for hardware menu button."; + } else { + RecordAction(UserMetricsAction("MobileUsingMenuByHwButtonTap")); + } + } else { + if (is_dragging) { + RecordAction(UserMetricsAction("MobileUsingMenuBySwButtonDragging")); + } else { + RecordAction(UserMetricsAction("MobileUsingMenuBySwButtonTap")); + } + } +} + +// Android Beam + +static void RecordBeamCallbackSuccess(JNIEnv*, jclass) { + RecordAction(UserMetricsAction("MobileBeamCallbackSuccess")); +} + +static void RecordBeamInvalidAppState(JNIEnv*, jclass) { + RecordAction(UserMetricsAction("MobileBeamInvalidAppState")); +} + +// Data Saver + +static void RecordDataReductionProxyTurnedOn(JNIEnv*, jclass) { + RecordAction(UserMetricsAction("DataReductionProxy_TurnedOn")); +} + +static void RecordDataReductionProxyTurnedOff(JNIEnv*, jclass) { + RecordAction(UserMetricsAction("DataReductionProxy_TurnedOff")); +} + +static void RecordDataReductionProxyTurnedOnFromPromo(JNIEnv*, jclass) { + RecordAction(UserMetricsAction("DataReductionProxy_TurnedOnFromPromo")); +} + +static void RecordDataReductionProxyPromoAction( + JNIEnv*, jclass, jint action, jint boundary) { + UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.PromoAction", + action, + boundary); +} + +static void RecordDataReductionProxyPromoDisplayed(JNIEnv*, jclass) { + RecordAction(UserMetricsAction("DataReductionProxy_PromoDisplayed")); +} + +static void RecordDataReductionProxySettings( + JNIEnv*, jclass, jint notification, jint boundary) { + UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.SettingsConversion", + notification, + boundary); +} + +namespace chrome { +namespace android { + +// Register native methods +bool RegisterUmaBridge(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace android +} // namespace chrome
diff --git a/chrome/browser/android/metrics/uma_bridge.h b/chrome/browser/android/metrics/uma_bridge.h new file mode 100644 index 0000000..0badc05d --- /dev/null +++ b/chrome/browser/android/metrics/uma_bridge.h
@@ -0,0 +1,19 @@ +// 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 CHROME_BROWSER_ANDROID_METRICS_UMA_BRIDGE_H_ +#define CHROME_BROWSER_ANDROID_METRICS_UMA_BRIDGE_H_ + +#include <jni.h> + +namespace chrome { +namespace android { + +// Registers the native methods through jni +bool RegisterUmaBridge(JNIEnv* env); + +} // namespace android +} // namespace chrome + +#endif // CHROME_BROWSER_ANDROID_METRICS_UMA_BRIDGE_H_
diff --git a/chrome/browser/android/metrics/uma_session_stats.cc b/chrome/browser/android/metrics/uma_session_stats.cc new file mode 100644 index 0000000..f4b2981 --- /dev/null +++ b/chrome/browser/android/metrics/uma_session_stats.cc
@@ -0,0 +1,199 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/android/metrics/uma_session_stats.h" + +#include "base/android/jni_string.h" +#include "base/command_line.h" +#include "base/metrics/histogram.h" +#include "base/prefs/pref_service.h" +#include "base/strings/string_number_conversions.h" +#include "base/time/time.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/metrics/chrome_metrics_service_accessor.h" +#include "chrome/browser/metrics/metrics_services_manager.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" +#include "chrome/installer/util/google_update_settings.h" +#include "components/metrics/metrics_service.h" +#include "components/variations/metrics_util.h" +#include "components/variations/variations_associated_data.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/user_metrics.h" +#include "jni/UmaSessionStats_jni.h" + +using base::android::ConvertJavaStringToUTF8; +using base::UserMetricsAction; + +namespace { +UmaSessionStats* g_uma_session_stats = NULL; +} // namespace + +UmaSessionStats::UmaSessionStats() + : active_session_count_(0) { +} + +UmaSessionStats::~UmaSessionStats() { +} + +void UmaSessionStats::UmaResumeSession(JNIEnv* env, jobject obj) { + DCHECK(g_browser_process); + + if (active_session_count_ == 0) { + session_start_time_ = base::TimeTicks::Now(); + + // Tell the metrics service that the application resumes. + metrics::MetricsService* metrics = g_browser_process->metrics_service(); + if (metrics) { + metrics->OnAppEnterForeground(); + } + } + ++active_session_count_; +} + +void UmaSessionStats::UmaEndSession(JNIEnv* env, jobject obj) { + --active_session_count_; + DCHECK(active_session_count_ >= 0); + + if (active_session_count_ == 0) { + base::TimeDelta duration = base::TimeTicks::Now() - session_start_time_; + UMA_HISTOGRAM_LONG_TIMES("Session.TotalDuration", duration); + + DCHECK(g_browser_process); + // Tell the metrics service it was cleanly shutdown. + metrics::MetricsService* metrics = g_browser_process->metrics_service(); + if (metrics) { + metrics->OnAppEnterBackground(); + } + } +} + +// static +void UmaSessionStats::RegisterSyntheticFieldTrialWithNameHash( + uint32_t trial_name_hash, + const std::string& group_name) { + ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrialWithNameHash( + trial_name_hash, group_name); +} + +// static +void UmaSessionStats::RegisterSyntheticFieldTrial( + const std::string& trial_name, + const std::string& group_name) { + ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial(trial_name, + group_name); +} + +// Starts/stops the MetricsService when permissions have changed. +// There are three possible states: +// * Logs are being recorded and being uploaded to the server. +// * Logs are being recorded, but not being uploaded to the server. +// This happens when we've got permission to upload on Wi-Fi but we're on a +// mobile connection (for example). +// * Logs are neither being recorded or uploaded. +static void UpdateMetricsServiceState(JNIEnv* env, jobject obj, + jboolean may_record, jboolean may_upload) { + metrics::MetricsService* metrics = g_browser_process->metrics_service(); + DCHECK(metrics); + + if (metrics->recording_active() != may_record) { + // This function puts a consent file with the ClientID in the + // data directory. The ID is passed to the renderer for crash + // reporting when things go wrong. + content::BrowserThread::GetBlockingPool()->PostTask(FROM_HERE, + base::Bind( + base::IgnoreResult(GoogleUpdateSettings::SetCollectStatsConsent), + may_record)); + } + + g_browser_process->GetMetricsServicesManager()->UpdatePermissions( + may_record, may_upload); +} + +// Renderer process crashed in the foreground. +static void LogRendererCrash(JNIEnv* env, jclass clazz, jboolean is_paused) { + DCHECK(g_browser_process); + + if (!is_paused) { + // Increment the renderer crash count in stability metrics. + PrefService* pref = g_browser_process->local_state(); + DCHECK(pref); + int value = pref->GetInteger(prefs::kStabilityRendererCrashCount); + pref->SetInteger(prefs::kStabilityRendererCrashCount, value + 1); + } + + // Note: When we are paused, any UI metric we increment may not make it to + // the disk before we are killed. Treat the count below as a lower bound. + content::RecordAction(base::UserMetricsAction("MobileRendererCrashed")); +} + +static void RegisterExternalExperiment(JNIEnv* env, + jclass clazz, + jint study_id, + jint experiment_id) { + const std::string group_name_utf8 = base::IntToString(experiment_id); + + variations::ActiveGroupId active_group; + active_group.name = static_cast<uint32>(study_id); + active_group.group = metrics::HashName(group_name_utf8); + variations::AssociateGoogleVariationIDForceHashes( + variations::GOOGLE_WEB_PROPERTIES, active_group, + static_cast<variations::VariationID>(experiment_id)); + + UmaSessionStats::RegisterSyntheticFieldTrialWithNameHash( + static_cast<uint32_t>(study_id), group_name_utf8); +} + +static void RegisterSyntheticFieldTrial(JNIEnv* env, + jclass clazz, + jstring jtrial_name, + jstring jgroup_name) { + std::string trial_name(ConvertJavaStringToUTF8(env, jtrial_name)); + std::string group_name(ConvertJavaStringToUTF8(env, jgroup_name)); + UmaSessionStats::RegisterSyntheticFieldTrial(trial_name, group_name); +} + +static void RecordMultiWindowSession(JNIEnv*, jclass, + jint area_percent, + jint instance_count) { + UMA_HISTOGRAM_PERCENTAGE("MobileStartup.MobileMultiWindowSession", + area_percent); + // Make sure the bucket count is the same as the range. This currently + // expects no more than 10 simultaneous multi window instances. + UMA_HISTOGRAM_CUSTOM_COUNTS("MobileStartup.MobileMultiWindowInstances", + instance_count, + 1 /* min */, + 10 /* max */, + 10 /* bucket count */); +} + +static void RecordTabCountPerLoad(JNIEnv*, jclass, jint num_tabs) { + // Record how many tabs total are open. + UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerLoad", num_tabs, 1, 200, 50); +} + +static void RecordPageLoaded(JNIEnv*, jclass, jboolean is_desktop_user_agent) { + // Should be called whenever a page has been loaded. + content::RecordAction(UserMetricsAction("MobilePageLoaded")); + if (is_desktop_user_agent) { + content::RecordAction( + UserMetricsAction("MobilePageLoadedDesktopUserAgent")); + } +} + +static void RecordPageLoadedWithKeyboard(JNIEnv*, jclass) { + content::RecordAction(UserMetricsAction("MobilePageLoadedWithKeyboard")); +} + +static jlong Init(JNIEnv* env, jclass obj) { + // We should have only one UmaSessionStats instance. + DCHECK(!g_uma_session_stats); + g_uma_session_stats = new UmaSessionStats(); + return reinterpret_cast<intptr_t>(g_uma_session_stats); +} + +// Register native methods +bool RegisterUmaSessionStats(JNIEnv* env) { + return RegisterNativesImpl(env); +}
diff --git a/chrome/browser/android/metrics/uma_session_stats.h b/chrome/browser/android/metrics/uma_session_stats.h new file mode 100644 index 0000000..173d342 --- /dev/null +++ b/chrome/browser/android/metrics/uma_session_stats.h
@@ -0,0 +1,45 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ANDROID_METRICS_UMA_SESSION_STATS_H_ +#define CHROME_BROWSER_ANDROID_METRICS_UMA_SESSION_STATS_H_ + +#include <jni.h> +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" + +class UserActionRateCounter; + +// The native part of java UmaSessionStats class. +class UmaSessionStats { + public: + UmaSessionStats(); + + void UmaResumeSession(JNIEnv* env, jobject obj); + void UmaEndSession(JNIEnv* env, jobject obj); + + static void RegisterSyntheticFieldTrialWithNameHash( + uint32_t trial_name_hash, + const std::string& group_name); + + static void RegisterSyntheticFieldTrial( + const std::string& trial_name, + const std::string& group_name); + + private: + ~UmaSessionStats(); + + // Start of the current session, used for UMA. + base::TimeTicks session_start_time_; + int active_session_count_; + + DISALLOW_COPY_AND_ASSIGN(UmaSessionStats); +}; + +// Registers the native methods through jni +bool RegisterUmaSessionStats(JNIEnv* env); + +#endif // CHROME_BROWSER_ANDROID_METRICS_UMA_SESSION_STATS_H_
diff --git a/chrome/browser/android/metrics/uma_utils.cc b/chrome/browser/android/metrics/uma_utils.cc new file mode 100644 index 0000000..12d9f18 --- /dev/null +++ b/chrome/browser/android/metrics/uma_utils.cc
@@ -0,0 +1,24 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/android/metrics/uma_utils.h" + +#include "jni/UmaUtils_jni.h" + +namespace chrome { +namespace android { + +base::Time GetMainEntryPointTime() { + JNIEnv* env = base::android::AttachCurrentThread(); + int64 startTimeUnixMs = Java_UmaUtils_getMainEntryPointTime(env); + return base::Time::UnixEpoch() + + base::TimeDelta::FromMilliseconds(startTimeUnixMs); +} + +bool RegisterStartupMetricUtils(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace android +} // namespace chrome
diff --git a/chrome/browser/android/metrics/uma_utils.h b/chrome/browser/android/metrics/uma_utils.h new file mode 100644 index 0000000..d455b126 --- /dev/null +++ b/chrome/browser/android/metrics/uma_utils.h
@@ -0,0 +1,21 @@ +// 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 CHROME_BROWSER_ANDROID_METRICS_UMA_UTILS_H_ +#define CHROME_BROWSER_ANDROID_METRICS_UMA_UTILS_H_ + +#include <jni.h> + +#include "base/time/time.h" + +namespace chrome { +namespace android { + +base::Time GetMainEntryPointTime(); +bool RegisterStartupMetricUtils(JNIEnv* env); + +} // namespace android +} // namespace chrome + +#endif // CHROME_BROWSER_ANDROID_METRICS_UMA_UTILS_H_
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc index 4512ce6..1ba7a70b 100644 --- a/chrome/browser/android/preferences/pref_service_bridge.cc +++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -104,6 +104,17 @@ return provider == HostContentSettingsMap::POLICY_PROVIDER; } +bool IsContentSettingManagedByCustodian( + ContentSettingsType content_settings_type) { + std::string source; + HostContentSettingsMap* content_settings = + GetOriginalProfile()->GetHostContentSettingsMap(); + content_settings->GetDefaultContentSetting(content_settings_type, &source); + HostContentSettingsMap::ProviderType provider = + content_settings->GetProviderTypeFromSource(source); + return provider == HostContentSettingsMap::SUPERVISED_PROVIDER; +} + bool IsContentSettingUserModifiable(ContentSettingsType content_settings_type) { std::string source; HostContentSettingsMap* content_settings = @@ -230,8 +241,7 @@ } static jboolean GetAllowLocationManagedByCustodian(JNIEnv* env, jobject obj) { - return GetPrefService()->IsPreferenceManagedByCustodian( - prefs::kGeolocationEnabled); + return IsContentSettingManagedByCustodian(CONTENT_SETTINGS_TYPE_GEOLOCATION); } static jboolean GetResolveNavigationErrorEnabled(JNIEnv* env, jobject obj) { @@ -477,12 +487,7 @@ } static jboolean GetCameraMicManagedByCustodian(JNIEnv* env, jobject obj) { - PrefService* prefs = GetPrefService(); - if (prefs->IsPreferenceManagedByCustodian(prefs::kVideoCaptureAllowed)) - return true; - if (prefs->IsPreferenceManagedByCustodian(prefs::kAudioCaptureAllowed)) - return true; - return false; + return IsContentSettingManagedByCustodian(CONTENT_SETTINGS_TYPE_MEDIASTREAM); } static jboolean GetAutologinEnabled(JNIEnv* env, jobject obj) {
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc index 66369ac..e9289de 100644 --- a/chrome/browser/android/tab_android.cc +++ b/chrome/browser/android/tab_android.cc
@@ -12,7 +12,7 @@ #include "cc/layers/layer.h" #include "chrome/browser/android/chrome_web_contents_delegate_android.h" #include "chrome/browser/android/compositor/tab_content_manager.h" -#include "chrome/browser/android/uma_utils.h" +#include "chrome/browser/android/metrics/uma_utils.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/bookmarks/chrome_bookmark_client.h" #include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h"
diff --git a/chrome/browser/android/uma_bridge.cc b/chrome/browser/android/uma_bridge.cc deleted file mode 100644 index 2b27ee5..0000000 --- a/chrome/browser/android/uma_bridge.cc +++ /dev/null
@@ -1,91 +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. - -#include "chrome/browser/android/uma_bridge.h" - -#include <jni.h> - -#include "base/metrics/histogram.h" -#include "content/public/browser/user_metrics.h" -#include "jni/UmaBridge_jni.h" - -using base::UserMetricsAction; -using content::RecordAction; -using content::RecordComputedAction; - -static void RecordMenuShow(JNIEnv*, jclass) { - RecordAction(UserMetricsAction("MobileMenuShow")); -} - -static void RecordUsingMenu(JNIEnv*, - jclass, - jboolean is_by_hw_button, - jboolean is_dragging) { - if (is_by_hw_button) { - if (is_dragging) { - NOTREACHED() << "We do not support dragging for hardware menu button."; - } else { - RecordAction(UserMetricsAction("MobileUsingMenuByHwButtonTap")); - } - } else { - if (is_dragging) { - RecordAction(UserMetricsAction("MobileUsingMenuBySwButtonDragging")); - } else { - RecordAction(UserMetricsAction("MobileUsingMenuBySwButtonTap")); - } - } -} - -// Android Beam - -static void RecordBeamCallbackSuccess(JNIEnv*, jclass) { - RecordAction(UserMetricsAction("MobileBeamCallbackSuccess")); -} - -static void RecordBeamInvalidAppState(JNIEnv*, jclass) { - RecordAction(UserMetricsAction("MobileBeamInvalidAppState")); -} - -// Data Saver - -static void RecordDataReductionProxyTurnedOn(JNIEnv*, jclass) { - RecordAction(UserMetricsAction("DataReductionProxy_TurnedOn")); -} - -static void RecordDataReductionProxyTurnedOff(JNIEnv*, jclass) { - RecordAction(UserMetricsAction("DataReductionProxy_TurnedOff")); -} - -static void RecordDataReductionProxyTurnedOnFromPromo(JNIEnv*, jclass) { - RecordAction(UserMetricsAction("DataReductionProxy_TurnedOnFromPromo")); -} - -static void RecordDataReductionProxyPromoAction( - JNIEnv*, jclass, jint action, jint boundary) { - UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.PromoAction", - action, - boundary); -} - -static void RecordDataReductionProxyPromoDisplayed(JNIEnv*, jclass) { - RecordAction(UserMetricsAction("DataReductionProxy_PromoDisplayed")); -} - -static void RecordDataReductionProxySettings( - JNIEnv*, jclass, jint notification, jint boundary) { - UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.SettingsConversion", - notification, - boundary); -} - -namespace chrome { -namespace android { - -// Register native methods -bool RegisterUmaBridge(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace android -} // namespace chrome
diff --git a/chrome/browser/android/uma_bridge.h b/chrome/browser/android/uma_bridge.h deleted file mode 100644 index c68c841..0000000 --- a/chrome/browser/android/uma_bridge.h +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_ANDROID_UMA_BRIDGE_H_ -#define CHROME_BROWSER_ANDROID_UMA_BRIDGE_H_ - -#include <jni.h> - -namespace chrome { -namespace android { - -// Registers the native methods through jni -bool RegisterUmaBridge(JNIEnv* env); - -} // namespace android -} // namespace chrome - -#endif // CHROME_BROWSER_ANDROID_UMA_BRIDGE_H_
diff --git a/chrome/browser/android/uma_utils.cc b/chrome/browser/android/uma_utils.cc deleted file mode 100644 index 0e9152d..0000000 --- a/chrome/browser/android/uma_utils.cc +++ /dev/null
@@ -1,24 +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. - -#include "chrome/browser/android/uma_utils.h" - -#include "jni/UmaUtils_jni.h" - -namespace chrome { -namespace android { - -base::Time GetMainEntryPointTime() { - JNIEnv* env = base::android::AttachCurrentThread(); - int64 startTimeUnixMs = Java_UmaUtils_getMainEntryPointTime(env); - return base::Time::UnixEpoch() + - base::TimeDelta::FromMilliseconds(startTimeUnixMs); -} - -bool RegisterStartupMetricUtils(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace android -} // namespace chrome
diff --git a/chrome/browser/android/uma_utils.h b/chrome/browser/android/uma_utils.h deleted file mode 100644 index 0853033..0000000 --- a/chrome/browser/android/uma_utils.h +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_ANDROID_UMA_UTILS_H_ -#define CHROME_BROWSER_ANDROID_UMA_UTILS_H_ - -#include <jni.h> - -#include "base/time/time.h" - -namespace chrome { -namespace android { - -base::Time GetMainEntryPointTime(); -bool RegisterStartupMetricUtils(JNIEnv* env); - -} // namespace android -} // namespace chrome - -#endif // CHROME_BROWSER_ANDROID_UMA_UTILS_H_
diff --git a/chrome/browser/android/voice_search_tab_helper.cc b/chrome/browser/android/voice_search_tab_helper.cc index 0edb753..2b3104b 100644 --- a/chrome/browser/android/voice_search_tab_helper.cc +++ b/chrome/browser/android/voice_search_tab_helper.cc
@@ -10,38 +10,36 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/content_switches.h" #include "content/public/common/web_preferences.h" -#include "jni/VoiceSearchTabHelper_jni.h" -using content::WebContents; +DEFINE_WEB_CONTENTS_USER_DATA_KEY(VoiceSearchTabHelper); -// Register native methods -bool RegisterVoiceSearchTabHelper(JNIEnv* env) { - return RegisterNativesImpl(env); +VoiceSearchTabHelper::VoiceSearchTabHelper(content::WebContents* contents) + : content::WebContentsObserver(contents) { + gesture_requirement_for_playback_disabled_ = + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableGestureRequirementForMediaPlayback); } -static void UpdateAutoplayStatus(JNIEnv* env, - jobject obj, - jobject j_web_contents) { +VoiceSearchTabHelper::~VoiceSearchTabHelper() { +} + +void VoiceSearchTabHelper::NavigationEntryCommitted( + const content::LoadCommittedDetails& load_details) { // In the case where media autoplay has been disabled by default (e.g. in // performance media tests) do not update it based on navigation changes. - const base::CommandLine& command_line = - *base::CommandLine::ForCurrentProcess(); - if (command_line.HasSwitch( - switches::kDisableGestureRequirementForMediaPlayback)) + if (gesture_requirement_for_playback_disabled_) return; - WebContents* web_contents = WebContents::FromJavaWebContents(j_web_contents); - content::RenderViewHost* host = web_contents->GetRenderViewHost(); + content::RenderViewHost* host = web_contents()->GetRenderViewHost(); content::WebPreferences prefs = host->GetWebkitPreferences(); bool gesture_required = - !google_util::IsGoogleSearchUrl(web_contents->GetLastCommittedURL()); + !google_util::IsGoogleSearchUrl(web_contents()->GetLastCommittedURL()); if (gesture_required != prefs.user_gesture_required_for_media_playback) { // TODO(chrishtr): this is wrong. user_gesture_required_for_media_playback // will be reset the next time a preference changes. - prefs.user_gesture_required_for_media_playback = - !google_util::IsGoogleSearchUrl(web_contents->GetLastCommittedURL()); + prefs.user_gesture_required_for_media_playback = gesture_required; host->UpdateWebkitPreferences(prefs); } }
diff --git a/chrome/browser/android/voice_search_tab_helper.h b/chrome/browser/android/voice_search_tab_helper.h index 3cf34f0c..c0e6292 100644 --- a/chrome/browser/android/voice_search_tab_helper.h +++ b/chrome/browser/android/voice_search_tab_helper.h
@@ -5,8 +5,28 @@ #ifndef CHROME_BROWSER_ANDROID_VOICE_SEARCH_TAB_HELPER_H_ #define CHROME_BROWSER_ANDROID_VOICE_SEARCH_TAB_HELPER_H_ -#include "base/android/jni_android.h" +#include "base/macros.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" -bool RegisterVoiceSearchTabHelper(JNIEnv* env); +// Tab helper to toggle media autoplay for voice URL searches. +class VoiceSearchTabHelper + : public content::WebContentsObserver, + public content::WebContentsUserData<VoiceSearchTabHelper> { + public: + ~VoiceSearchTabHelper() override; + + // content::WebContentsObserver overrides. + void NavigationEntryCommitted( + const content::LoadCommittedDetails& load_details) override; + + private: + explicit VoiceSearchTabHelper(content::WebContents* contents); + friend class content::WebContentsUserData<VoiceSearchTabHelper>; + + bool gesture_requirement_for_playback_disabled_; + + DISALLOW_COPY_AND_ASSIGN(VoiceSearchTabHelper); +}; #endif // CHROME_BROWSER_ANDROID_VOICE_SEARCH_TAB_HELPER_H_
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index 01feef4d..866f7c0 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -897,7 +897,9 @@ // already loaded a new one, so the pointer needs to be updated; // otherwise we will try to start up a browser window with a pointer // to the old profile. - if (lastProfile_ && profilePath == lastProfile_->GetPath()) + // In a browser test, the application is not brought to the front, so + // |lastProfile_| might be null. + if (!lastProfile_ || profilePath == lastProfile_->GetPath()) lastProfile_ = g_browser_process->profile_manager()->GetLastUsedProfile(); auto it = profileBookmarkMenuBridgeMap_.find(profilePath);
diff --git a/chrome/browser/apps/app_window_interactive_uitest.cc b/chrome/browser/apps/app_window_interactive_uitest.cc index 30247d7..73199034 100644 --- a/chrome/browser/apps/app_window_interactive_uitest.cc +++ b/chrome/browser/apps/app_window_interactive_uitest.cc
@@ -461,6 +461,42 @@ ASSERT_TRUE(RunAppWindowInteractiveTest("testDrawAttention")) << message_; } +IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest, TestCreateHidden) { + // Created hidden both times. + { + ExtensionTestMessageListener launched_listener("Launched", true); + LoadAndLaunchPlatformApp("hidden_with_id", &launched_listener); + EXPECT_TRUE(launched_listener.WaitUntilSatisfied()); + ExtensionTestMessageListener create_listener_1("Launched", true); + launched_listener.Reply("createHidden"); + EXPECT_TRUE(create_listener_1.WaitUntilSatisfied()); + AppWindow* app_window = GetFirstAppWindow(); + EXPECT_TRUE(app_window->is_hidden()); + ExtensionTestMessageListener create_listener_2("Launched", false); + create_listener_1.Reply("createHidden"); + EXPECT_TRUE(create_listener_2.WaitUntilSatisfied()); + EXPECT_TRUE(app_window->is_hidden()); + app_window->GetBaseWindow()->Close(); + } + + // Created hidden, then visible. The second create should show the window. + { + ExtensionTestMessageListener launched_listener("Launched", true); + LoadAndLaunchPlatformApp("hidden_with_id", &launched_listener); + EXPECT_TRUE(launched_listener.WaitUntilSatisfied()); + ExtensionTestMessageListener create_listener_1("Launched", true); + launched_listener.Reply("createHidden"); + EXPECT_TRUE(create_listener_1.WaitUntilSatisfied()); + AppWindow* app_window = GetFirstAppWindow(); + EXPECT_TRUE(app_window->is_hidden()); + ExtensionTestMessageListener create_listener_2("Launched", false); + create_listener_1.Reply("createVisible"); + EXPECT_TRUE(create_listener_2.WaitUntilSatisfied()); + EXPECT_FALSE(app_window->is_hidden()); + app_window->GetBaseWindow()->Close(); + } +} + // Only Linux and Windows use keep-alive to determine when to shut down. #if defined(OS_LINUX) || defined(OS_WIN)
diff --git a/chrome/browser/apps/custom_launcher_page_browsertest_views.cc b/chrome/browser/apps/custom_launcher_page_browsertest_views.cc index 8f4fb35..00e3484 100644 --- a/chrome/browser/apps/custom_launcher_page_browsertest_views.cc +++ b/chrome/browser/apps/custom_launcher_page_browsertest_views.cc
@@ -20,8 +20,11 @@ #include "ui/app_list/views/app_list_main_view.h" #include "ui/app_list/views/app_list_view.h" #include "ui/app_list/views/contents_view.h" +#include "ui/app_list/views/search_box_view.h" #include "ui/events/test/event_generator.h" +#include "ui/views/controls/textfield/textfield.h" #include "ui/views/controls/webview/webview.h" +#include "ui/views/focus/focus_manager.h" namespace { @@ -383,3 +386,51 @@ EXPECT_TRUE(model->custom_launcher_page_enabled()); EXPECT_TRUE(custom_page_view->visible()); } + +// Currently this fails on ChromeOS +// Disabled test http://crbug.com/463456 +#if defined(OS_CHROMEOS) +#define MAYBE_LauncherPageFocusTraversal DISABLED_LauncherPageFocusTraversal +#else +#define MAYBE_LauncherPageFocusTraversal LauncherPageFocusTraversal +#endif + +IN_PROC_BROWSER_TEST_F(CustomLauncherPageBrowserTest, + MAYBE_LauncherPageFocusTraversal) { + LoadAndLaunchPlatformApp(kCustomLauncherPagePath, "Launched"); + app_list::AppListView* app_list_view = GetAppListView(); + app_list::ContentsView* contents_view = + app_list_view->app_list_main_view()->contents_view(); + app_list::SearchBoxView* search_box_view = + app_list_view->app_list_main_view()->search_box_view(); + + ASSERT_TRUE( + contents_view->IsStateActive(app_list::AppListModel::STATE_START)); + EXPECT_EQ(app_list_view->GetFocusManager()->GetFocusedView(), + search_box_view->search_box()); + + { + ExtensionTestMessageListener listener("onPageProgressAt1", false); + contents_view->SetActivePage(contents_view->GetPageIndexForState( + app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE)); + listener.WaitUntilSatisfied(); + EXPECT_TRUE(contents_view->IsStateActive( + app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE)); + EXPECT_EQ(app_list_view->GetFocusManager()->GetFocusedView(), + search_box_view->search_box()); + } + { + ExtensionTestMessageListener listener("textfieldFocused", false); + app_list_view->GetFocusManager()->AdvanceFocus(false); + listener.WaitUntilSatisfied(); + EXPECT_NE(app_list_view->GetFocusManager()->GetFocusedView(), + search_box_view->search_box()); + } + { + ExtensionTestMessageListener listener("textfieldBlurred", false); + app_list_view->GetFocusManager()->AdvanceFocus(false); + listener.WaitUntilSatisfied(); + EXPECT_EQ(app_list_view->GetFocusManager()->GetFocusedView(), + search_box_view->search_box()); + } +}
diff --git a/chrome/browser/apps/ephemeral_app_browsertest.cc b/chrome/browser/apps/ephemeral_app_browsertest.cc index 04c96fe..fd1d298 100644 --- a/chrome/browser/apps/ephemeral_app_browsertest.cc +++ b/chrome/browser/apps/ephemeral_app_browsertest.cc
@@ -23,7 +23,7 @@ #include "content/public/browser/power_save_blocker.h" #include "content/public/test/browser_test.h" #include "content/public/test/test_utils.h" -#include "extensions/browser/api/power/power_api_manager.h" +#include "extensions/browser/api/power/power_api.h" #include "extensions/browser/app_sorting.h" #include "extensions/browser/event_router.h" #include "extensions/browser/extension_prefs.h" @@ -1028,9 +1028,7 @@ // chrome.power.releaseKeepAwake() themselves. IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, ReleasePowerKeepAwake) { PowerSettingsMock power_settings; - extensions::PowerApiManager* power_manager = - extensions::PowerApiManager::Get(profile()); - power_manager->SetCreateBlockerFunctionForTesting( + extensions::PowerAPI::Get(profile())->SetCreateBlockerFunctionForTesting( base::Bind(&PowerSaveBlockerStub::Create, &power_settings)); const Extension* app = InstallAndLaunchEphemeralApp(kPowerTestApp);
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc index bec47cb..ca29991 100644 --- a/chrome/browser/apps/guest_view/web_view_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -925,14 +925,6 @@ TestHelper("testWebRequestAPIExistence", "web_view/shim", NO_TEST_SERVER); } -// Tests the existence of DeclarativeContent API event objects on the request -// object, on the webview element, and hanging directly off webview. -IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestDeclarativeContentAPIExistence) { - TestHelper("testDeclarativeContentAPIExistence", - "web_view/shim", - NO_TEST_SERVER); -} - // http://crbug.com/315920 #if defined(GOOGLE_CHROME_BUILD) && (defined(OS_WIN) || defined(OS_LINUX)) #define MAYBE_Shim_TestChromeExtensionURL DISABLED_Shim_TestChromeExtensionURL
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc index 455325b..52bcb4d 100644 --- a/chrome/browser/autofill/form_structure_browsertest.cc +++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -46,16 +46,6 @@ } const std::vector<base::FilePath> GetTestFiles() { - static const base::FilePath::CharType* const kFilesToSkip[] = { - FILE_PATH_LITERAL("bug_459132.html"), - FILE_PATH_LITERAL("bug_454366b.html"), - FILE_PATH_LITERAL("bug_454366.html"), - FILE_PATH_LITERAL("25_checkout_m_llbean.com.html"), - }; - std::set<base::FilePath> set_of_files_to_skip; - for (size_t i = 0; i < arraysize(kFilesToSkip); ++i) - set_of_files_to_skip.insert(base::FilePath(kFilesToSkip[i])); - base::FilePath dir; CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &dir)); dir = dir.AppendASCII("chrome/test/data/autofill") @@ -65,8 +55,7 @@ std::vector<base::FilePath> files; for (base::FilePath input_file = input_files.Next(); !input_file.empty(); input_file = input_files.Next()) { - if (!ContainsKey(set_of_files_to_skip, input_file.BaseName())) - files.push_back(input_file); + files.push_back(input_file); } std::sort(files.begin(), files.end());
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h index 59446743..29ab9b4 100644 --- a/chrome/browser/browser_process.h +++ b/chrome/browser/browser_process.h
@@ -34,6 +34,7 @@ class PrefService; class Profile; class ProfileManager; +class PromoResourceService; class SafeBrowsingService; class StatusTray; class WatchDogThread; @@ -125,6 +126,7 @@ virtual PrefService* local_state() = 0; virtual net::URLRequestContextGetter* system_request_context() = 0; virtual chrome_variations::VariationsService* variations_service() = 0; + virtual PromoResourceService* promo_resource_service() = 0; virtual BrowserProcessPlatformPart* platform_part() = 0;
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index 2f86717..31a2dbc 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc
@@ -570,6 +570,11 @@ return GetMetricsServicesManager()->GetVariationsService(); } +PromoResourceService* BrowserProcessImpl::promo_resource_service() { + DCHECK(CalledOnValidThread()); + return promo_resource_service_.get(); +} + BrowserProcessPlatformPart* BrowserProcessImpl::platform_part() { return platform_part_.get(); }
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h index 9122d8f0..4a53a92 100644 --- a/chrome/browser/browser_process_impl.h +++ b/chrome/browser/browser_process_impl.h
@@ -86,6 +86,7 @@ PrefService* local_state() override; net::URLRequestContextGetter* system_request_context() override; chrome_variations::VariationsService* variations_service() override; + PromoResourceService* promo_resource_service() override; BrowserProcessPlatformPart* platform_part() override; extensions::EventRouterForwarder* extension_event_router_forwarder() override; NotificationUIManager* notification_ui_manager() override;
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index b0ce0fd..0bb67a8 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -69,8 +69,6 @@ <structure name="IDR_KEYBOARD_UTILS_JS" file="resources\chromeos\keyboard\keyboard_utils.js" flattenhtml="true" type="chrome_html" /> <structure name="IDR_CUSTOM_ELEMENTS_HTML" file="resources\chromeos\login\custom_elements.html" flattenhtml="true" type="chrome_html" /> <structure name="IDR_CUSTOM_ELEMENTS_JS" file="resources\chromeos\login\custom_elements.js" flattenhtml="true" type="chrome_html" /> - <structure name="IDR_NEW_OOBE_HTML" file="resources\chromeos\login\new\oobe.html" flattenhtml="true" type="chrome_html" variables="OOBE=oobe" expand_variables="true"/> - <structure name="IDR_NEW_OOBE_JS" file="resources\chromeos\login\new\oobe.js" flattenhtml="true" type="chrome_html" /> </if> <structure name="IDR_READER_OUT_OF_DATE_HTML" file="resources\reader_out_of_date.html" flattenhtml="true" type="chrome_html" /> <structure name="IDR_SECURITY_INTERSTITIAL_UI_HTML" file="resources\security_warnings\interstitial_ui.html" flattenhtml="true" type="chrome_html" />
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 3af4c61..d0e92847 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -144,18 +144,18 @@ #include "chrome/browser/metrics/thread_watcher_android.h" #else #include "chrome/browser/feedback/feedback_profile_observer.h" -#endif +#endif // defined(OS_ANDROID) #if defined(OS_LINUX) && !defined(OS_CHROMEOS) #include "chrome/browser/first_run/upgrade_util_linux.h" #include "chrome/browser/sxs_linux.h" -#endif +#endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chromeos/chromeos_switches.h" #include "chromeos/settings/cros_settings_names.h" -#endif +#endif // defined(OS_CHROMEOS) // TODO(port): several win-only methods have been pulled out of this, but // BrowserMain() as a whole needs to be broken apart so that it's usable by @@ -188,38 +188,38 @@ #include "base/mac/scoped_nsautorelease_pool.h" #include "chrome/browser/mac/keystone_glue.h" -#endif +#endif // defined(OS_MACOSX) #if !defined(OS_IOS) #include "chrome/browser/ui/app_modal/chrome_javascript_native_dialog_factory.h" -#endif +#endif // !defined(OS_IOS) #if !defined(DISABLE_NACL) #include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h" #include "components/nacl/browser/nacl_process_host.h" -#endif +#endif // !defined(DISABLE_NACL) #if defined(ENABLE_EXTENSIONS) #include "chrome/browser/extensions/startup_helper.h" #include "extensions/browser/extension_protocols.h" #include "extensions/components/javascript_dialog_extensions_client/javascript_dialog_extension_client_impl.h" -#endif +#endif // defined(ENABLE_EXTENSIONS) #if defined(ENABLE_PRINT_PREVIEW) && !defined(OFFICIAL_BUILD) #include "printing/printed_document.h" -#endif +#endif // defined(ENABLE_PRINT_PREVIEW) && !defined(OFFICIAL_BUILD) #if defined(ENABLE_RLZ) #include "chrome/browser/rlz/rlz.h" -#endif +#endif // defined(ENABLE_RLZ) #if defined(ENABLE_WEBRTC) #include "chrome/browser/media/webrtc_log_util.h" -#endif +#endif // defined(ENABLE_WEBRTC) #if defined(USE_AURA) #include "ui/aura/env.h" -#endif +#endif // defined(USE_AURA) using content::BrowserThread; @@ -318,7 +318,7 @@ local_state->SetString(prefs::kApplicationLocale, owner_locale); } } -#endif +#endif // defined(OS_CHROMEOS) return local_state; } @@ -379,7 +379,7 @@ profile = g_browser_process->profile_manager()->GetProfile( ProfileManager::GetGuestProfilePath()); } -#endif +#endif // defined(OS_CHROMEOS) || defined(OS_ANDROID) if (profile) { UMA_HISTOGRAM_LONG_TIMES( "Startup.CreateFirstProfile", base::Time::Now() - start); @@ -391,7 +391,7 @@ // user_data_dir. It is better to CHECK-fail here than it is to // silently exit because of missing code in the above test. CHECK(profile) << "Cannot get default profile."; -#endif +#endif // !defined(OS_WIN) return NULL; } @@ -401,7 +401,7 @@ SecKeychainCallbackInfo* info, void* context) { return noErr; } -#endif +#endif // defined(OS_MACOSX) void RegisterComponentsForUpdate() { component_updater::ComponentUpdateService* cus = @@ -415,7 +415,7 @@ RegisterPepperFlashComponent(cus); RegisterSwiftShaderComponent(cus); RegisterWidevineCdmComponent(cus); -#endif +#endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID) #if !defined(DISABLE_NACL) && !defined(OS_ANDROID) #if defined(OS_CHROMEOS) @@ -423,9 +423,9 @@ // Chrome4ChromeOS on Linux doesn't contain PNaCl so enable component // installer when running on Linux. See crbug.com/422121 for more details. if (!base::SysInfo::IsRunningOnChromeOS()) -#endif +#endif // defined(OS_CHROMEOS) g_browser_process->pnacl_component_installer()->RegisterPnaclComponent(cus); -#endif +#endif // !defined(DISABLE_NACL) && !defined(OS_ANDROID) // Registration of the CLD Component is a no-op unless the CLD data source has // been configured to be the "Component" data source. @@ -450,13 +450,13 @@ // 1. Android: Because it currently does not have the EV indicator. // 2. Chrome OS: On Chrome OS this registration is delayed until user login. RegisterEVWhitelistComponent(cus, path); -#endif +#endif // defined(OS_ANDROID) } #if defined(OS_WIN) RegisterSwReporterComponent(cus, g_browser_process->local_state()); RegisterCAPSComponent(cus); -#endif +#endif // defined(OS_WIN) cus->Start(); } @@ -471,7 +471,7 @@ browser_watcher::ExitFunnel::RecordSingleEvent( chrome::kBrowserExitCodesRegistryPath, L"ProcessSingletonIsShuttingDown"); -#endif +#endif // defined(OS_WIN) return false; } @@ -556,13 +556,13 @@ // localization data files. #if defined(OS_WIN) const char kMissingLocaleDataTitle[] = "Missing File Error"; -#endif +#endif // defined(OS_WIN) #if defined(OS_WIN) // TODO(port) This should be used on Linux Aura as well. http://crbug.com/338969 const char kMissingLocaleDataMessage[] = "Unable to find locale data files. Please reinstall."; -#endif +#endif // defined(OS_WIN) } // namespace chrome_browser @@ -702,7 +702,7 @@ bool is_first_run = false; #else bool is_first_run = first_run::IsChromeFirstRun(); -#endif +#endif // defined(OS_ANDROID) // CurrentProcessInfo::CreationTime() is currently only implemented on some // platforms. @@ -787,7 +787,7 @@ // These members must be initialized before exiting this function normally. DCHECK(master_prefs_.get()); DCHECK(browser_creator_.get()); -#endif +#endif // !defined(OS_ANDROID) for (size_t i = 0; i < chrome_extra_parts_.size(); ++i) chrome_extra_parts_[i]->PreCreateThreads(); } @@ -800,7 +800,7 @@ run_message_loop_ = false; #if !defined(OS_ANDROID) chrome::MaybeShowInvalidUserDataDirWarningDialog(); -#endif +#endif // !defined(OS_ANDROID) if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir_)) return chrome::RESULT_CODE_MISSING_DATA; @@ -814,7 +814,7 @@ // Cache first run state early. first_run::IsChromeFirstRun(); -#endif +#endif // !defined(OS_ANDROID) scoped_refptr<base::SequencedTaskRunner> local_state_task_runner = JsonPrefStore::GetTaskRunnerForFile( @@ -860,7 +860,7 @@ browser_creator_.reset(new StartupBrowserCreator); // TODO(yfriedman): Refactor Android to re-use UMABrowsingActivityObserver chrome::UMABrowsingActivityObserver::Init(); -#endif +#endif // !defined(OS_ANDROID) #if !defined(OS_CHROMEOS) // Convert active labs into switches. This needs to be done before @@ -877,7 +877,7 @@ base::CommandLine::ForCurrentProcess(), about_flags::kAddSentinels); } -#endif +#endif // !defined(OS_CHROMEOS) local_state_->UpdateCommandLinePrefStore( new CommandLinePrefStore(base::CommandLine::ForCurrentProcess())); @@ -982,13 +982,13 @@ master_prefs_->suppress_default_browser_prompt_for_version); } } -#endif +#endif // !defined(OS_ANDROID) && !defined(OS_CHROMEOS) #if defined(OS_LINUX) || defined(OS_OPENBSD) || defined(OS_MACOSX) // Set the product channel for crash reports. base::debug::SetCrashKeyValue(crash_keys::kChannel, chrome::VersionInfo::GetVersionStringModifier()); -#endif +#endif // defined(OS_LINUX) || defined(OS_OPENBSD) || defined(OS_MACOSX) // Initialize tracking synchronizer system. tracking_synchronizer_ = new metrics::TrackingSynchronizer(); @@ -1001,13 +1001,13 @@ // (Note that the callback mask here is empty. I don't want to register for // any callbacks, I just want to initialize the mechanism.) SecKeychainAddCallback(&KeychainCallback, 0, NULL); -#endif +#endif // defined(OS_MACOSX) #if defined(OS_CHROMEOS) // Must be done after g_browser_process is constructed, before // SetupMetricsAndFieldTrials(). chromeos::CrosSettings::Initialize(); -#endif +#endif // defined(OS_CHROMEOS) // Now the command line has been mutated based on about:flags, we can setup // metrics and initialize field trials. The field trials are needed by @@ -1073,15 +1073,15 @@ BrowserThread::FILE, FROM_HERE, base::Bind(&ProfileManager::CleanUpStaleProfiles, profiles_to_delete)); } -#endif // OS_ANDROID +#endif // !defined(OS_ANDROID) #if defined(ENABLE_EXTENSIONS) javascript_dialog_extensions_client::InstallClient(); -#endif +#endif // defined(ENABLE_EXTENSIONS) #if !defined(OS_IOS) InstallChromeJavaScriptNativeDialogFactory(); -#endif +#endif // !defined(OS_IOS) } void ChromeBrowserMainParts::PostProfileInit() { @@ -1106,7 +1106,7 @@ #if !defined(OS_ANDROID) // Allow ProcessSingleton to process messages. process_singleton_->Unlock(); -#endif +#endif // !defined(OS_ANDROID) #if defined(ENABLE_WEBRTC) // Set up a task to delete old WebRTC log files for all profiles. Use a delay // to reduce the impact on startup time. @@ -1115,18 +1115,19 @@ FROM_HERE, base::Bind(&WebRtcLogUtil::DeleteOldWebRtcLogFilesForAllProfiles), base::TimeDelta::FromMinutes(1)); -#endif +#endif // defined(ENABLE_WEBRTC) } int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() { TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreMainMessageLoopRunImpl"); SCOPED_UMA_HISTOGRAM_LONG_TIMER("Startup.PreMainMessageLoopRunImplLongTime"); + const base::TimeTicks start_time_step1 = base::TimeTicks::Now(); // Android updates the metrics service dynamically depending on whether the // application is in the foreground or not. Do not start here. #if !defined(OS_ANDROID) // Now that the file thread has been started, start recording. StartMetricsRecording(); -#endif +#endif // !defined(OS_ANDROID) if (!base::debug::BeingDebugged()) { // Create watchdog thread after creating all other threads because it will @@ -1161,7 +1162,7 @@ ui::SelectFileDialog::SetFactory(new ChromeSelectFileDialogFactory( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))); -#endif +#endif // defined(OS_WIN) if (parsed_command_line().HasSwitch(switches::kMakeDefaultBrowser)) { return ShellIntegration::SetAsDefaultBrowser() ? @@ -1172,7 +1173,7 @@ #if defined(USE_AURA) // Make sure aura::Env has been initialized. CHECK(aura::Env::GetInstance()); -#endif +#endif // defined(USE_AURA) // Android doesn't support extensions and doesn't implement ProcessSingleton. #if !defined(OS_ANDROID) @@ -1203,9 +1204,11 @@ case ProcessSingleton::PROCESS_NOTIFIED: #if defined(OS_POSIX) && !defined(OS_MACOSX) + // On POSIX systems, print a message notifying the process is running. printf("%s\n", base::SysWideToNativeMB(base::UTF16ToWide( l10n_util::GetStringUTF16(IDS_USED_EXISTING_BROWSER))).c_str()); -#endif +#endif // defined(OS_POSIX) && !defined(OS_MACOSX) + // Having a differentiated return type for testing allows for tests to // verify proper handling of some switches. When not testing, stick to // the standard Unix convention of returning zero when things went as @@ -1293,6 +1296,12 @@ metrics::MetricsService::SetExecutionPhase( metrics::MetricsService::CREATE_PROFILE, g_browser_process->local_state()); + + UMA_HISTOGRAM_TIMES("Startup.PreMainMessageLoopRunImplStep1Time", + base::TimeTicks::Now() - start_time_step1); + + // This step is costly and is already measured in Startup.CreateFirstProfile + // and more directly Profile.CreateAndInitializeProfile. profile_ = CreatePrimaryProfile(parameters(), user_data_dir_, parsed_command_line()); @@ -1300,6 +1309,7 @@ return content::RESULT_CODE_NORMAL_EXIT; #if !defined(OS_ANDROID) + const base::TimeTicks start_time_step2 = base::TimeTicks::Now(); // The first run sentinel must be created after the process singleton was // grabbed and no early return paths were otherwise hit above. first_run::CreateSentinelIfNeeded(); @@ -1309,7 +1319,7 @@ // Autoload any profiles which are running background apps. // TODO(rlp): Do this on a separate thread. See http://crbug.com/99075. browser_process_->profile_manager()->AutoloadProfiles(); -#endif +#endif // defined(ENABLE_BACKGROUND) // Post-profile init --------------------------------------------------------- TranslateService::Initialize(); @@ -1325,7 +1335,7 @@ NaClBrowserDelegateImpl* delegate = new NaClBrowserDelegateImpl(browser_process_->profile_manager()); nacl::NaClBrowser::SetDelegate(delegate); -#endif +#endif // !defined(DISABLE_NACL) // TODO(stevenjb): Move WIN and MACOSX specific code to appropriate Parts. // (requires supporting early exit). @@ -1389,7 +1399,7 @@ base::Bind(&NetworkProfileBubble::CheckNetworkProfile, profile_->GetPath())); } -#endif // OS_WIN +#endif // defined(OS_WIN) #if defined(ENABLE_RLZ) && !defined(OS_CHROMEOS) // Init the RLZ library. This just binds the dll and schedules a task on the @@ -1446,7 +1456,7 @@ parsed_command_line().GetSwitchValuePath(switches::kDebugPrint); printing::PrintedDocument::set_debug_dump_path(path); } -#endif +#endif // defined(ENABLE_PRINT_PREVIEW) && !defined(OFFICIAL_BUILD) HandleTestParameters(parsed_command_line()); browser_process_->metrics_service()->RecordBreakpadHasDebugger( @@ -1471,7 +1481,7 @@ #if !defined(OS_ANDROID) // Start watching for a hang. browser_process_->metrics_service()->LogNeedForCleanShutdown(); -#endif +#endif // !defined(OS_ANDROID) #if defined(ENABLE_PRINT_PREVIEW) // Create the instance of the cloud print proxy service so that it can launch @@ -1481,7 +1491,7 @@ // BrowserContextKeyedServiceFactory::ServiceIsCreatedWithBrowserContext() // instead? CloudPrintProxyServiceFactory::GetForProfile(profile_); -#endif +#endif // defined(ENABLE_PRINT_PREVIEW) // Start watching all browser threads for responsiveness. metrics::MetricsService::SetExecutionPhase( @@ -1491,14 +1501,14 @@ #if defined(OS_ANDROID) ThreadWatcherAndroid::RegisterApplicationStatusListener(); -#endif +#endif // defined(OS_ANDROID) #if !defined(DISABLE_NACL) BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(nacl::NaClProcessHost::EarlyStartup)); -#endif +#endif // !defined(DISABLE_NACL) // Make sure initial prefs are recorded PrefMetricsService::Factory::GetForProfile(profile_); @@ -1544,17 +1554,24 @@ #else std::vector<Profile*> last_opened_profiles = g_browser_process->profile_manager()->GetLastOpenedProfiles(); -#endif +#endif // defined(OS_CHROMEOS) - if (browser_creator_->Start(parsed_command_line(), base::FilePath(), - profile_, last_opened_profiles)) { + UMA_HISTOGRAM_TIMES("Startup.PreMainMessageLoopRunImplStep2Time", + base::TimeTicks::Now() - start_time_step2); + + // This step is costly and is already measured in + // Startup.StartupBrowserCreator_Start. + bool started = browser_creator_->Start( + parsed_command_line(), base::FilePath(), profile_, last_opened_profiles); + const base::TimeTicks start_time_step3 = base::TimeTicks::Now(); + if (started) { #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) // Initialize autoupdate timer. Timer callback costs basically nothing // when browser is not in persistent mode, so it's OK to let it ride on // the main thread. This needs to be done here because we don't want // to start the timer when Chrome is run inside a test harness. browser_process_->StartAutoupdateTimer(); -#endif +#endif // defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) #if defined(OS_LINUX) && !defined(OS_CHROMEOS) // On Linux, the running exe will be updated if an upgrade becomes @@ -1562,7 +1579,7 @@ // modified time of the exe, so we can compare to determine if there is // an upgrade while the browser is kept alive by a persistent extension. upgrade_util::SaveLastModifiedTimeOfExe(); -#endif +#endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) // Record now as the last successful chrome start. GoogleUpdateSettings::SetLastRunTime(); @@ -1572,7 +1589,7 @@ // because Start() will add things to it while creating the main window. if (parameters().autorelease_pool) parameters().autorelease_pool->Recycle(); -#endif +#endif // defined(OS_MACOSX) base::TimeDelta delay = base::TimeTicks::Now() - browser_open_start; UMA_HISTOGRAM_LONG_TIMES_100("Startup.BrowserOpenTabs", delay); @@ -1589,7 +1606,7 @@ #if defined(OS_WIN) variations_service->StartGoogleUpdateRegistrySync(); -#endif +#endif // defined(OS_WIN) } translate::TranslateDownloadManager::RequestLanguageList( @@ -1605,7 +1622,7 @@ #if !defined(OS_LINUX) || defined(OS_CHROMEOS) // http://crbug.com/426393 if (g_browser_process->metrics_service()->reporting_active()) content::StartPowerUsageMonitor(); -#endif +#endif // !defined(OS_LINUX) || defined(OS_CHROMEOS) process_power_collector_.reset(new ProcessPowerCollector); process_power_collector_->Initialize(); @@ -1621,11 +1638,17 @@ #if defined(OS_ANDROID) // We never run the C++ main loop on Android, since the UI thread message // loop is controlled by the OS, so this is as close as we can get to - // the start of the main loop + // the start of the main loop. if (result_code_ <= 0) { RecordBrowserStartupTime(); } -#endif +#endif // defined(OS_ANDROID) + +#if !defined(OS_ANDROID) + UMA_HISTOGRAM_TIMES("Startup.PreMainMessageLoopRunImplStep3Time", + base::TimeTicks::Now() - start_time_step3); +#endif // !defined(OS_ANDROID) + return result_code_; } @@ -1658,7 +1681,7 @@ run_loop.Run(); return true; -#endif +#endif // defined(OS_ANDROID) } void ChromeBrowserMainParts::PostMainMessageLoopRun() { @@ -1701,7 +1724,7 @@ restart_last_session_ = browser_shutdown::ShutdownPreThreadsStop(); browser_process_->StartTearDown(); -#endif +#endif // defined(OS_ANDROID) } void ChromeBrowserMainParts::PostDestroyThreads() { @@ -1728,8 +1751,8 @@ #if defined(OS_CHROMEOS) chromeos::CrosSettings::Shutdown(); -#endif -#endif +#endif // defined(OS_CHROMEOS) +#endif // defined(OS_ANDROID) } // Public members:
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index be00c5c4..7ce95d4e 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -43,6 +43,8 @@ #include "chrome/browser/metrics/rappor/sampling.h" #include "chrome/browser/nacl_host/nacl_browser_delegate_impl.h" #include "chrome/browser/net/chrome_net_log.h" +#include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h" +#include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h" #include "chrome/browser/notifications/desktop_notification_service.h" #include "chrome/browser/notifications/desktop_notification_service_factory.h" #include "chrome/browser/notifications/platform_notification_service_impl.h" @@ -56,14 +58,14 @@ #include "chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_io_data.h" +#include "chrome/browser/push_messaging/push_messaging_permission_context.h" +#include "chrome/browser/push_messaging/push_messaging_permission_context_factory.h" #include "chrome/browser/renderer_host/chrome_render_message_filter.h" #include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h" #include "chrome/browser/search/instant_service.h" #include "chrome/browser/search/instant_service_factory.h" #include "chrome/browser/search/search.h" #include "chrome/browser/search_engines/search_provider_install_state_message_filter.h" -#include "chrome/browser/services/gcm/push_messaging_permission_context.h" -#include "chrome/browser/services/gcm/push_messaging_permission_context_factory.h" #include "chrome/browser/signin/principals_message_filter.h" #include "chrome/browser/speech/chrome_speech_recognition_manager_delegate.h" #include "chrome/browser/speech/tts_controller.h" @@ -100,6 +102,7 @@ #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/permission_request_id.h" +#include "components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h" #include "components/dom_distiller/core/url_constants.h" #include "components/google/core/browser/google_util.h" #include "components/metrics/client_info.h" @@ -650,7 +653,7 @@ break; #endif case content::PERMISSION_PUSH_MESSAGING: - return gcm::PushMessagingPermissionContextFactory::GetForProfile(profile); + return PushMessagingPermissionContextFactory::GetForProfile(profile); case content::PERMISSION_NUM: NOTREACHED() << "Invalid RequestPermission for " << permission; break; @@ -680,6 +683,12 @@ } } +void OnRequestPermission( + const base::Callback<void(content::PermissionStatus)>& callback, + ContentSetting content_setting) { + callback.Run(ContentSettingToPermissionStatus(content_setting)); +} + } // namespace namespace chrome { @@ -938,6 +947,13 @@ if (switches::IsEnableAccountConsistency()) host->AddFilter(new PrincipalsMessageFilter(id)); + DataReductionProxyChromeSettings* data_reduction_proxy_settings = + DataReductionProxyChromeSettingsFactory::GetForBrowserContext(profile); + if (data_reduction_proxy_settings) { + host->AddFilter(new data_reduction_proxy::DataReductionProxyMessageFilter( + data_reduction_proxy_settings)); + } + host->Send(new ChromeViewMsg_SetIsIncognitoProcess( profile->IsOffTheRecord())); @@ -1934,7 +1950,7 @@ int bridge_id, const GURL& requesting_frame, bool user_gesture, - const base::Callback<void(bool)>& result_callback) { + const base::Callback<void(content::PermissionStatus)>& result_callback) { int render_process_id = web_contents->GetRenderProcessHost()->GetID(); int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID(); const PermissionRequestID request_id(render_process_id, @@ -1949,7 +1965,8 @@ return; context->RequestPermission(web_contents, request_id, requesting_frame, - user_gesture, result_callback); + user_gesture, + base::Bind(&OnRequestPermission, result_callback)); } content::PermissionStatus ChromeContentBrowserClient::GetPermissionStatus(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 3397a42..30e8f41 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -188,7 +188,7 @@ int bridge_id, const GURL& requesting_frame, bool user_gesture, - const base::Callback<void(bool)>& result_callback) override; + const base::Callback<void(content::PermissionStatus)>& callback) override; content::PermissionStatus GetPermissionStatus( content::PermissionType permission, content::BrowserContext* browser_context,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 8742198..ddbb0ad5 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -72,6 +72,7 @@ # be generated before code in this target can start building. "//components/strings", "//components/variations", + "//components/webui_generator", "//content/public/browser", "//content/public/common", "//crypto", @@ -114,6 +115,8 @@ "//ui/events:dom4_keycode_converter", "//ui/file_manager", "//ui/message_center", + "//ui/oobe:oobe", + "//ui/oobe:oobe_gen", "//ui/surface", "//ui/views", "//ui/views/controls/webview",
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc index e84dff2..9ae916bd 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
@@ -7,6 +7,7 @@ #include <map> #include <set> +#include "base/barrier_closure.h" #include "base/bind.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -28,12 +29,14 @@ #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/extensions/external_loader.h" #include "chrome/browser/extensions/external_provider_impl.h" +#include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/extensions/extension_constants.h" #include "chromeos/chromeos_paths.h" #include "chromeos/cryptohome/async_method_caller.h" #include "chromeos/settings/cros_settings_names.h" #include "components/ownership/owner_key_util.h" +#include "components/user_manager/user_manager.h" #include "content/public/browser/browser_thread.h" #include "extensions/common/extension_urls.h" @@ -49,12 +52,15 @@ } void OnRemoveAppCryptohomeComplete(const std::string& app, + const base::Closure& callback, bool success, cryptohome::MountError return_code) { if (!success) { LOG(ERROR) << "Remove cryptohome for " << app << " failed, return code: " << return_code; } + if (!callback.is_null()) + callback.Run(); } // Check for presence of machine owner public key file. @@ -538,6 +544,22 @@ } } + base::Closure cryptohomes_barrier_closure; + + const user_manager::User* active_user = + user_manager::UserManager::Get()->GetActiveUser(); + if (active_user) { + std::string active_user_id = active_user->GetUserID(); + for (const auto& it : old_apps) { + if (it.second->user_id() == active_user_id) { + VLOG(1) << "Currently running kiosk app removed from policy, exiting"; + cryptohomes_barrier_closure = BarrierClosure( + old_apps.size(), base::Bind(&chrome::AttemptUserExit)); + break; + } + } + } + // Clears cache and deletes the remaining old data. std::vector<std::string> apps_to_remove; for (std::map<std::string, KioskAppData*>::iterator it = old_apps.begin(); @@ -545,7 +567,9 @@ it->second->ClearCache(); cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove( it->second->user_id(), - base::Bind(&OnRemoveAppCryptohomeComplete, it->first)); + base::Bind(&OnRemoveAppCryptohomeComplete, + it->first, + cryptohomes_barrier_closure)); apps_to_remove.push_back(it->second->app_id()); } STLDeleteValues(&old_apps);
diff --git a/chrome/browser/chromeos/app_mode/kiosk_external_updater.cc b/chrome/browser/chromeos/app_mode/kiosk_external_updater.cc index 1617cc8a..4fcc1ff 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_external_updater.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_external_updater.cc
@@ -42,9 +42,9 @@ return; } - JSONFileValueSerializer serializer(manifest); + JSONFileValueDeserializer deserializer(manifest); std::string error_msg; - base::Value* extensions = serializer.Deserialize(NULL, &error_msg); + base::Value* extensions = deserializer.Deserialize(NULL, &error_msg); if (!extensions) { *error_code = KioskExternalUpdater::ERROR_INVALID_MANIFEST; return;
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc index d43781d..00462959 100644 --- a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc +++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
@@ -125,17 +125,17 @@ // static. void StartupAppLauncher::LoadOAuthFileOnBlockingPool( KioskOAuthParams* auth_params) { - int error_code = JSONFileValueSerializer::JSON_NO_ERROR; + int error_code = JSONFileValueDeserializer::JSON_NO_ERROR; std::string error_msg; base::FilePath user_data_dir; CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)); base::FilePath auth_file = user_data_dir.Append(kOAuthFileName); - scoped_ptr<JSONFileValueSerializer> serializer( - new JSONFileValueSerializer(user_data_dir.Append(kOAuthFileName))); + scoped_ptr<JSONFileValueDeserializer> deserializer( + new JSONFileValueDeserializer(user_data_dir.Append(kOAuthFileName))); scoped_ptr<base::Value> value( - serializer->Deserialize(&error_code, &error_msg)); + deserializer->Deserialize(&error_code, &error_msg)); base::DictionaryValue* dict = NULL; - if (error_code != JSONFileValueSerializer::JSON_NO_ERROR || + if (error_code != JSONFileValueDeserializer::JSON_NO_ERROR || !value.get() || !value->GetAsDictionary(&dict)) { LOG(WARNING) << "Can't find auth file at " << auth_file.value(); return;
diff --git a/chrome/browser/chromeos/customization/customization_document_unittest.cc b/chrome/browser/chromeos/customization/customization_document_unittest.cc index f17c803a..3e2342b6 100644 --- a/chrome/browser/chromeos/customization/customization_document_unittest.cc +++ b/chrome/browser/chromeos/customization/customization_document_unittest.cc
@@ -179,12 +179,13 @@ public: MockExternalProviderVisitor() {} - MOCK_METHOD6(OnExternalExtensionFileFound, + MOCK_METHOD7(OnExternalExtensionFileFound, bool(const std::string&, const base::Version*, const base::FilePath&, extensions::Manifest::Location, int, + bool, bool)); MOCK_METHOD6(OnExternalExtensionUpdateUrlFound, bool(const std::string&, @@ -345,7 +346,7 @@ extensions::Extension::FROM_WEBSTORE | extensions::Extension::WAS_INSTALLED_BY_DEFAULT)); - EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _)) + EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _, _)) .Times(0); EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _)) .Times(0); @@ -390,7 +391,7 @@ extensions::Extension::FROM_WEBSTORE | extensions::Extension::WAS_INSTALLED_BY_DEFAULT)); - EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _)) + EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _, _)) .Times(0); EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _)) .Times(0); @@ -401,7 +402,7 @@ loader->StartLoading(); Mock::VerifyAndClearExpectations(&visitor); - EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _)) + EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _, _)) .Times(0); EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _)) .Times(2); @@ -440,7 +441,7 @@ extensions::Extension::FROM_WEBSTORE | extensions::Extension::WAS_INSTALLED_BY_DEFAULT)); - EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _)) + EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _, _)) .Times(0); EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _)) .Times(0); @@ -451,7 +452,7 @@ loader->StartLoading(); Mock::VerifyAndClearExpectations(&visitor); - EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _)) + EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _, _)) .Times(0); EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _)) .Times(0);
diff --git a/chrome/browser/chromeos/device/input_service_proxy.cc b/chrome/browser/chromeos/device/input_service_proxy.cc index 861ef6c9..3d27ab1 100644 --- a/chrome/browser/chromeos/device/input_service_proxy.cc +++ b/chrome/browser/chromeos/device/input_service_proxy.cc
@@ -15,6 +15,9 @@ namespace chromeos { +// static +BrowserThread::ID InputServiceProxy::thread_identifier_ = BrowserThread::FILE; + class InputServiceProxy::ServiceObserver : public InputServiceLinux::Observer { public: ServiceObserver() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); } @@ -73,7 +76,7 @@ private: bool CalledOnValidThread() const { - return BrowserThread::CurrentlyOn(BrowserThread::FILE); + return BrowserThread::CurrentlyOn(InputServiceProxy::thread_identifier_); } base::WeakPtr<InputServiceProxy> proxy_; @@ -82,10 +85,12 @@ }; InputServiceProxy::InputServiceProxy() - : service_observer_(new ServiceObserver()), weak_factory_(this) { + : service_observer_(new ServiceObserver()), + task_runner_(BrowserThread::GetMessageLoopProxyForThread( + thread_identifier_)), + weak_factory_(this) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - BrowserThread::PostTask( - BrowserThread::FILE, + task_runner_->PostTask( FROM_HERE, base::Bind(&InputServiceProxy::ServiceObserver::Initialize, base::Unretained(service_observer_.get()), @@ -94,8 +99,7 @@ InputServiceProxy::~InputServiceProxy() { DCHECK(thread_checker_.CalledOnValidThread()); - BrowserThread::PostTask( - BrowserThread::FILE, + task_runner_->PostTask( FROM_HERE, base::Bind(&InputServiceProxy::ServiceObserver::Shutdown, base::Unretained(service_observer_.release()))); @@ -104,7 +108,7 @@ // static void InputServiceProxy::WarmUp() { content::BrowserThread::PostTask( - content::BrowserThread::FILE, + thread_identifier_, FROM_HERE, base::Bind(base::IgnoreResult(&InputServiceLinux::GetInstance))); } @@ -123,8 +127,8 @@ void InputServiceProxy::GetDevices(const GetDevicesCallback& callback) { DCHECK(thread_checker_.CalledOnValidThread()); - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::FILE, + base::PostTaskAndReplyWithResult( + task_runner_.get(), FROM_HERE, base::Bind(&InputServiceProxy::ServiceObserver::GetDevices, base::Unretained(service_observer_.get())), @@ -134,8 +138,7 @@ void InputServiceProxy::GetDeviceInfo(const std::string& id, const GetDeviceInfoCallback& callback) { DCHECK(thread_checker_.CalledOnValidThread()); - BrowserThread::PostTask( - BrowserThread::FILE, + task_runner_->PostTask( FROM_HERE, base::Bind(&InputServiceProxy::ServiceObserver::GetDeviceInfo, base::Unretained(service_observer_.release()), @@ -143,6 +146,11 @@ callback)); } +// static +void InputServiceProxy::SetThreadIdForTesting(BrowserThread::ID thread_id) { + InputServiceProxy::thread_identifier_ = thread_id; +} + void InputServiceProxy::OnDeviceAdded( const InputServiceLinux::InputDeviceInfo& info) { DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chrome/browser/chromeos/device/input_service_proxy.h b/chrome/browser/chromeos/device/input_service_proxy.h index e41196f..44a0a63 100644 --- a/chrome/browser/chromeos/device/input_service_proxy.h +++ b/chrome/browser/chromeos/device/input_service_proxy.h
@@ -11,7 +11,9 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "base/task_runner.h" #include "base/threading/thread_checker.h" +#include "content/public/browser/browser_thread.h" #include "device/hid/input_service_linux.h" namespace chromeos { @@ -47,7 +49,12 @@ void GetDeviceInfo(const std::string& id, const GetDeviceInfoCallback& callback); + // Should be called once before any InputServiceProxy instance is created. + static void SetThreadIdForTesting(content::BrowserThread::ID thread_id); + private: + static content::BrowserThread::ID thread_identifier_; + class ServiceObserver; void OnDeviceAdded(const device::InputServiceLinux::InputDeviceInfo& info); @@ -58,6 +65,8 @@ base::ThreadChecker thread_checker_; + scoped_refptr<base::TaskRunner> task_runner_; + base::WeakPtrFactory<InputServiceProxy> weak_factory_; DISALLOW_COPY_AND_ASSIGN(InputServiceProxy);
diff --git a/chrome/browser/chromeos/device_hierarchy_observer.h b/chrome/browser/chromeos/device_hierarchy_observer.h deleted file mode 100644 index 86c53724..0000000 --- a/chrome/browser/chromeos/device_hierarchy_observer.h +++ /dev/null
@@ -1,26 +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. - -#ifndef CHROME_BROWSER_CHROMEOS_DEVICE_HIERARCHY_OBSERVER_H_ -#define CHROME_BROWSER_CHROMEOS_DEVICE_HIERARCHY_OBSERVER_H_ - -namespace chromeos { - -// Observers receive notifications when a device has been added/removed. -class DeviceHierarchyObserver { - public: - virtual void DeviceHierarchyChanged() = 0; - - // Called when a new device (e.g. an external USB keyboard) is attached or - // detached. - virtual void DeviceAdded(int device_id) = 0; - virtual void DeviceRemoved(int device_id) = 0; - - protected: - virtual ~DeviceHierarchyObserver() {} -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_DEVICE_HIERARCHY_OBSERVER_H_
diff --git a/chrome/browser/chromeos/drive/file_system_util.cc b/chrome/browser/chromeos/drive/file_system_util.cc index 88ed4c2..60c81da 100644 --- a/chrome/browser/chromeos/drive/file_system_util.cc +++ b/chrome/browser/chromeos/drive/file_system_util.cc
@@ -58,7 +58,7 @@ return std::string(); } - JSONFileValueSerializer reader(file_path); + JSONFileValueDeserializer reader(file_path); std::string error_message; scoped_ptr<base::Value> root_value(reader.Deserialize(NULL, &error_message)); if (!root_value) {
diff --git a/chrome/browser/chromeos/drive/sync/entry_update_performer.cc b/chrome/browser/chromeos/drive/sync/entry_update_performer.cc index e107c8f..f2c5084 100644 --- a/chrome/browser/chromeos/drive/sync/entry_update_performer.cc +++ b/chrome/browser/chromeos/drive/sync/entry_update_performer.cc
@@ -254,7 +254,7 @@ DCHECK(!callback.is_null()); scoped_ptr<LocalState> local_state(new LocalState); - LocalState* local_state_ptr = local_state.get(); + LocalState* const local_state_ptr = local_state.get(); base::PostTaskAndReplyWithResult( blocking_task_runner_.get(), FROM_HERE, @@ -327,11 +327,13 @@ options.modified_date = last_modified; options.last_viewed_by_me_date = last_accessed; options.properties = properties; + LocalState* const local_state_ptr = local_state.get(); scheduler_->UploadNewFile( - local_state->parent_entry.resource_id(), local_state->drive_file_path, - local_state->cache_file_path, local_state->entry.title(), - local_state->entry.file_specific_info().content_mime_type(), options, - context, + local_state_ptr->parent_entry.resource_id(), + local_state_ptr->drive_file_path, local_state_ptr->cache_file_path, + local_state_ptr->entry.title(), + local_state_ptr->entry.file_specific_info().content_mime_type(), + options, context, base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource, weak_ptr_factory_.GetWeakPtr(), context, callback, base::Passed(&local_state), @@ -343,11 +345,12 @@ options.modified_date = last_modified; options.last_viewed_by_me_date = last_accessed; options.properties = properties; + LocalState* const local_state_ptr = local_state.get(); scheduler_->UploadExistingFile( - local_state->entry.resource_id(), local_state->drive_file_path, - local_state->cache_file_path, - local_state->entry.file_specific_info().content_mime_type(), options, - context, + local_state_ptr->entry.resource_id(), + local_state_ptr->drive_file_path, local_state_ptr->cache_file_path, + local_state_ptr->entry.file_specific_info().content_mime_type(), + options, context, base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource, weak_ptr_factory_.GetWeakPtr(), context, callback, base::Passed(&local_state), @@ -367,9 +370,10 @@ options.modified_date = last_modified; options.last_viewed_by_me_date = last_accessed; options.properties = properties; + LocalState* const local_state_ptr = local_state.get(); scheduler_->AddNewDirectory( - local_state->parent_entry.resource_id(), local_state->entry.title(), - options, context, + local_state_ptr->parent_entry.resource_id(), + local_state_ptr->entry.title(), options, context, base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource, weak_ptr_factory_.GetWeakPtr(), context, callback, base::Passed(&local_state), base::Passed(&loader_lock))); @@ -384,9 +388,11 @@ } // Perform metadata update. + LocalState* const local_state_ptr = local_state.get(); scheduler_->UpdateResource( - local_state->entry.resource_id(), local_state->parent_entry.resource_id(), - local_state->entry.title(), last_modified, last_accessed, properties, + local_state_ptr->entry.resource_id(), + local_state_ptr->parent_entry.resource_id(), + local_state_ptr->entry.title(), last_modified, last_accessed, properties, context, base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource, weak_ptr_factory_.GetWeakPtr(), context, callback,
diff --git a/chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener.cc b/chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener.cc index c569342..c208667 100644 --- a/chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener.cc +++ b/chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener.cc
@@ -16,9 +16,7 @@ namespace { // Checks the |event| and asynchronously sets the XKB layout when necessary. -void HandleHierarchyChangedEvent( - XIHierarchyEvent* event, - ObserverList<DeviceHierarchyObserver>* observer_list) { +void HandleHierarchyChangedEvent(XIHierarchyEvent* event) { if (!(event->flags & (XISlaveAdded | XISlaveRemoved))) return; @@ -26,15 +24,8 @@ for (int i = 0; i < event->num_info; ++i) { XIHierarchyInfo* info = &event->info[i]; if ((info->flags & XISlaveAdded) && (info->use == XIFloatingSlave)) { - FOR_EACH_OBSERVER(DeviceHierarchyObserver, - *observer_list, - DeviceAdded(info->deviceid)); update_keyboard_status = true; - } else if (info->flags & XISlaveRemoved) { - // Can't check info->use here; it appears to always be 0. - FOR_EACH_OBSERVER(DeviceHierarchyObserver, - *observer_list, - DeviceRemoved(info->deviceid)); + break; } } @@ -73,16 +64,6 @@ stopped_ = true; } -void XInputHierarchyChangedEventListener::AddObserver( - DeviceHierarchyObserver* observer) { - observer_list_.AddObserver(observer); -} - -void XInputHierarchyChangedEventListener::RemoveObserver( - DeviceHierarchyObserver* observer) { - observer_list_.RemoveObserver(observer); -} - void XInputHierarchyChangedEventListener::WillProcessEvent( const ui::PlatformEvent& event) { ProcessedXEvent(event); @@ -100,16 +81,8 @@ if (cookie->evtype == XI_HierarchyChanged) { XIHierarchyEvent* event = static_cast<XIHierarchyEvent*>(cookie->data); - HandleHierarchyChangedEvent(event, &observer_list_); - if (event->flags & XIDeviceEnabled || event->flags & XIDeviceDisabled) - NotifyDeviceHierarchyChanged(); + HandleHierarchyChangedEvent(event); } } -void XInputHierarchyChangedEventListener::NotifyDeviceHierarchyChanged() { - FOR_EACH_OBSERVER(DeviceHierarchyObserver, - observer_list_, - DeviceHierarchyChanged()); -} - } // namespace chromeos
diff --git a/chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener.h b/chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener.h index 8e9850a..8170f2bb 100644 --- a/chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener.h +++ b/chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener.h
@@ -7,7 +7,6 @@ #include "base/memory/singleton.h" #include "base/observer_list.h" -#include "chrome/browser/chromeos/device_hierarchy_observer.h" #include "ui/events/platform/platform_event_observer.h" typedef union _XEvent XEvent; @@ -24,9 +23,6 @@ void Stop(); - void AddObserver(DeviceHierarchyObserver* observer); - void RemoveObserver(DeviceHierarchyObserver* observer); - private: // Defines the delete on exit Singleton traits we like. Best to have this // and const/dest private as recommended for Singletons. @@ -42,13 +38,8 @@ // Returns true if the event was processed, false otherwise. void ProcessedXEvent(XEvent* xevent); - // Notify observers that a device has been added/removed. - void NotifyDeviceHierarchyChanged(); - bool stopped_; - ObserverList<DeviceHierarchyObserver> observer_list_; - DISALLOW_COPY_AND_ASSIGN(XInputHierarchyChangedEventListener); };
diff --git a/chrome/browser/chromeos/extensions/default_app_order.cc b/chrome/browser/chromeos/extensions/default_app_order.cc index 71c38749..9b6246f4 100644 --- a/chrome/browser/chromeos/extensions/default_app_order.cc +++ b/chrome/browser/chromeos/extensions/default_app_order.cc
@@ -63,9 +63,9 @@ if (!base::PathExists(path)) return NULL; - JSONFileValueSerializer serializer(path); + JSONFileValueDeserializer deserializer(path); std::string error_msg; - base::Value* value = serializer.Deserialize(NULL, &error_msg); + base::Value* value = deserializer.Deserialize(NULL, &error_msg); if (!value) { LOG(WARNING) << "Unable to deserialize default app ordinals json data:" << error_msg << ", file=" << path.value();
diff --git a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc index fd6e7c599..bd9c5a3 100644 --- a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc +++ b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc
@@ -68,12 +68,13 @@ MockExternalPolicyProviderVisitor(); virtual ~MockExternalPolicyProviderVisitor(); - MOCK_METHOD6(OnExternalExtensionFileFound, + MOCK_METHOD7(OnExternalExtensionFileFound, bool(const std::string&, const base::Version*, const base::FilePath&, extensions::Manifest::Location, int, + bool, bool)); MOCK_METHOD6(OnExternalExtensionUpdateUrlFound, bool(const std::string&, @@ -165,7 +166,7 @@ void DeviceLocalAccountExternalPolicyLoaderTest:: VerifyAndResetVisitorCallExpectations() { Mock::VerifyAndClearExpectations(&visitor_); - EXPECT_CALL(visitor_, OnExternalExtensionFileFound(_, _, _, _, _, _)) + EXPECT_CALL(visitor_, OnExternalExtensionFileFound(_, _, _, _, _, _, _)) .Times(0); EXPECT_CALL(visitor_, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _)) .Times(0); @@ -290,6 +291,7 @@ cached_crx_path, extensions::Manifest::EXTERNAL_POLICY, _, + _, _)); EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get())) .Times(1)
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc index c96dff0..65206db6b 100644 --- a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc +++ b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
@@ -56,7 +56,7 @@ << message_; } -IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, DISABLED_BigFile) { +IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, BigFile) { ASSERT_TRUE(RunPlatformAppTestWithFlags("file_system_provider/big_file", kFlagLoadAsComponent)) << message_;
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc index 45890d0..2319eb1 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
@@ -30,11 +30,6 @@ FILE_PATH_LITERAL("background/js/device_handler_unittest.html"))); } -IN_PROC_BROWSER_TEST_F(FileManagerJsTest, MetadataCacheTest) { - RunTest(base::FilePath(FILE_PATH_LITERAL( - "foreground/js/metadata/metadata_cache_unittest.html"))); -} - IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FileOperationManagerTest) { RunTest(base::FilePath( FILE_PATH_LITERAL("background/js/file_operation_manager_unittest.html"))); @@ -124,9 +119,9 @@ "foreground/js/metadata/metadata_cache_set_unittest.html"))); } -IN_PROC_BROWSER_TEST_F(FileManagerJsTest, NewMetadataProvider) { +IN_PROC_BROWSER_TEST_F(FileManagerJsTest, MultiMetadataProvider) { RunTest(base::FilePath(FILE_PATH_LITERAL( - "foreground/js/metadata/new_metadata_provider_unittest.html"))); + "foreground/js/metadata/multi_metadata_provider_unittest.html"))); } IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ListThumbnailLoader) { @@ -149,9 +144,9 @@ "foreground/js/metadata/content_metadata_provider_unittest.html"))); } -IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FileSystemMetadata) { +IN_PROC_BROWSER_TEST_F(FileManagerJsTest, MetadataModel) { RunTest(base::FilePath(FILE_PATH_LITERAL( - "foreground/js/metadata/file_system_metadata_unittest.html"))); + "foreground/js/metadata/metadata_model_unittest.html"))); } IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ThumbnailModel) {
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc index 7c2dde6..6820aab0 100644 --- a/chrome/browser/chromeos/file_manager/volume_manager.cc +++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -661,18 +661,23 @@ storage::FileSystemMountOption(), path); DCHECK(result); + + // TODO(yawano) A variable to switch MTP write support. This variable should + // be false until MTP write operation is implemented and shipped. + bool write_supported = false; + content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, base::Bind( - &MTPDeviceMapService::RegisterMTPFileSystem, - base::Unretained(MTPDeviceMapService::GetInstance()), - info.location(), fsid)); + content::BrowserThread::IO, FROM_HERE, + base::Bind(&MTPDeviceMapService::RegisterMTPFileSystem, + base::Unretained(MTPDeviceMapService::GetInstance()), + info.location(), fsid, !write_supported /* read_only */)); VolumeInfo volume_info; volume_info.type = VOLUME_TYPE_MTP; volume_info.mount_path = path; volume_info.mount_condition = chromeos::disks::MOUNT_CONDITION_NONE; volume_info.is_parent = true; - volume_info.is_read_only = true; + volume_info.is_read_only = !write_supported; volume_info.volume_id = kMtpVolumeIdPrefix + label; volume_info.volume_label = label; volume_info.source_path = path;
diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system.cc b/chrome/browser/chromeos/file_system_provider/provided_file_system.cc index 76671e0..aef7e584 100644 --- a/chrome/browser/chromeos/file_system_provider/provided_file_system.cc +++ b/chrome/browser/chromeos/file_system_provider/provided_file_system.cc
@@ -654,7 +654,6 @@ if (result != base::File::FILE_OK) { callback.Run(result); watcher_queue_.Complete(token); - watcher_queue_.Remove(token); return; } @@ -663,7 +662,6 @@ if (it != watchers_.end()) { callback.Run(base::File::FILE_OK); watcher_queue_.Complete(token); - watcher_queue_.Remove(token); return; } @@ -678,7 +676,6 @@ callback.Run(base::File::FILE_OK); watcher_queue_.Complete(token); - watcher_queue_.Remove(token); } void ProvidedFileSystem::OnRemoveWatcherInQueueCompleted( @@ -690,7 +687,6 @@ base::File::Error result) { if (!extension_response && result != base::File::FILE_OK) { watcher_queue_.Complete(token); - watcher_queue_.Remove(token); callback.Run(result); return; } @@ -712,7 +708,6 @@ callback.Run(base::File::FILE_OK); watcher_queue_.Complete(token); - watcher_queue_.Remove(token); } void ProvidedFileSystem::OnNotifyInQueueCompleted( @@ -721,7 +716,6 @@ if (result != base::File::FILE_OK) { args->callback.Run(result); watcher_queue_.Complete(args->token); - watcher_queue_.Remove(args->token); return; } @@ -731,7 +725,6 @@ if (it == watchers_.end()) { args->callback.Run(base::File::FILE_ERROR_NOT_FOUND); watcher_queue_.Complete(args->token); - watcher_queue_.Remove(args->token); return; } @@ -754,7 +747,6 @@ args->callback.Run(base::File::FILE_OK); watcher_queue_.Complete(args->token); - watcher_queue_.Remove(args->token); } void ProvidedFileSystem::OnOpenFileCompleted(const base::FilePath& file_path,
diff --git a/chrome/browser/chromeos/file_system_provider/queue.cc b/chrome/browser/chromeos/file_system_provider/queue.cc index bd32c11e..dca78ea 100644 --- a/chrome/browser/chromeos/file_system_provider/queue.cc +++ b/chrome/browser/chromeos/file_system_provider/queue.cc
@@ -50,37 +50,17 @@ void Queue::Complete(size_t token) { const auto it = executed_.find(token); - CHECK(it != executed_.end()); - completed_[token] = it->second; + DCHECK(it != executed_.end()); executed_.erase(it); -} - -void Queue::Remove(size_t token) { - const auto it = completed_.find(token); - if (it != completed_.end()) { - completed_.erase(it); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&Queue::MaybeRun, weak_ptr_factory_.GetWeakPtr())); - return; - } - - // If not completed, then it must have been aborted. - const auto aborted_it = aborted_.find(token); - CHECK(aborted_it != aborted_.end()); - aborted_.erase(aborted_it); - base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&Queue::MaybeRun, weak_ptr_factory_.GetWeakPtr())); } void Queue::MaybeRun() { - if (executed_.size() + completed_.size() == max_in_parallel_ || - !pending_.size()) { + if (executed_.size() == max_in_parallel_ || !pending_.size()) return; - } - CHECK_GT(max_in_parallel_, executed_.size() + completed_.size()); + CHECK_GT(max_in_parallel_, executed_.size()); Task task = pending_.front(); pending_.pop_front(); @@ -95,24 +75,20 @@ } void Queue::Abort(size_t token) { - // Check if it's running. + // Check if it's running. If so, then abort and expect a Complete() call soon. const auto it = executed_.find(token); if (it != executed_.end()) { - Task task = it->second; - aborted_[token] = task; - executed_.erase(it); - CHECK(!task.abort_callback.is_null()); - task.abort_callback.Run(); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&Queue::MaybeRun, weak_ptr_factory_.GetWeakPtr())); + Task& task = it->second; + AbortCallback abort_callback = task.abort_callback; + task.abort_callback = AbortCallback(); + DCHECK(!abort_callback.is_null()); + abort_callback.Run(); return; } // Aborting not running tasks is linear. TODO(mtomasz): Optimize if feasible. for (auto it = pending_.begin(); it != pending_.end(); ++it) { if (token == it->token) { - aborted_[token] = *it; pending_.erase(it); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, @@ -125,21 +101,5 @@ NOTREACHED(); } -bool Queue::IsAborted(size_t token) { -#if !NDEBUG - bool in_queue = executed_.find(token) != executed_.end() || - completed_.find(token) != completed_.end() || - aborted_.find(token) != aborted_.end(); - for (auto& task : pending_) { - if (token == task.token) { - in_queue = true; - break; - } - } - DCHECK(in_queue); -#endif - return aborted_.find(token) != aborted_.end(); -} - } // namespace file_system_provider } // namespace chromeos
diff --git a/chrome/browser/chromeos/file_system_provider/queue.h b/chrome/browser/chromeos/file_system_provider/queue.h index 559dcd65..adc1684e 100644 --- a/chrome/browser/chromeos/file_system_provider/queue.h +++ b/chrome/browser/chromeos/file_system_provider/queue.h
@@ -24,19 +24,14 @@ // 1. Call NewToken() to obtain the token used bo all other methods. // 2. Call Enqueue() to enqueue the task. // 3. Call Complete() when the task is completed. -// 4. Call Remove() to remove a completed task from the queue and run other -// enqueued tasks. // -// Enqueued tasks can be aborted with Abort() at any time until they are marked -// as completed or removed from the queue, as long as the task supports aborting -// (it's abort callback is not NULL). Aorting does not remove the task from the -// queue. +// If the task supports aborting (it's abort callback is not NULL), then an +// enqueued task can be aborted with Abort() at any time as long as the task is +// not completed. // -// In most cases you'll want to call Remove() and Complete() one after the -// other. However, in some cases you may want to separate it. Eg. for limiting -// number of opened files, you may want to call Complete() after opening is -// completed, but Remove() after the file is closed. Note, that they can be -// called at most once. +// Once a task is executed, it must be marked as completed with Complete(). If +// it's aborted before executing, no call to Complete() can happen. Simply +// saying, just call Complete() from the completion callback of the task. class Queue { public: typedef base::Callback<AbortCallback(void)> AbortableCallback; @@ -51,33 +46,20 @@ // Enqueues a task using a token generated with NewToken(). The task will be // executed if there is space in the internal queue, otherwise it will wait - // until another task is finished. Once the task is finished, Complete() and - // Remove() must be called. The callback's abort callback may be NULL. In - // such case, Abort() must not be called. + // until another task is finished. Once the task is finished, Complete() must + // be called. The callback's abort callback may be NULL. In such case, Abort() + // must not be called. void Enqueue(size_t token, const AbortableCallback& callback); // Forcibly aborts a previously enqueued task. May be called at any time as // long as the task is still in the queue and is not marked as completed. - // Note, that Remove() must be called in order to remove the task from the - // queue. Must not be called if the task doesn't support aborting (it's - // abort callback is NULL). void Abort(size_t token); - // Returns true if the task which is in the queue with |token| has been - // aborted. This method must not be called for tasks which are not in the - // queue. - bool IsAborted(size_t token); - - // Marks the previously enqueued task as complete. Must be called for each - // enqueued task (unless aborted). Note, that Remove() must be called in order - // to remove the task from the queue if it hasn't been aborted earlier. - // It must not be called more than one, nor for aborted tasks. + // Marks an executed task with |token| as completed. Must be called once the + // task is executed. Simply saying, in most cases it should be just called + // from the task's completion callback. void Complete(size_t token); - // Removes the previously enqueued and completed or aborted task from the - // queue. Must not be called more than once. - void Remove(size_t token); - private: // Information about an enqueued task which hasn't been removed, nor aborted. struct Task { @@ -98,8 +80,6 @@ size_t next_token_; std::deque<Task> pending_; std::map<int, Task> executed_; - std::map<int, Task> completed_; - std::map<int, Task> aborted_; base::WeakPtrFactory<Queue> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(Queue);
diff --git a/chrome/browser/chromeos/file_system_provider/queue_unittest.cc b/chrome/browser/chromeos/file_system_provider/queue_unittest.cc index a5bab45..f371659 100644 --- a/chrome/browser/chromeos/file_system_provider/queue_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/queue_unittest.cc
@@ -70,19 +70,11 @@ EXPECT_EQ(0, second_counter); EXPECT_EQ(0, second_abort_counter); - // Complete the first task, which should not run the second one, yet. + // Complete the first task from the queue should run the second task. queue.Complete(first_token); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, first_counter); EXPECT_EQ(0, first_abort_counter); - EXPECT_EQ(0, second_counter); - EXPECT_EQ(0, second_abort_counter); - - // Removing the first task from the queue should run the second task. - queue.Remove(first_token); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1, first_counter); - EXPECT_EQ(0, first_abort_counter); EXPECT_EQ(1, second_counter); EXPECT_EQ(0, second_abort_counter); @@ -103,7 +95,7 @@ // After aborting the second task, the third should run. queue.Abort(second_token); - queue.Remove(second_token); + queue.Complete(second_token); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, first_counter); EXPECT_EQ(0, first_abort_counter); @@ -113,30 +105,6 @@ EXPECT_EQ(0, third_abort_counter); } -TEST_F(FileSystemProviderQueueTest, Enqueue_WhilePreviousNotRemoved) { - Queue queue(1); - const size_t first_token = queue.NewToken(); - int first_counter = 0; - int first_abort_counter = 0; - queue.Enqueue(first_token, - base::Bind(&OnRun, &first_counter, &first_abort_counter)); - - base::RunLoop().RunUntilIdle(); - queue.Complete(first_token); - - // Enqueuing a new task must not start it, once the queue is filled with a - // completed task. - const size_t second_token = queue.NewToken(); - int second_counter = 0; - int second_abort_counter = 0; - queue.Enqueue(second_token, - base::Bind(&OnRun, &second_counter, &second_abort_counter)); - - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(0, second_counter); - EXPECT_EQ(0, second_abort_counter); -} - TEST_F(FileSystemProviderQueueTest, Enqueue_MultipleAtOnce) { Queue queue(2); const size_t first_token = queue.NewToken(); @@ -167,7 +135,6 @@ // Completing and removing the second task, should start the last one. queue.Complete(second_token); - queue.Remove(second_token); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, first_counter); EXPECT_EQ(0, first_abort_counter); @@ -206,10 +173,10 @@ // Completing and removing the first task, which however hasn't started. // That should not invoke the second task. EXPECT_DEATH(queue.Complete(first_token), ""); - EXPECT_DEATH(queue.Remove(first_token), ""); } -TEST_F(FileSystemProviderQueueTest, InvalidUsage_RemoveNotCompletedNorAborted) { +TEST_F(FileSystemProviderQueueTest, + InvalidUsage_CompleteAfterAbortingNonExecutedTask) { Queue queue(1); const size_t first_token = queue.NewToken(); int first_counter = 0; @@ -217,23 +184,6 @@ queue.Enqueue(first_token, base::Bind(&OnRun, &first_counter, &first_abort_counter)); - base::RunLoop().RunUntilIdle(); - - // Remove before completing. - EXPECT_DEATH(queue.Remove(first_token), ""); -} - -TEST_F(FileSystemProviderQueueTest, InvalidUsage_CompleteAfterAborting) { - Queue queue(1); - const size_t first_token = queue.NewToken(); - int first_counter = 0; - int first_abort_counter = 0; - queue.Enqueue(first_token, - base::Bind(&OnRun, &first_counter, &first_abort_counter)); - - base::RunLoop().RunUntilIdle(); - - // Run, then abort. std::vector<base::File::Error> first_abort_callback_log; queue.Abort(first_token); @@ -282,71 +232,6 @@ EXPECT_DEATH(queue.Abort(first_token), ""); } -TEST_F(FileSystemProviderQueueTest, InvalidUsage_IsAbortedWhileNotInQueue) { - Queue queue(1); - EXPECT_DEATH(queue.IsAborted(1234), ""); -} - -TEST_F(FileSystemProviderQueueTest, InvalidUsage_IsAbortedAfterRemoved) { - Queue queue(1); - const size_t first_token = queue.NewToken(); - int first_counter = 0; - int first_abort_counter = 0; - queue.Enqueue(first_token, - base::Bind(&OnRun, &first_counter, &first_abort_counter)); - - base::RunLoop().RunUntilIdle(); - - queue.Abort(first_token); - queue.Remove(first_token); - EXPECT_DEATH(queue.IsAborted(first_token), ""); -} - -TEST_F(FileSystemProviderQueueTest, InvalidUsage_RemoveTwice) { - Queue queue(1); - const size_t first_token = queue.NewToken(); - int first_counter = 0; - int first_abort_counter = 0; - queue.Enqueue(first_token, - base::Bind(&OnRun, &first_counter, &first_abort_counter)); - - base::RunLoop().RunUntilIdle(); - - queue.Complete(first_token); - queue.Remove(first_token); - EXPECT_DEATH(queue.Complete(first_token), ""); -} - -TEST_F(FileSystemProviderQueueTest, InvalidUsage_AbortAfterRemoving) { - Queue queue(1); - const size_t first_token = queue.NewToken(); - int first_counter = 0; - int first_abort_counter = 0; - queue.Enqueue(first_token, - base::Bind(&OnRun, &first_counter, &first_abort_counter)); - - base::RunLoop().RunUntilIdle(); - - queue.Complete(first_token); - queue.Remove(first_token); - EXPECT_DEATH(queue.Abort(first_token), ""); -} - -TEST_F(FileSystemProviderQueueTest, InvalidUsage_CompleteAfterRemoving) { - Queue queue(1); - const size_t first_token = queue.NewToken(); - int first_counter = 0; - int first_abort_counter = 0; - queue.Enqueue(first_token, - base::Bind(&OnRun, &first_counter, &first_abort_counter)); - - base::RunLoop().RunUntilIdle(); - - queue.Complete(first_token); - queue.Remove(first_token); - EXPECT_DEATH(queue.Complete(first_token), ""); -} - TEST_F(FileSystemProviderQueueTest, InvalidUsage_AbortNonAbortable) { Queue queue(1); const size_t first_token = queue.NewToken(); @@ -383,17 +268,12 @@ EXPECT_EQ(0, second_abort_counter); // Abort the first task while it's being executed. - EXPECT_FALSE(queue.IsAborted(first_token)); queue.Abort(first_token); - EXPECT_TRUE(queue.IsAborted(first_token)); - queue.Remove(first_token); + queue.Complete(first_token); // Abort the second task, before it's started. EXPECT_EQ(0, second_counter); - EXPECT_FALSE(queue.IsAborted(second_token)); queue.Abort(second_token); - EXPECT_TRUE(queue.IsAborted(second_token)); - queue.Remove(second_token); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, first_counter);
diff --git a/chrome/browser/chromeos/file_system_provider/throttled_file_system.cc b/chrome/browser/chromeos/file_system_provider/throttled_file_system.cc index dc01372..b0d018f 100644 --- a/chrome/browser/chromeos/file_system_provider/throttled_file_system.cc +++ b/chrome/browser/chromeos/file_system_provider/throttled_file_system.cc
@@ -195,19 +195,12 @@ const OpenFileCallback& callback, int file_handle, base::File::Error result) { - // The task may be aborted either via the callback, or by the operation, eg. - // because of destroying the request manager or unmounting the file system - // during the operation. Mark the task as completed only if it hasn't been - // aborted before. - if (!open_queue_->IsAborted(queue_token)) - open_queue_->Complete(queue_token); - // If the file is opened successfully then hold the queue token until the file // is closed. if (result == base::File::FILE_OK) opened_files_[file_handle] = queue_token; else - open_queue_->Remove(queue_token); + open_queue_->Complete(queue_token); callback.Run(file_handle, result); } @@ -220,10 +213,10 @@ // closed on the C++ side. Release the task from the queue, so other files // which are enqueued can be opened. const auto it = opened_files_.find(file_handle); - CHECK(it != opened_files_.end()); + DCHECK(it != opened_files_.end()); const int queue_token = it->second; - open_queue_->Remove(queue_token); + open_queue_->Complete(queue_token); opened_files_.erase(file_handle); callback.Run(result);
diff --git a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc b/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc index 9883f07..cc0c287 100644 --- a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc +++ b/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
@@ -322,8 +322,8 @@ scoped_ptr<base::DictionaryValue> ComponentExtensionIMEManagerImpl::GetManifest( const std::string& manifest_string) { std::string error; - JSONStringValueSerializer serializer(manifest_string); - scoped_ptr<base::Value> manifest(serializer.Deserialize(NULL, &error)); + JSONStringValueDeserializer deserializer(manifest_string); + scoped_ptr<base::Value> manifest(deserializer.Deserialize(NULL, &error)); if (!manifest.get()) LOG(ERROR) << "Failed at getting manifest";
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc index d747f2a..7a10b51 100644 --- a/chrome/browser/chromeos/login/chrome_restart_request.cc +++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -90,6 +90,7 @@ ::switches::kDisablePanelFitting, ::switches::kDisableSeccompFilterSandbox, ::switches::kDisableSetuidSandbox, + ::switches::kDisableSurfaces, ::switches::kDisableTextBlobs, ::switches::kDisableThreadedGpuRasterization, ::switches::kDisableThreadedScrolling,
diff --git a/chrome/browser/chromeos/login/default_pinned_apps_field_trial.cc b/chrome/browser/chromeos/login/default_pinned_apps_field_trial.cc deleted file mode 100644 index 4b21f533..0000000 --- a/chrome/browser/chromeos/login/default_pinned_apps_field_trial.cc +++ /dev/null
@@ -1,32 +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. - -#include "chrome/browser/chromeos/login/default_pinned_apps_field_trial.h" - -#include "base/basictypes.h" -#include "base/prefs/pref_registry_simple.h" -#include "base/prefs/pref_service.h" - -namespace chromeos { -namespace default_pinned_apps_field_trial { - -namespace { - -// Name of a local state pref to store the list of users that participate -// the experiment. -const char kExperimentUsers[] = "DefaultPinnedAppsExperimentUsers"; - -} // namespace - -void RegisterPrefs(PrefRegistrySimple* registry) { - registry->RegisterListPref(kExperimentUsers); -} - -void MigratePrefs(PrefService* local_state) { - // TODO(xiyuan): Remove everything in M34. - local_state->ClearPref(kExperimentUsers); -} - -} // namespace default_pinned_apps_field_trial -} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/default_pinned_apps_field_trial.h b/chrome/browser/chromeos/login/default_pinned_apps_field_trial.h deleted file mode 100644 index 5a1c6aa..0000000 --- a/chrome/browser/chromeos/login/default_pinned_apps_field_trial.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_DEFAULT_PINNED_APPS_FIELD_TRIAL_H_ -#define CHROME_BROWSER_CHROMEOS_LOGIN_DEFAULT_PINNED_APPS_FIELD_TRIAL_H_ - -#include <string> - -namespace base { -class ListValue; -} - -class PrefRegistrySimple; -class PrefService; - -namespace chromeos { -namespace default_pinned_apps_field_trial { - -// Registers a local state that keeps track of users in experiment. -void RegisterPrefs(PrefRegistrySimple* registry); - -// Migrate by removing the old local state. -void MigratePrefs(PrefService* local_state); - -} // namespace default_pinned_apps_field_trial -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_LOGIN_DEFAULT_PINNED_APPS_FIELD_TRIAL_H_
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc index 5b22b41..3378e997 100644 --- a/chrome/browser/chromeos/login/existing_user_controller.cc +++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -722,11 +722,12 @@ // ExistingUserController, private: void ExistingUserController::DeviceSettingsChanged() { - if (host_ != NULL) { + // If login was already completed, we should avoid any signin screen + // transitions, see http://crbug.com/461604 for example. + if (host_ != NULL && !login_display_->is_signin_completed()) { // Signed settings or user list changed. Notify views and update them. UpdateLoginDisplay(user_manager::UserManager::Get()->GetUsers()); ConfigurePublicSessionAutoLogin(); - return; } }
diff --git a/chrome/browser/chromeos/login/hid_detection_browsertest.cc b/chrome/browser/chromeos/login/hid_detection_browsertest.cc new file mode 100644 index 0000000..ebb23d20 --- /dev/null +++ b/chrome/browser/chromeos/login/hid_detection_browsertest.cc
@@ -0,0 +1,124 @@ +// 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/bind.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/login/test/oobe_base_test.h" +#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" +#include "chrome/browser/chromeos/login/ui/oobe_display.h" +#include "content/public/browser/browser_thread.h" +#include "device/bluetooth/bluetooth_adapter_factory.h" +#include "device/bluetooth/test/mock_bluetooth_adapter.h" +#include "device/hid/fake_input_service_linux.h" +#include "device/hid/input_service_linux.h" +#include "testing/gmock/include/gmock/gmock.h" + +using content::BrowserThread; +using device::InputServiceLinux; +using testing::_; + +using InputDeviceInfo = InputServiceLinux::InputDeviceInfo; + +namespace { + +void SetUpBluetoothMock( + scoped_refptr< + testing::NiceMock<device::MockBluetoothAdapter> > mock_adapter, + bool is_present) { + device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter); + + EXPECT_CALL(*mock_adapter, IsPresent()) + .WillRepeatedly(testing::Return(is_present)); + + EXPECT_CALL(*mock_adapter, IsPowered()) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL(*mock_adapter, GetDevices()).WillRepeatedly( + testing::Return(device::BluetoothAdapter::ConstDeviceList())); +} + +} // namespace + +namespace chromeos { + +class HidDetectionTest : public OobeBaseTest { + public: + typedef device::InputServiceLinux::InputDeviceInfo InputDeviceInfo; + + HidDetectionTest() : weak_ptr_factory_(this) { + InputServiceProxy::SetThreadIdForTesting(content::BrowserThread::UI); + HidDetectionTest::InitInputService(); + } + + ~HidDetectionTest() override {} + + void InitInputService() { + input_service_linux_.reset(new device::FakeInputServiceLinux); + InputServiceLinux::SetForTesting(input_service_linux_.get()); + } + + void SetUpOnMainThread() override { + OobeBaseTest::SetUpOnMainThread(); + } + + void SetUpInProcessBrowserTestFixture() override { + OobeBaseTest::SetUpInProcessBrowserTestFixture(); + + mock_adapter_ = new testing::NiceMock<device::MockBluetoothAdapter>(); + SetUpBluetoothMock(mock_adapter_, true); + } + + void AddUsbMouse(const std::string& mouse_id) { + InputDeviceInfo mouse; + mouse.id = mouse_id; + mouse.subsystem = InputDeviceInfo::SUBSYSTEM_INPUT; + mouse.type = InputDeviceInfo::TYPE_USB; + mouse.is_mouse = true; + LOG(ERROR) << input_service_linux_.get(); + input_service_linux_->AddDeviceForTesting(mouse); + } + + void AddUsbKeyboard(const std::string& keyboard_id) { + InputDeviceInfo keyboard; + keyboard.id = keyboard_id; + keyboard.subsystem = InputDeviceInfo::SUBSYSTEM_INPUT; + keyboard.type = InputDeviceInfo::TYPE_USB; + keyboard.is_keyboard = true; + input_service_linux_->AddDeviceForTesting(keyboard); + } + + private: + scoped_refptr< + testing::NiceMock<device::MockBluetoothAdapter> > mock_adapter_; + + scoped_ptr<device::FakeInputServiceLinux> input_service_linux_; + + base::WeakPtrFactory<HidDetectionTest> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(HidDetectionTest); +}; + +class HidDetectionSkipTest : public HidDetectionTest { + public: + HidDetectionSkipTest() { + AddUsbMouse("mouse"); + AddUsbKeyboard("keyboard"); + } + + void SetUpOnMainThread() override { + HidDetectionTest::SetUpOnMainThread(); + } +}; + +IN_PROC_BROWSER_TEST_F(HidDetectionTest, NoDevicesConnected) { + OobeScreenWaiter(OobeDisplay::SCREEN_OOBE_HID_DETECTION).Wait(); +} + +IN_PROC_BROWSER_TEST_F(HidDetectionSkipTest, BothDevicesPreConnected) { + OobeScreenWaiter(OobeDisplay::SCREEN_OOBE_NETWORK).Wait(); + +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc index 5fceb28..2bf45b9e 100644 --- a/chrome/browser/chromeos/login/lock/screen_locker.cc +++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -43,6 +43,7 @@ #include "chromeos/dbus/session_manager_client.h" #include "chromeos/login/auth/authenticator.h" #include "chromeos/login/auth/extended_authenticator.h" +#include "chromeos/network/portal_detector/network_portal_detector.h" #include "components/signin/core/browser/signin_manager.h" #include "components/user_manager/user_manager.h" #include "components/user_manager/user_type.h" @@ -366,6 +367,8 @@ VLOG(1) << "Calling session manager's StopSession D-Bus method"; DBusThreadManager::Get()->GetSessionManagerClient()->StopSession(); } + // Close captive portal window and clear signin profile. + NetworkPortalDetector::Get()->OnLockScreenRequest(); } // static
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_authentication.cc b/chrome/browser/chromeos/login/supervised/supervised_user_authentication.cc index bd65b30..c2ea24d 100644 --- a/chrome/browser/chromeos/login/supervised/supervised_user_authentication.cc +++ b/chrome/browser/chromeos/login/supervised/supervised_user_authentication.cc
@@ -55,12 +55,13 @@ } base::DictionaryValue* LoadPasswordData(base::FilePath profile_dir) { - JSONFileValueSerializer serializer(profile_dir.Append(kPasswordUpdateFile)); + JSONFileValueDeserializer deserializer( + profile_dir.Append(kPasswordUpdateFile)); std::string error_message; - int error_code = JSONFileValueSerializer::JSON_NO_ERROR; + int error_code = JSONFileValueDeserializer::JSON_NO_ERROR; scoped_ptr<base::Value> value( - serializer.Deserialize(&error_code, &error_message)); - if (JSONFileValueSerializer::JSON_NO_ERROR != error_code) { + deserializer.Deserialize(&error_code, &error_message)); + if (JSONFileValueDeserializer::JSON_NO_ERROR != error_code) { LOG(ERROR) << "Could not deserialize password data, error = " << error_code << " / " << error_message; return NULL;
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc index 7e843cc8..4cd04528 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
@@ -110,7 +110,7 @@ const char kOobeURL[] = "chrome://oobe/oobe"; // URL which corresponds to the new implementation of OOBE WebUI. -const char kNewOobeURL[] = "chrome://oobe/new-oobe"; +const char kNewOobeURL[] = "chrome://oobe-md/"; // URL which corresponds to the user adding WebUI. const char kUserAddingURL[] = "chrome://oobe/user-adding"; @@ -273,6 +273,7 @@ startup_sound_played_(false), startup_sound_honors_spoken_feedback_(false), is_observing_keyboard_(false), + is_new_oobe_(false), pointer_factory_(this), animation_weak_ptr_factory_(this) { DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this); @@ -498,8 +499,8 @@ VLOG(1) << "Login WebUI >> wizard"; if (!login_window_) { - LoadURL(StartupUtils::IsNewOobeActivated() ? GURL(kNewOobeURL) - : GURL(kOobeURL)); + is_new_oobe_ = StartupUtils::IsNewOobeActivated(); + LoadURL(is_new_oobe_ ? GURL(kNewOobeURL) : GURL(kOobeURL)); } DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name; @@ -510,6 +511,9 @@ wizard_controller_.reset(); wizard_controller_.reset(CreateWizardController()); + if (is_new_oobe_) + return; + oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered(); SetOobeProgressBarVisible(oobe_progress_bar_visible_); wizard_controller_->Init(first_screen_name);
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.h b/chrome/browser/chromeos/login/ui/login_display_host_impl.h index 9d31b2f..f12b77d 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_impl.h +++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.h
@@ -308,6 +308,9 @@ // The bounds of the virtual keyboard. gfx::Rect keyboard_bounds_; + // True if the host is showing a new version of OOBE screen. + bool is_new_oobe_; + base::WeakPtrFactory<LoginDisplayHostImpl> pointer_factory_; base::WeakPtrFactory<LoginDisplayHostImpl> animation_weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc index 20a9d98..ef44c39 100644 --- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc +++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -307,6 +307,8 @@ base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); wallpaper_loader_ = new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC, task_runner_); + + user_manager::UserManager::Get()->AddSessionStateObserver(this); } WallpaperManager::~WallpaperManager() { @@ -314,6 +316,8 @@ // http://crbug.com/171694 DCHECK(!show_user_name_on_signin_subscription_); + user_manager::UserManager::Get()->RemoveSessionStateObserver(this); + ClearObsoleteWallpaperPrefs(); weak_factory_.InvalidateWeakPtrs(); } @@ -966,6 +970,10 @@ return loading_.size(); } +void WallpaperManager::UserChangedChildStatus(user_manager::User* user) { + SetUserWallpaperNow(user->email()); +} + void WallpaperManager::OnDefaultWallpaperDecoded( const base::FilePath& path, const wallpaper::WallpaperLayout layout,
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h index 14eec18..536d752d 100644 --- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h +++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
@@ -21,6 +21,7 @@ #include "chrome/browser/chromeos/settings/cros_settings.h" #include "components/user_manager/user.h" #include "components/user_manager/user_image/user_image.h" +#include "components/user_manager/user_manager.h" #include "components/wallpaper/wallpaper_layout.h" #include "components/wallpaper/wallpaper_manager_base.h" #include "content/public/browser/notification_observer.h" @@ -30,7 +31,9 @@ namespace chromeos { -class WallpaperManager : public wallpaper::WallpaperManagerBase { +class WallpaperManager : + public wallpaper::WallpaperManagerBase, + public user_manager::UserManager::UserSessionStateObserver { public: class PendingWallpaper; @@ -115,6 +118,9 @@ // Returns queue size. size_t GetPendingListSizeForTesting() const override; + // Overridden from user_manager::UserManager::UserSessionStateObserver: + void UserChangedChildStatus(user_manager::User* user) override; + private: friend class TestApi; friend class WallpaperManagerBrowserTest;
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.cc b/chrome/browser/chromeos/net/network_portal_detector_impl.cc index 302318e..461241b 100644 --- a/chrome/browser/chromeos/net/network_portal_detector_impl.cc +++ b/chrome/browser/chromeos/net/network_portal_detector_impl.cc
@@ -332,6 +332,10 @@ StartDetectionIfIdle(); } +void NetworkPortalDetectorImpl::OnLockScreenRequest() { + notification_controller_.CloseDialog(); +} + void NetworkPortalDetectorImpl::DefaultNetworkChanged( const NetworkState* default_network) { DCHECK(CalledOnValidThread());
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.h b/chrome/browser/chromeos/net/network_portal_detector_impl.h index b02f1e2..4f5091e 100644 --- a/chrome/browser/chromeos/net/network_portal_detector_impl.h +++ b/chrome/browser/chromeos/net/network_portal_detector_impl.h
@@ -76,6 +76,7 @@ void Enable(bool start_detection) override; bool StartDetectionIfIdle() override; void SetStrategy(PortalDetectorStrategy::StrategyId id) override; + void OnLockScreenRequest() override; // NetworkStateHandlerObserver implementation: void DefaultNetworkChanged(const NetworkState* network) override;
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc b/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc index a33dd88..7d064a24 100644 --- a/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc +++ b/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc
@@ -2,15 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/command_line.h" #include "base/compiler_specific.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" +#include "base/prefs/pref_service.h" #include "base/run_loop.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/login/login_manager_test.h" #include "chrome/browser/chromeos/login/startup_utils.h" #include "chrome/browser/chromeos/net/network_portal_detector_impl.h" #include "chrome/browser/chromeos/net/network_portal_detector_test_utils.h" +#include "chrome/browser/chromeos/net/network_portal_notification_controller.h" +#include "chrome/browser/prefs/pref_service_syncable.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/common/pref_names.h" #include "chromeos/chromeos_switches.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/shill_service_client.h" @@ -20,6 +27,7 @@ #include "content/public/test/test_utils.h" #include "dbus/object_path.h" #include "net/base/net_errors.h" +#include "testing/gtest/include/gtest/gtest.h" #include "third_party/cros_system_api/dbus/service_constants.h" #include "ui/message_center/message_center.h" #include "ui/message_center/message_center_observer.h" @@ -30,6 +38,8 @@ namespace chromeos { +class NetworkPortalWebDialog; + namespace { const char* const kNotificationId = @@ -139,6 +149,16 @@ MessageCenter* message_center() { return MessageCenter::Get(); } + void SetIgnoreNoNetworkForTesting() { + network_portal_detector_->notification_controller_ + .SetIgnoreNoNetworkForTesting(); + } + + const NetworkPortalWebDialog* GetDialog() const { + return network_portal_detector_->notification_controller_ + .GetDialogForTesting(); + } + private: NetworkPortalDetectorImpl* network_portal_detector_; @@ -201,4 +221,90 @@ action_checker.Expect(Controller::USER_ACTION_METRIC_CLOSED, 1)->Check()); } +class NetworkPortalDetectorImplBrowserTestIgnoreProxy + : public NetworkPortalDetectorImplBrowserTest, + public testing::WithParamInterface<bool> { + public: + NetworkPortalDetectorImplBrowserTestIgnoreProxy() + : NetworkPortalDetectorImplBrowserTest() {} + + void SetUpCommandLine(base::CommandLine* command_line) override { + NetworkPortalDetectorImplBrowserTest::SetUpCommandLine(command_line); + + command_line->AppendSwitch( + chromeos::switches::kEnableCaptivePortalBypassProxyOption); + } + + protected: + void TestImpl(const bool preference_value); + + DISALLOW_COPY_AND_ASSIGN(NetworkPortalDetectorImplBrowserTestIgnoreProxy); +}; + +void NetworkPortalDetectorImplBrowserTestIgnoreProxy::TestImpl( + const bool preference_value) { + using Controller = NetworkPortalNotificationController; + + TestObserver observer; + + EnumHistogramChecker ui_checker( + kNotificationMetric, Controller::NOTIFICATION_METRIC_COUNT, nullptr); + EnumHistogramChecker action_checker( + kUserActionMetric, Controller::USER_ACTION_METRIC_COUNT, nullptr); + + LoginUser(kTestUser); + content::RunAllPendingInMessageLoop(); + + SetIgnoreNoNetworkForTesting(); + + ProfileManager::GetActiveUserProfile()->GetPrefs()->SetBoolean( + prefs::kCaptivePortalAuthenticationIgnoresProxy, preference_value); + + // User connects to wifi. + SetConnected(kWifiServicePath); + + EXPECT_EQ(PortalDetectorStrategy::STRATEGY_ID_SESSION, strategy()->Id()); + + // No notification until portal detection is completed. + EXPECT_FALSE(message_center()->FindVisibleNotificationById(kNotificationId)); + RestartDetection(); + CompleteURLFetch(net::OK, 200, nullptr); + + // Check that WiFi is marked as behind a portal and that a notification + // is displayed. + EXPECT_TRUE(message_center()->FindVisibleNotificationById(kNotificationId)); + EXPECT_EQ( + NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, + NetworkPortalDetector::Get()->GetCaptivePortalState(kWifiGuid).status); + + // Wait until notification is displayed. + observer.WaitAndReset(); + + EXPECT_TRUE( + ui_checker.Expect(Controller::NOTIFICATION_METRIC_DISPLAYED, 1)->Check()); + EXPECT_TRUE(action_checker.Check()); + + message_center()->ClickOnNotification(kNotificationId); + + content::RunAllPendingInMessageLoop(); + + EXPECT_EQ(preference_value, static_cast<bool>(GetDialog())); +} + +IN_PROC_BROWSER_TEST_P(NetworkPortalDetectorImplBrowserTestIgnoreProxy, + PRE_TestWithPreference) { + RegisterUser(kTestUser); + StartupUtils::MarkOobeCompleted(); + EXPECT_EQ(PortalDetectorStrategy::STRATEGY_ID_LOGIN_SCREEN, strategy()->Id()); +} + +IN_PROC_BROWSER_TEST_P(NetworkPortalDetectorImplBrowserTestIgnoreProxy, + TestWithPreference) { + TestImpl(GetParam()); +} + +INSTANTIATE_TEST_CASE_P(CaptivePortalAuthenticationIgnoresProxy, + NetworkPortalDetectorImplBrowserTestIgnoreProxy, + testing::Bool()); + } // namespace chromeos
diff --git a/chrome/browser/chromeos/net/network_portal_detector_test_impl.cc b/chrome/browser/chromeos/net/network_portal_detector_test_impl.cc index fafada0..2c4e8bd 100644 --- a/chrome/browser/chromeos/net/network_portal_detector_test_impl.cc +++ b/chrome/browser/chromeos/net/network_portal_detector_test_impl.cc
@@ -95,4 +95,7 @@ strategy_id_ = id; } +void NetworkPortalDetectorTestImpl::OnLockScreenRequest() { +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/net/network_portal_detector_test_impl.h b/chrome/browser/chromeos/net/network_portal_detector_test_impl.h index 033d325..70ecf1c 100644 --- a/chrome/browser/chromeos/net/network_portal_detector_test_impl.h +++ b/chrome/browser/chromeos/net/network_portal_detector_test_impl.h
@@ -37,6 +37,7 @@ bool StartDetectionIfIdle() override; void SetStrategy(PortalDetectorStrategy::StrategyId id) override; + void OnLockScreenRequest() override; PortalDetectorStrategy::StrategyId strategy_id() const { return strategy_id_;
diff --git a/chrome/browser/chromeos/net/network_portal_notification_controller.cc b/chrome/browser/chromeos/net/network_portal_notification_controller.cc index d9461a0e..eacf5e4 100644 --- a/chrome/browser/chromeos/net/network_portal_notification_controller.cc +++ b/chrome/browser/chromeos/net/network_portal_notification_controller.cc
@@ -16,10 +16,12 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" +#include "base/prefs/pref_service.h" #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/mobile/mobile_activator.h" #include "chrome/browser/chromeos/net/network_portal_web_dialog.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" @@ -29,6 +31,7 @@ #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" #include "chrome/browser/ui/singleton_tabs.h" +#include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "chrome/grit/theme_resources.h" #include "chromeos/chromeos_switches.h" @@ -162,22 +165,22 @@ NetworkPortalNotificationController::USER_ACTION_METRIC_CLICKED, NetworkPortalNotificationController::USER_ACTION_METRIC_COUNT); - // ConsumerManagementService may not exist in tests. - const policy::ConsumerManagementService* consumer_management_service = - g_browser_process->platform_part() - ->browser_policy_connector_chromeos() - ->GetConsumerManagementService(); - const bool enrolled = consumer_management_service && - consumer_management_service->GetStatus() == - policy::ConsumerManagementService::STATUS_ENROLLED; + Profile* profile = ProfileManager::GetActiveUserProfile(); - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - chromeos::switches::kEnableCaptivePortalBypassProxy) && - !enrolled) { + const bool bypass_proxy_switch_present = + base::CommandLine::ForCurrentProcess()->HasSwitch( + chromeos::switches::kEnableCaptivePortalBypassProxyOption); + const bool use_incognito_profile = + bypass_proxy_switch_present + ? (profile && + profile->GetPrefs()->GetBoolean( + prefs::kCaptivePortalAuthenticationIgnoresProxy)) + : false; + + if (use_incognito_profile) { if (controller_) controller_->ShowDialog(); } else { - Profile* profile = ProfileManager::GetActiveUserProfile(); if (!profile) return; chrome::ScopedTabbedBrowserDisplayer displayer( @@ -220,7 +223,7 @@ "CaptivePortal.Notification.UserAction"; NetworkPortalNotificationController::NetworkPortalNotificationController() - : dialog_(nullptr) { + : dialog_(nullptr), ignore_no_network_for_testing_(false) { } NetworkPortalNotificationController::~NetworkPortalNotificationController() { @@ -251,8 +254,14 @@ state.status != NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL) { last_network_path_.clear(); - if (dialog_) + // In browser tests we initiate fake network portal detection, but network + // state usually stays connected. This way, after dialog is shown, it is + // immediately closed. The testing check below prevents dialog from closing. + if (dialog_ && + (!ignore_no_network_for_testing_ || + state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE)) { dialog_->Close(); + } CloseNotification(); return; @@ -394,4 +403,18 @@ } } +void NetworkPortalNotificationController::SetIgnoreNoNetworkForTesting() { + ignore_no_network_for_testing_ = true; +} + +void NetworkPortalNotificationController::CloseDialog() { + if (dialog_) + dialog_->Close(); +} + +const NetworkPortalWebDialog* +NetworkPortalNotificationController::GetDialogForTesting() const { + return dialog_; +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/net/network_portal_notification_controller.h b/chrome/browser/chromeos/net/network_portal_notification_controller.h index 10c1984e..5470f9f 100644 --- a/chrome/browser/chromeos/net/network_portal_notification_controller.h +++ b/chrome/browser/chromeos/net/network_portal_notification_controller.h
@@ -63,9 +63,19 @@ // Creates NetworkPortalWebDialog. void ShowDialog(); + // Destroys NetworkPortalWebDialog. + void CloseDialog(); + // NULLifies reference to the active dialog. void OnDialogDestroyed(const NetworkPortalWebDialog* dialog); + // Ignores "No network" errors in browser tests. + void SetIgnoreNoNetworkForTesting(); + + // Browser tests should be able to verify that NetworkPortalWebDialog is + // shown. + const NetworkPortalWebDialog* GetDialogForTesting() const; + private: // Creates the default notification informing the user that a captive portal // has been detected. On click the captive portal login page is opened in the @@ -96,6 +106,9 @@ // Currently displayed authorization dialog, or NULL if none. NetworkPortalWebDialog* dialog_; + // Do not close Portal Login dialog on "No network" error in browser tests. + bool ignore_no_network_for_testing_; + DISALLOW_COPY_AND_ASSIGN(NetworkPortalNotificationController); };
diff --git a/chrome/browser/chromeos/oobe/oobe.cc b/chrome/browser/chromeos/oobe/oobe.cc new file mode 100644 index 0000000..bd98074 --- /dev/null +++ b/chrome/browser/chromeos/oobe/oobe.cc
@@ -0,0 +1,34 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/prefs/pref_service.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/oobe/oobe.h" +#include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/common/pref_names.h" + +namespace chromeos { + +// static +void Oobe::Register() { + gen::OobeViewModel::SetFactory( + [](content::BrowserContext* context) + -> gen::OobeViewModel* { return new Oobe(); }); +} + +Oobe::Oobe() { +} + +Oobe::~Oobe() { +} + +void Oobe::Initialize() { +} + +void Oobe::OnButtonClicked() { + g_browser_process->local_state()->SetBoolean(prefs::kNewOobe, false); + chrome::AttemptRestart(); +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/oobe/oobe.h b/chrome/browser/chromeos/oobe/oobe.h new file mode 100644 index 0000000..6e36cc0 --- /dev/null +++ b/chrome/browser/chromeos/oobe/oobe.h
@@ -0,0 +1,31 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_OOBE_OOBE_H_ +#define CHROME_BROWSER_CHROMEOS_OOBE_OOBE_H_ + +#include "base/macros.h" +#include "ui/oobe/declarations/oobe_view_model.h" + +namespace chromeos { + +class Oobe : public gen::OobeViewModel { + public: + Oobe(); + ~Oobe() override; + + static void Register(); + + // Overridden from wug::ViewModel: + void Initialize() override; + + private: + void OnButtonClicked() override; + + DISALLOW_COPY_AND_ASSIGN(Oobe); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_OOBE_OOBE_H_
diff --git a/chrome/browser/chromeos/policy/power_policy_browsertest.cc b/chrome/browser/chromeos/policy/power_policy_browsertest.cc index 37b89884..4345ab3 100644 --- a/chrome/browser/chromeos/policy/power_policy_browsertest.cc +++ b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
@@ -49,7 +49,7 @@ #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" #include "content/public/test/test_utils.h" -#include "extensions/browser/api/power/power_api_manager.h" +#include "extensions/browser/api/power/power_api.h" #include "extensions/common/api/power.h" #include "policy/proto/device_management_backend.pb.h" #include "testing/gmock/include/gmock/gmock.h" @@ -482,8 +482,8 @@ // Pretend an extension grabs a screen wake lock. const char kExtensionId[] = "abcdefghijklmnopabcdefghijlkmnop"; - extensions::PowerApiManager::Get(browser()->profile())->AddRequest( - kExtensionId, extensions::core_api::power::LEVEL_DISPLAY); + extensions::PowerAPI::Get(browser()->profile()) + ->AddRequest(kExtensionId, extensions::core_api::power::LEVEL_DISPLAY); base::RunLoop().RunUntilIdle(); // Check that the lock is in effect (ignoring ac_idle_action,
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc index d2699d4d..d630d653 100644 --- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc +++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
@@ -120,6 +120,11 @@ POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, new base::FundamentalValue(false), NULL); + policy_map_.Set(key::kCaptivePortalAuthenticationIgnoresProxy, + POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, + new base::FundamentalValue(false), + NULL); expected_bundle_.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())) .CopyFrom(policy_map_);
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc index 32babb7c..5363a31 100644 --- a/chrome/browser/chromeos/preferences.cc +++ b/chrome/browser/chromeos/preferences.cc
@@ -318,11 +318,15 @@ false, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); + input_method::InputMethodSyncer::RegisterProfilePrefs(registry); + registry->RegisterBooleanPref( prefs::kResolveTimezoneByGeolocation, true, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); - input_method::InputMethodSyncer::RegisterProfilePrefs(registry); + registry->RegisterBooleanPref( + prefs::kCaptivePortalAuthenticationIgnoresProxy, true, + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); } void Preferences::InitUserPrefs(PrefServiceSyncable* prefs) {
diff --git a/chrome/browser/chromeos/system/pointer_device_observer.cc b/chrome/browser/chromeos/system/pointer_device_observer.cc index 2de1305..125e3af 100644 --- a/chrome/browser/chromeos/system/pointer_device_observer.cc +++ b/chrome/browser/chromeos/system/pointer_device_observer.cc
@@ -11,10 +11,6 @@ #include "content/public/browser/browser_thread.h" #include "ui/events/devices/device_data_manager.h" -#if defined(USE_X11) -#include "chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener.h" -#endif - using content::BrowserThread; namespace chromeos { @@ -25,21 +21,11 @@ } PointerDeviceObserver::~PointerDeviceObserver() { -#if defined(USE_X11) - XInputHierarchyChangedEventListener::GetInstance() - ->RemoveObserver(this); -#elif defined(USE_OZONE) ui::DeviceDataManager::GetInstance()->RemoveObserver(this); -#endif } void PointerDeviceObserver::Init() { -#if defined(USE_X11) - XInputHierarchyChangedEventListener::GetInstance() - ->AddObserver(this); -#elif defined(USE_OZONE) ui::DeviceDataManager::GetInstance()->AddObserver(this); -#endif } void PointerDeviceObserver::CheckDevices() { @@ -55,10 +41,6 @@ observers_.RemoveObserver(observer); } -void PointerDeviceObserver::DeviceHierarchyChanged() { - CheckDevices(); -} - void PointerDeviceObserver::OnMouseDeviceConfigurationChanged() { CheckDevices(); }
diff --git a/chrome/browser/chromeos/system/pointer_device_observer.h b/chrome/browser/chromeos/system/pointer_device_observer.h index 1415c44..c813da49 100644 --- a/chrome/browser/chromeos/system/pointer_device_observer.h +++ b/chrome/browser/chromeos/system/pointer_device_observer.h
@@ -7,14 +7,12 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" -#include "chrome/browser/chromeos/device_hierarchy_observer.h" #include "ui/events/devices/input_device_event_observer.h" namespace chromeos { namespace system { -class PointerDeviceObserver : public DeviceHierarchyObserver, - public ui::InputDeviceEventObserver { +class PointerDeviceObserver : public ui::InputDeviceEventObserver { public: PointerDeviceObserver(); ~PointerDeviceObserver() override; @@ -38,11 +36,6 @@ void RemoveObserver(Observer* observer); private: - // DeviceHierarchyObserver: - void DeviceHierarchyChanged() override; - void DeviceAdded(int device_id) override {} - void DeviceRemoved(int device_id) override {} - // InputDeviceEventObserver: void OnMouseDeviceConfigurationChanged() override; void OnTouchpadDeviceConfigurationChanged() override;
diff --git a/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc b/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc index 9a0c708..3e42ead 100644 --- a/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc +++ b/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc
@@ -125,9 +125,9 @@ // Read a manifest file in. base::DictionaryValue* ReadJSONManifest(const base::FilePath& manifest_path) { - JSONFileValueSerializer serializer(manifest_path); + JSONFileValueDeserializer deserializer(manifest_path); std::string error; - scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error)); + scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, &error)); if (!root.get()) return NULL; if (!root->IsType(base::Value::TYPE_DICTIONARY))
diff --git a/chrome/browser/component_updater/recovery_component_installer.cc b/chrome/browser/component_updater/recovery_component_installer.cc index 20898059..34e5303 100644 --- a/chrome/browser/component_updater/recovery_component_installer.cc +++ b/chrome/browser/component_updater/recovery_component_installer.cc
@@ -90,9 +90,9 @@ #if defined(OS_WIN) scoped_ptr<base::DictionaryValue> ReadManifest(const base::FilePath& manifest) { - JSONFileValueSerializer serializer(manifest); + JSONFileValueDeserializer deserializer(manifest); std::string error; - scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error)); + scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, &error)); if (root.get() && root->IsType(base::Value::TYPE_DICTIONARY)) { return scoped_ptr<base::DictionaryValue>( static_cast<base::DictionaryValue*>(root.release()));
diff --git a/chrome/browser/component_updater/test/component_installers_unittest.cc b/chrome/browser/component_updater/test/component_installers_unittest.cc index e94ccb7c..8cb58d0c 100644 --- a/chrome/browser/component_updater/test/component_installers_unittest.cc +++ b/chrome/browser/component_updater/test/component_installers_unittest.cc
@@ -73,10 +73,10 @@ return; } - JSONFileValueSerializer serializer(manifest); + JSONFileValueDeserializer deserializer(manifest); std::string error; scoped_ptr<base::DictionaryValue> root(static_cast<base::DictionaryValue*>( - serializer.Deserialize(NULL, &error))); + deserializer.Deserialize(NULL, &error))); ASSERT_TRUE(root); ASSERT_TRUE(root->IsType(base::Value::TYPE_DICTIONARY));
diff --git a/chrome/browser/content_settings/content_settings_supervised_provider.cc b/chrome/browser/content_settings/content_settings_supervised_provider.cc new file mode 100644 index 0000000..f448a0d --- /dev/null +++ b/chrome/browser/content_settings/content_settings_supervised_provider.cc
@@ -0,0 +1,101 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/content_settings/content_settings_supervised_provider.h" + +#include <string> +#include <vector> + +#include "chrome/browser/supervised_user/supervised_user_constants.h" +#include "chrome/browser/supervised_user/supervised_user_settings_service.h" + +namespace { + +struct ContentSettingsFromSupervisedSettingsEntry { + const char* setting_name; + ContentSettingsType content_type; +}; + +const ContentSettingsFromSupervisedSettingsEntry + kContentSettingsFromSupervisedSettingsMap[] = { + { + supervised_users::kGeolocationDisabled, + CONTENT_SETTINGS_TYPE_GEOLOCATION, + }, { + supervised_users::kCameraMicDisabled, + CONTENT_SETTINGS_TYPE_MEDIASTREAM, + } +}; + +} // namespace + +namespace content_settings { + +SupervisedProvider::SupervisedProvider( + SupervisedUserSettingsService* supervised_user_settings_service) + : weak_ptr_factory_(this) { + supervised_user_settings_service->Subscribe(base::Bind( + &content_settings::SupervisedProvider::OnSupervisedSettingsAvailable, + weak_ptr_factory_.GetWeakPtr())); +} + +SupervisedProvider::~SupervisedProvider() { +} + +RuleIterator* SupervisedProvider::GetRuleIterator( + ContentSettingsType content_type, + const ResourceIdentifier& resource_identifier, + bool incognito) const { + scoped_ptr<base::AutoLock> auto_lock(new base::AutoLock(lock_)); + return value_map_.GetRuleIterator(content_type, resource_identifier, + auto_lock.Pass()); +} + +void SupervisedProvider::OnSupervisedSettingsAvailable( + const base::DictionaryValue* settings) { + if (!settings) + return; + std::vector<ContentSettingsType> to_notify; + // Entering locked scope to update content settings. + { + base::AutoLock auto_lock(lock_); + bool new_value, old_value; + for (const auto& entry : kContentSettingsFromSupervisedSettingsMap) { + if (settings->GetBoolean(entry.setting_name, &new_value)) { + old_value = !value_map_.IsContentSettingEnabled(entry.content_type); + if (new_value != old_value) { + to_notify.push_back(entry.content_type); + value_map_.SetContentSettingDisabled(entry.content_type, new_value); + } + } + } + } + for (const auto& notification : to_notify) { + NotifyObservers(ContentSettingsPattern(), ContentSettingsPattern(), + notification, std::string()); + } +} + +// Since the SupervisedProvider is a read only content settings provider, all +// methods of the ProviderInterface that set or delete any settings do nothing. +bool SupervisedProvider::SetWebsiteSetting( + const ContentSettingsPattern& primary_pattern, + const ContentSettingsPattern& secondary_pattern, + ContentSettingsType content_type, + const ResourceIdentifier& resource_identifier, + base::Value* value) { + return false; +} + +void SupervisedProvider::ClearAllContentSettingsRules( + ContentSettingsType content_type) { +} + +void SupervisedProvider::ShutdownOnUIThread() { + DCHECK(CalledOnValidThread()); + RemoveAllObservers(); + weak_ptr_factory_.InvalidateWeakPtrs(); +} + +} // namespace content_settings
diff --git a/chrome/browser/content_settings/content_settings_supervised_provider.h b/chrome/browser/content_settings/content_settings_supervised_provider.h new file mode 100644 index 0000000..3a3ee13 --- /dev/null +++ b/chrome/browser/content_settings/content_settings_supervised_provider.h
@@ -0,0 +1,59 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_SUPERVISED_PROVIDER_H_ +#define CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_SUPERVISED_PROVIDER_H_ + +// A content setting provider that is set by the custodian of a supervised user. + +#include "base/synchronization/lock.h" +#include "components/content_settings/core/browser/content_settings_binary_value_map.h" +#include "components/content_settings/core/browser/content_settings_observable_provider.h" + +class PrefService; +class SupervisedUserSettingsService; + +namespace content_settings { + +// SupervisedProvider that provides content-settings managed by the custodian +// of a supervised user. +class SupervisedProvider : public ObservableProvider { + public: + explicit SupervisedProvider( + SupervisedUserSettingsService* supervised_user_settings_service); + ~SupervisedProvider() override; + + // ProviderInterface implementations. + RuleIterator* GetRuleIterator(ContentSettingsType content_type, + const ResourceIdentifier& resource_identifier, + bool incognito) const override; + + bool SetWebsiteSetting(const ContentSettingsPattern& primary_pattern, + const ContentSettingsPattern& secondary_pattern, + ContentSettingsType content_type, + const ResourceIdentifier& resource_identifier, + base::Value* value) override; + + void ClearAllContentSettingsRules(ContentSettingsType content_type) override; + + void ShutdownOnUIThread() override; + + // Callback on receiving settings from the supervised user settings service. + void OnSupervisedSettingsAvailable(const base::DictionaryValue* settings); + + private: + BinaryValueMap value_map_; + + // Used around accesses to the |value_map_| object to guarantee + // thread safety. + mutable base::Lock lock_; + + base::WeakPtrFactory<SupervisedProvider> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(SupervisedProvider); +}; + +} // namespace content_settings + +#endif // CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_SUPERVISED_PROVIDER_H_
diff --git a/chrome/browser/content_settings/permission_bubble_request_impl.cc b/chrome/browser/content_settings/permission_bubble_request_impl.cc index 5d7e6be..3fc8bed 100644 --- a/chrome/browser/content_settings/permission_bubble_request_impl.cc +++ b/chrome/browser/content_settings/permission_bubble_request_impl.cc
@@ -16,7 +16,7 @@ bool user_gesture, ContentSettingsType type, const std::string& display_languages, - const base::Callback<void(bool, bool)> permission_decided_callback, + const PermissionDecidedCallback& permission_decided_callback, const base::Closure delete_callback) : request_origin_(request_origin), user_gesture_(user_gesture), @@ -136,17 +136,17 @@ void PermissionBubbleRequestImpl::PermissionGranted() { RegisterActionTaken(); - permission_decided_callback_.Run(true, true); + permission_decided_callback_.Run(true, CONTENT_SETTING_ALLOW); } void PermissionBubbleRequestImpl::PermissionDenied() { RegisterActionTaken(); - permission_decided_callback_.Run(true, false); + permission_decided_callback_.Run(true, CONTENT_SETTING_BLOCK); } void PermissionBubbleRequestImpl::Cancelled() { RegisterActionTaken(); - permission_decided_callback_.Run(false, false); + permission_decided_callback_.Run(false, CONTENT_SETTING_DEFAULT); } void PermissionBubbleRequestImpl::RequestFinished() {
diff --git a/chrome/browser/content_settings/permission_bubble_request_impl.h b/chrome/browser/content_settings/permission_bubble_request_impl.h index caf05b7..985c9d0 100644 --- a/chrome/browser/content_settings/permission_bubble_request_impl.h +++ b/chrome/browser/content_settings/permission_bubble_request_impl.h
@@ -7,6 +7,7 @@ #include "base/callback.h" #include "chrome/browser/ui/website_settings/permission_bubble_request.h" +#include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings_types.h" #include "components/content_settings/core/common/permission_request_id.h" @@ -19,16 +20,14 @@ // is executed. class PermissionBubbleRequestImpl : public PermissionBubbleRequest { public: - - typedef base::Callback<void(bool persist_permission, bool grant_permission)> - PermissionDecidedCallback; + using PermissionDecidedCallback = base::Callback<void(bool, ContentSetting)>; PermissionBubbleRequestImpl( const GURL& request_origin, bool user_gesture, ContentSettingsType type, const std::string& display_languages, - const PermissionDecidedCallback permission_decided_callback, + const PermissionDecidedCallback& permission_decided_callback, const base::Closure delete_callback); ~PermissionBubbleRequestImpl() override;
diff --git a/chrome/browser/content_settings/permission_context_base.cc b/chrome/browser/content_settings/permission_context_base.cc index c188377..711dbe5 100644 --- a/chrome/browser/content_settings/permission_context_base.cc +++ b/chrome/browser/content_settings/permission_context_base.cc
@@ -99,8 +99,8 @@ << "," << embedding_origin << " (" << content_settings::GetTypeName(permission_type_) << " is not supported in popups)"; - NotifyPermissionSet(id, requesting_origin, embedding_origin, - callback, false /* persist */, false /* granted */); + NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, + false /* persist */, CONTENT_SETTING_BLOCK); return; } @@ -110,17 +110,11 @@ requesting_origin, embedding_origin, permission_type_, std::string()); - switch (content_setting) { - case CONTENT_SETTING_BLOCK: - NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, - false /* persist */, false /* granted */); - return; - case CONTENT_SETTING_ALLOW: - NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, - false /* persist */, true /* granted */); - return; - default: - break; + if (content_setting == CONTENT_SETTING_ALLOW || + content_setting == CONTENT_SETTING_BLOCK) { + NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, + false /* persist */, content_setting); + return; } PermissionContextUmaUtil::PermissionRequested( @@ -168,25 +162,28 @@ const GURL& embedding_origin, const BrowserPermissionCallback& callback, bool persist, - bool allowed) { + ContentSetting content_setting) { // Infobar persistance and its related UMA is tracked on the infobar // controller directly. if (PermissionBubbleManager::Enabled()) { if (persist) { - if (allowed) + DCHECK(content_setting == CONTENT_SETTING_ALLOW || + content_setting == CONTENT_SETTING_BLOCK); + if (CONTENT_SETTING_ALLOW) PermissionContextUmaUtil::PermissionGranted(permission_type_, requesting_origin); else PermissionContextUmaUtil::PermissionDenied(permission_type_, requesting_origin); } else { + DCHECK_EQ(content_setting, CONTENT_SETTING_DEFAULT); PermissionContextUmaUtil::PermissionDismissed(permission_type_, requesting_origin); } } NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, - persist, allowed); + persist, content_setting); } PermissionQueueController* PermissionContextBase::GetQueueController() { @@ -203,13 +200,23 @@ const GURL& embedding_origin, const BrowserPermissionCallback& callback, bool persist, - bool allowed) { + ContentSetting content_setting) { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - if (persist) - UpdateContentSetting(requesting_origin, embedding_origin, allowed); - UpdateTabContext(id, requesting_origin, allowed); - callback.Run(allowed); + if (persist) + UpdateContentSetting(requesting_origin, embedding_origin, content_setting); + + UpdateTabContext(id, requesting_origin, + content_setting == CONTENT_SETTING_ALLOW); + + if (content_setting == CONTENT_SETTING_DEFAULT) { + content_setting = + profile_->GetHostContentSettingsMap()->GetDefaultContentSetting( + permission_type_, nullptr); + } + + DCHECK_NE(content_setting, CONTENT_SETTING_DEFAULT); + callback.Run(content_setting); } void PermissionContextBase::CleanUpBubble(const PermissionRequestID& id) { @@ -217,13 +224,15 @@ DCHECK(success == 1) << "Missing request " << id.ToString(); } -void PermissionContextBase::UpdateContentSetting(const GURL& requesting_origin, - const GURL& embedding_origin, - bool allowed) { +void PermissionContextBase::UpdateContentSetting( + const GURL& requesting_origin, + const GURL& embedding_origin, + ContentSetting content_setting) { DCHECK_EQ(requesting_origin, requesting_origin.GetOrigin()); DCHECK_EQ(embedding_origin, embedding_origin.GetOrigin()); - ContentSetting content_setting = - allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; + DCHECK(content_setting == CONTENT_SETTING_ALLOW || + content_setting == CONTENT_SETTING_BLOCK); + profile_->GetHostContentSettingsMap()->SetContentSetting( ContentSettingsPattern::FromURLNoWildcard(requesting_origin), ContentSettingsPattern::FromURLNoWildcard(embedding_origin),
diff --git a/chrome/browser/content_settings/permission_context_base.h b/chrome/browser/content_settings/permission_context_base.h index 740aa8f..e727ce9 100644 --- a/chrome/browser/content_settings/permission_context_base.h +++ b/chrome/browser/content_settings/permission_context_base.h
@@ -23,7 +23,7 @@ class WebContents; } -typedef base::Callback<void(bool)> BrowserPermissionCallback; +using BrowserPermissionCallback = base::Callback<void(ContentSetting)>; // This base class contains common operations for granting permissions. // It offers the following functionality: @@ -95,14 +95,14 @@ const GURL& embedding_origin, const BrowserPermissionCallback& callback, bool persist, - bool allowed); + ContentSetting content_setting); virtual void NotifyPermissionSet(const PermissionRequestID& id, const GURL& requesting_origin, const GURL& embedding_origin, const BrowserPermissionCallback& callback, bool persist, - bool allowed); + ContentSetting content_setting); // Implementors can override this method to update the icons on the // url bar with the result of the new permission. @@ -121,7 +121,7 @@ // (for example for desktop notifications). virtual void UpdateContentSetting(const GURL& requesting_origin, const GURL& embedding_origin, - bool allowed); + ContentSetting content_setting); private: // Called when a bubble is no longer used so it can be cleaned up.
diff --git a/chrome/browser/content_settings/permission_context_base_unittest.cc b/chrome/browser/content_settings/permission_context_base_unittest.cc index 01cd4e1..d43250d 100644 --- a/chrome/browser/content_settings/permission_context_base_unittest.cc +++ b/chrome/browser/content_settings/permission_context_base_unittest.cc
@@ -48,9 +48,9 @@ return tab_context_updated_; } - void TrackPermissionDecision(bool granted) { + void TrackPermissionDecision(ContentSetting content_setting) { permission_set_ = true; - permission_granted_ = granted; + permission_granted_ = content_setting == CONTENT_SETTING_ALLOW; } protected:
diff --git a/chrome/browser/content_settings/permission_queue_controller.cc b/chrome/browser/content_settings/permission_queue_controller.cc index 9747ce7..c0a6531 100644 --- a/chrome/browser/content_settings/permission_queue_controller.cc +++ b/chrome/browser/content_settings/permission_queue_controller.cc
@@ -45,7 +45,7 @@ const PermissionRequestID& id, const GURL& requesting_frame, const GURL& embedder, - PermissionDecidedCallback callback); + const PermissionDecidedCallback& callback); ~PendingInfobarRequest(); bool IsForPair(const GURL& requesting_frame, @@ -56,7 +56,7 @@ bool has_infobar() const { return !!infobar_; } infobars::InfoBar* infobar() { return infobar_; } - void RunCallback(bool allowed); + void RunCallback(ContentSetting content_setting); void CreateInfoBar(PermissionQueueController* controller, const std::string& display_languages); @@ -76,7 +76,7 @@ const PermissionRequestID& id, const GURL& requesting_frame, const GURL& embedder, - PermissionDecidedCallback callback) + const PermissionDecidedCallback& callback) : type_(type), id_(id), requesting_frame_(requesting_frame), @@ -95,8 +95,8 @@ } void PermissionQueueController::PendingInfobarRequest::RunCallback( - bool allowed) { - callback_.Run(allowed); + ContentSetting content_setting) { + callback_.Run(content_setting); } void PermissionQueueController::PendingInfobarRequest::CreateInfoBar( @@ -152,7 +152,7 @@ const PermissionRequestID& id, const GURL& requesting_frame, const GURL& embedder, - PermissionDecidedCallback callback) { + const PermissionDecidedCallback& callback) { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); if (requesting_frame.SchemeIs(content::kChromeUIScheme) || @@ -235,10 +235,20 @@ i != infobars_to_remove.end(); ++i) GetInfoBarService(i->id())->RemoveInfoBar(i->infobar()); + // PermissionContextBase needs to know about the new ContentSetting value, + // CONTENT_SETTING_DEFAULT being the value for nothing happened. The callers + // of ::OnPermissionSet passes { true, true } for allow, { true, false } for + // block and { false, * } for dismissed. The tuple being + // { update_content_setting, allowed }. + ContentSetting content_setting = CONTENT_SETTING_DEFAULT; + if (update_content_setting) { + content_setting = allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; + } + // Send out the permission notifications. for (PendingInfobarRequests::iterator i = requests_to_notify.begin(); i != requests_to_notify.end(); ++i) - i->RunCallback(allowed); + i->RunCallback(content_setting); // Remove the pending requests in reverse order. for (int i = pending_requests_to_remove.size() - 1; i >= 0; --i)
diff --git a/chrome/browser/content_settings/permission_queue_controller.h b/chrome/browser/content_settings/permission_queue_controller.h index ba2dbd42..3e856b6a 100644 --- a/chrome/browser/content_settings/permission_queue_controller.h +++ b/chrome/browser/content_settings/permission_queue_controller.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_CONTENT_SETTINGS_PERMISSION_QUEUE_CONTROLLER_H_ #include "base/bind.h" +#include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings_types.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -25,7 +26,7 @@ // the notification infrastructure would simplify. class PermissionQueueController : public content::NotificationObserver { public: - typedef base::Callback<void(bool /* allowed */)> PermissionDecidedCallback; + using PermissionDecidedCallback = base::Callback<void(ContentSetting)>; PermissionQueueController(Profile* profile, ContentSettingsType type); ~PermissionQueueController() override; @@ -35,7 +36,7 @@ void CreateInfoBarRequest(const PermissionRequestID& id, const GURL& requesting_frame, const GURL& embedder, - PermissionDecidedCallback callback); + const PermissionDecidedCallback& callback); // Cancels a specific infobar request. void CancelInfoBarRequest(const PermissionRequestID& id);
diff --git a/chrome/browser/content_settings/permission_queue_controller_unittest.cc b/chrome/browser/content_settings/permission_queue_controller_unittest.cc index d21cd9b..4cc3eac 100644 --- a/chrome/browser/content_settings/permission_queue_controller_unittest.cc +++ b/chrome/browser/content_settings/permission_queue_controller_unittest.cc
@@ -95,21 +95,21 @@ // for notifications, it gets notified exactly once." ObservationCountingQueueController queue_controller(profile()); GURL url("http://www.example.com/geolocation"); - base::Callback<void(bool)> callback; + base::Callback<void(ContentSetting)> callback; queue_controller.CreateInfoBarRequest( RequestID(0), url, url, callback); queue_controller.CreateInfoBarRequest( RequestID(1), url, url, callback); queue_controller.CancelInfoBarRequest(RequestID(0)); EXPECT_EQ(1, queue_controller.call_count()); -}; +} TEST_F(PermissionQueueControllerTests, FailOnBadPattern) { ObservationCountingQueueController queue_controller(profile()); GURL url("chrome://settings"); - base::Callback<void(bool)> callback; + base::Callback<void(ContentSetting)> callback; queue_controller.CreateInfoBarRequest( RequestID(0), url, url, callback); queue_controller.CancelInfoBarRequest(RequestID(0)); EXPECT_EQ(0, queue_controller.call_count()); -}; +}
diff --git a/chrome/browser/copresence/chrome_whispernet_client_browsertest.cc b/chrome/browser/copresence/chrome_whispernet_client_browsertest.cc index 61d3b3c..331153e 100644 --- a/chrome/browser/copresence/chrome_whispernet_client_browsertest.cc +++ b/chrome/browser/copresence/chrome_whispernet_client_browsertest.cc
@@ -33,7 +33,7 @@ namespace { -// TODO(rkc): Add more varied test input. +// TODO(ckehoe): Use randomly generated tokens instead. const char kSixZeros[] = "MDAwMDAw"; const char kEightZeros[] = "MDAwMDAwMDA"; const char kNineZeros[] = "MDAwMDAwMDAw"; @@ -114,7 +114,8 @@ void EncodeTokenAndSaveSamples(WhispernetClient* client, bool audible, - const std::string& token) { + const std::string& token, + const TokenParameters token_params[2]) { run_loop_.reset(new base::RunLoop()); client->RegisterSamplesCallback( base::Bind(&ChromeWhispernetClientTest::SamplesCallback, @@ -122,7 +123,6 @@ expected_token_ = token; expected_audible_ = audible; - TokenParameters token_params[2]; client->EncodeToken(token, audible ? AUDIBLE : INAUDIBLE, token_params); run_loop_->Run(); @@ -231,16 +231,19 @@ DISALLOW_COPY_AND_ASSIGN(ChromeWhispernetClientTest); }; -// These tests are irrelevant if NACL is disabled. See crbug.com/449198 -#if defined(DISABLE_NACL) +// These tests are irrelevant if NACL is disabled. See crbug.com/449198. +// TODO(crbug/464120): There is also a problem in Windows debug mode. +#if defined(DISABLE_NACL) || (!defined(NDEBUG) && defined(OS_WIN)) #define MAYBE_Initialize DISABLED_Initialize #define MAYBE_EncodeAndDecode DISABLED_EncodeAndDecode #define MAYBE_TokenLengths DISABLED_TokenLengths +#define MAYBE_Crc DISABLED_Crc #define MAYBE_MultipleClients DISABLED_MultipleClients #else #define MAYBE_Initialize Initialize #define MAYBE_EncodeAndDecode EncodeAndDecode #define MAYBE_TokenLengths TokenLengths +#define MAYBE_Crc Crc #define MAYBE_MultipleClients MultipleClients #endif @@ -257,10 +260,10 @@ TokenParameters token_params[2]; GetTokenParamsForLengths(kTokenLengths, token_params); - EncodeTokenAndSaveSamples(client.get(), true, kSixZeros); + EncodeTokenAndSaveSamples(client.get(), true, kSixZeros, token_params); DecodeSamplesAndVerifyToken(client.get(), true, kSixZeros, token_params); - EncodeTokenAndSaveSamples(client.get(), false, kSixZeros); + EncodeTokenAndSaveSamples(client.get(), false, kSixZeros, token_params); DecodeSamplesAndVerifyToken(client.get(), false, kSixZeros, token_params); } @@ -274,13 +277,31 @@ TokenParameters token_params[2]; GetTokenParamsForLengths(kLongTokenLengths, token_params); - EncodeTokenAndSaveSamples(client.get(), true, kEightZeros); + EncodeTokenAndSaveSamples(client.get(), true, kEightZeros, token_params); DecodeSamplesAndVerifyToken(client.get(), true, kEightZeros, token_params); - EncodeTokenAndSaveSamples(client.get(), false, kNineZeros); + EncodeTokenAndSaveSamples(client.get(), false, kNineZeros, token_params); DecodeSamplesAndVerifyToken(client.get(), false, kNineZeros, token_params); } +IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_Crc) { + scoped_ptr<WhispernetClient> client( + new ChromeWhispernetClient(browser()->profile())); + client->Initialize(base::Bind(&IgnoreResult)); + SetupDecode(); + + TokenParameters token_params[2]; + GetTokenParamsForLengths(kTokenLengths, token_params); + token_params[0].crc = true; + token_params[1].crc = true; + + EncodeTokenAndSaveSamples(client.get(), true, kSixZeros, token_params); + DecodeSamplesAndVerifyToken(client.get(), true, kSixZeros, token_params); + + EncodeTokenAndSaveSamples(client.get(), false, kSixZeros, token_params); + DecodeSamplesAndVerifyToken(client.get(), false, kSixZeros, token_params); +} + IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_MultipleClients) { scoped_ptr<WhispernetClient> client_1( new ChromeWhispernetClient(browser()->profile())); @@ -297,24 +318,21 @@ client_1->Initialize(base::Bind(&IgnoreResult)); client_2->Initialize(base::Bind(&IgnoreResult)); - EncodeTokenAndSaveSamples(client_1.get(), true, kSixZeros); + EncodeTokenAndSaveSamples(client_1.get(), true, kSixZeros, token_params); DecodeSamplesAndVerifyToken(client_1.get(), true, kSixZeros, token_params); - EncodeTokenAndSaveSamples(client_2.get(), false, kSixZeros); + EncodeTokenAndSaveSamples(client_2.get(), false, kSixZeros, token_params); DecodeSamplesAndVerifyToken(client_2.get(), false, kSixZeros, token_params); // Test sequential initialization. client_3->Initialize(base::Bind(&IgnoreResult)); - EncodeTokenAndSaveSamples(client_3.get(), true, kSixZeros); + EncodeTokenAndSaveSamples(client_3.get(), true, kSixZeros, token_params); DecodeSamplesAndVerifyToken(client_3.get(), true, kSixZeros, token_params); const size_t kLongTokenLengths[2] = {8, 9}; GetTokenParamsForLengths(kLongTokenLengths, token_params); - EncodeTokenAndSaveSamples(client_2.get(), true, kEightZeros); + EncodeTokenAndSaveSamples(client_2.get(), true, kEightZeros, token_params); DecodeSamplesAndVerifyToken(client_2.get(), true, kEightZeros, token_params); } - -// TODO(ckehoe): Test crc and parity -// TODO(ckehoe): More multi-client testing
diff --git a/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc b/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc index 73187c9..2d23952 100644 --- a/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc +++ b/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc
@@ -9,6 +9,8 @@ namespace { +using DispatchCallback = DevToolsEmbedderMessageDispatcher::DispatchCallback; + bool GetValue(const base::Value* value, std::string* result) { return value->GetAsString(result); } @@ -78,13 +80,25 @@ }; template<typename... As> -bool ParseAndHandle(const base::Callback<void(int, As...)>& handler, - int request_id, +bool ParseAndHandle(const base::Callback<void(As...)>& handler, + const DispatchCallback& callback, const base::ListValue& list) { ParamTuple<As...> tuple; if (!tuple.Parse(list, list.begin())) return false; - tuple.Apply(handler, request_id); + tuple.Apply(handler); + return true; +} + +template<typename... As> +bool ParseAndHandleWithCallback( + const base::Callback<void(const DispatchCallback&, As...)>& handler, + const DispatchCallback& callback, + const base::ListValue& list) { + ParamTuple<As...> tuple; + if (!tuple.Parse(list, list.begin())) + return false; + tuple.Apply(handler, callback); return true; } @@ -102,23 +116,36 @@ public: ~DispatcherImpl() override {} - bool Dispatch(int request_id, + bool Dispatch(const DispatchCallback& callback, const std::string& method, const base::ListValue* params) override { HandlerMap::iterator it = handlers_.find(method); - return it != handlers_.end() && it->second.Run(request_id, *params); + return it != handlers_.end() && it->second.Run(callback, *params); } - template<typename T, typename... As> + template<typename... As> void RegisterHandler(const std::string& method, - void (T::*handler)(int, As...), T* delegate) { + void (Delegate::*handler)(As...), + Delegate* delegate) { handlers_[method] = base::Bind(&ParseAndHandle<As...>, base::Bind(handler, base::Unretained(delegate))); } + template<typename... As> + void RegisterHandlerWithCallback( + const std::string& method, + void (Delegate::*handler)(const DispatchCallback&, As...), + Delegate* delegate) { + handlers_[method] = base::Bind(&ParseAndHandleWithCallback<As...>, + base::Bind(handler, + base::Unretained(delegate))); + } + + private: - using Handler = base::Callback<bool(int, const base::ListValue&)>; + using Handler = base::Callback<bool(const DispatchCallback&, + const base::ListValue&)>; using HandlerMap = std::map<std::string, Handler>; HandlerMap handlers_; }; @@ -138,7 +165,8 @@ &Delegate::InspectElementCompleted, delegate); d->RegisterHandler("inspectedURLChanged", &Delegate::InspectedURLChanged, delegate); - d->RegisterHandler("setIsDocked", &Delegate::SetIsDocked, delegate); + d->RegisterHandlerWithCallback("setIsDocked", + &Delegate::SetIsDocked, delegate); d->RegisterHandler("openInNewTab", &Delegate::OpenInNewTab, delegate); d->RegisterHandler("save", &Delegate::SaveToFile, delegate); d->RegisterHandler("append", &Delegate::AppendToFile, delegate); @@ -149,8 +177,8 @@ d->RegisterHandler("upgradeDraggedFileSystemPermissions", &Delegate::UpgradeDraggedFileSystemPermissions, delegate); d->RegisterHandler("indexPath", &Delegate::IndexPath, delegate); - d->RegisterHandler("loadNetworkResource", - &Delegate::LoadNetworkResource, delegate); + d->RegisterHandlerWithCallback("loadNetworkResource", + &Delegate::LoadNetworkResource, delegate); d->RegisterHandler("stopIndexing", &Delegate::StopIndexing, delegate); d->RegisterHandler("searchInPath", &Delegate::SearchInPath, delegate); d->RegisterHandler("setWhitelistedShortcuts",
diff --git a/chrome/browser/devtools/devtools_embedder_message_dispatcher.h b/chrome/browser/devtools/devtools_embedder_message_dispatcher.h index 78c5ad7d..b7ed9b1 100644 --- a/chrome/browser/devtools/devtools_embedder_message_dispatcher.h +++ b/chrome/browser/devtools/devtools_embedder_message_dispatcher.h
@@ -15,6 +15,7 @@ namespace base { class ListValue; +class Value; } /** @@ -27,63 +28,55 @@ public: class Delegate { public: + using DispatchCallback = base::Callback<void(const base::Value*)>; + virtual ~Delegate() {} - virtual void ActivateWindow(int request_id) = 0; - virtual void CloseWindow(int request_id) = 0; - virtual void LoadCompleted(int request_id) = 0; - virtual void SetInspectedPageBounds(int request_id, - const gfx::Rect& rect) = 0; - virtual void InspectElementCompleted(int request_id) = 0; - virtual void InspectedURLChanged(int request_id, - const std::string& url) = 0; - virtual void SetIsDocked(int request_id, bool is_docked) = 0; - virtual void OpenInNewTab(int request_id, const std::string& url) = 0; - virtual void SaveToFile(int request_id, - const std::string& url, + virtual void ActivateWindow() = 0; + virtual void CloseWindow() = 0; + virtual void LoadCompleted() = 0; + virtual void SetInspectedPageBounds(const gfx::Rect& rect) = 0; + virtual void InspectElementCompleted() = 0; + virtual void InspectedURLChanged(const std::string& url) = 0; + virtual void SetIsDocked(const DispatchCallback& callback, + bool is_docked) = 0; + virtual void OpenInNewTab(const std::string& url) = 0; + virtual void SaveToFile(const std::string& url, const std::string& content, bool save_as) = 0; - virtual void AppendToFile(int request_id, - const std::string& url, + virtual void AppendToFile(const std::string& url, const std::string& content) = 0; - virtual void RequestFileSystems(int request_id) = 0; - virtual void AddFileSystem(int request_id) = 0; - virtual void RemoveFileSystem(int request_id, - const std::string& file_system_path) = 0; + virtual void RequestFileSystems() = 0; + virtual void AddFileSystem() = 0; + virtual void RemoveFileSystem(const std::string& file_system_path) = 0; virtual void UpgradeDraggedFileSystemPermissions( - int request_id, const std::string& file_system_url) = 0; - virtual void IndexPath(int request_id, - int index_request_id, + virtual void IndexPath(int index_request_id, const std::string& file_system_path) = 0; - virtual void StopIndexing(int request_id, int index_request_id) = 0; - virtual void LoadNetworkResource(int request_id, + virtual void StopIndexing(int index_request_id) = 0; + virtual void LoadNetworkResource(const DispatchCallback& callback, const std::string& url, const std::string& headers, int stream_id) = 0; - virtual void SearchInPath(int request_id, - int search_request_id, + virtual void SearchInPath(int search_request_id, const std::string& file_system_path, const std::string& query) = 0; - virtual void SetWhitelistedShortcuts(int request_id, - const std::string& message) = 0; - virtual void ZoomIn(int request_id) = 0; - virtual void ZoomOut(int request_id) = 0; - virtual void ResetZoom(int request_id) = 0; - virtual void OpenUrlOnRemoteDeviceAndInspect(int request_id, - const std::string& browser_id, + virtual void SetWhitelistedShortcuts(const std::string& message) = 0; + virtual void ZoomIn() = 0; + virtual void ZoomOut() = 0; + virtual void ResetZoom() = 0; + virtual void OpenUrlOnRemoteDeviceAndInspect(const std::string& browser_id, const std::string& url) = 0; - virtual void SetDeviceCountUpdatesEnabled(int request_id, bool enabled) = 0; - virtual void SetDevicesUpdatesEnabled(int request_id, bool enabled) = 0; - virtual void SendMessageToBrowser(int request_id, - const std::string& message) = 0; - virtual void RecordActionUMA(int request_id, - const std::string& name, - int action) = 0; + virtual void SetDeviceCountUpdatesEnabled(bool enabled) = 0; + virtual void SetDevicesUpdatesEnabled(bool enabled) = 0; + virtual void SendMessageToBrowser(const std::string& message) = 0; + virtual void RecordActionUMA(const std::string& name, int action) = 0; }; + using DispatchCallback = Delegate::DispatchCallback; + virtual ~DevToolsEmbedderMessageDispatcher() {} - virtual bool Dispatch(int request_id, + virtual bool Dispatch(const DispatchCallback& callback, const std::string& method, const base::ListValue* params) = 0;
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc index 1ace00df..51607ad2 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.cc +++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -452,8 +452,8 @@ jobs_it->second->Stop(); } indexing_jobs_.clear(); - SetDeviceCountUpdatesEnabled(0, false); - SetDevicesUpdatesEnabled(0, false); + SetDeviceCountUpdatesEnabled(false); + SetDevicesUpdatesEnabled(false); // Remove self from global list. DevToolsUIBindingsList* instances = g_instances.Pointer(); @@ -490,7 +490,12 @@ } int id = 0; dict->GetInteger(kFrontendHostId, &id); - embedder_message_dispatcher_->Dispatch(id, method, params); + embedder_message_dispatcher_->Dispatch( + base::Bind(&DevToolsUIBindings::SendMessageAck, + weak_factory_.GetWeakPtr(), + id), + method, + params); } void DevToolsUIBindings::HandleMessageFromDevToolsFrontendToBackend( @@ -535,34 +540,33 @@ } // DevToolsEmbedderMessageDispatcher::Delegate implementation ----------------- -void DevToolsUIBindings::ActivateWindow(int request_id) { +void DevToolsUIBindings::ActivateWindow() { delegate_->ActivateWindow(); } -void DevToolsUIBindings::CloseWindow(int request_id) { +void DevToolsUIBindings::CloseWindow() { delegate_->CloseWindow(); } -void DevToolsUIBindings::LoadCompleted(int request_id) { +void DevToolsUIBindings::LoadCompleted() { FrontendLoaded(); } -void DevToolsUIBindings::SetInspectedPageBounds(int request_id, - const gfx::Rect& rect) { +void DevToolsUIBindings::SetInspectedPageBounds(const gfx::Rect& rect) { delegate_->SetInspectedPageBounds(rect); } -void DevToolsUIBindings::SetIsDocked(int request_id, bool dock_requested) { +void DevToolsUIBindings::SetIsDocked(const DispatchCallback& callback, + bool dock_requested) { delegate_->SetIsDocked(dock_requested); - SendMessageAck(request_id, nullptr); + callback.Run(nullptr); } -void DevToolsUIBindings::InspectElementCompleted(int request_id) { +void DevToolsUIBindings::InspectElementCompleted() { delegate_->InspectElementCompleted(); } -void DevToolsUIBindings::InspectedURLChanged(int request_id, - const std::string& url) { +void DevToolsUIBindings::InspectedURLChanged(const std::string& url) { content::NavigationController& controller = web_contents()->GetController(); content::NavigationEntry* entry = controller.GetActiveEntry(); // DevTools UI is not localized. @@ -571,7 +575,7 @@ web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE); } -void DevToolsUIBindings::LoadNetworkResource(int request_id, +void DevToolsUIBindings::LoadNetworkResource(const DispatchCallback& callback, const std::string& url, const std::string& headers, int stream_id) { @@ -579,13 +583,13 @@ if (!gurl.is_valid()) { base::DictionaryValue response; response.SetInteger("statusCode", 404); - SendMessageAck(request_id, &response); + callback.Run(&response); return; } net::URLFetcher* fetcher = net::URLFetcher::Create(gurl, net::URLFetcher::GET, this); - pending_requests_[fetcher] = request_id; + pending_requests_[fetcher] = callback; fetcher->SetRequestContext(profile_->GetRequestContext()); fetcher->SetExtraRequestHeaders(headers); fetcher->SaveResponseWithWriter(scoped_ptr<net::URLFetcherResponseWriter>( @@ -593,12 +597,11 @@ fetcher->Start(); } -void DevToolsUIBindings::OpenInNewTab(int request_id, const std::string& url) { +void DevToolsUIBindings::OpenInNewTab(const std::string& url) { delegate_->OpenInNewTab(url); } -void DevToolsUIBindings::SaveToFile(int request_id, - const std::string& url, +void DevToolsUIBindings::SaveToFile(const std::string& url, const std::string& content, bool save_as) { file_helper_->Save(url, content, save_as, @@ -608,21 +611,20 @@ weak_factory_.GetWeakPtr(), url)); } -void DevToolsUIBindings::AppendToFile(int request_id, - const std::string& url, +void DevToolsUIBindings::AppendToFile(const std::string& url, const std::string& content) { file_helper_->Append(url, content, base::Bind(&DevToolsUIBindings::AppendedTo, weak_factory_.GetWeakPtr(), url)); } -void DevToolsUIBindings::RequestFileSystems(int request_id) { +void DevToolsUIBindings::RequestFileSystems() { CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme)); file_helper_->RequestFileSystems(base::Bind( &DevToolsUIBindings::FileSystemsLoaded, weak_factory_.GetWeakPtr())); } -void DevToolsUIBindings::AddFileSystem(int request_id) { +void DevToolsUIBindings::AddFileSystem() { CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme)); file_helper_->AddFileSystem( base::Bind(&DevToolsUIBindings::FileSystemAdded, @@ -631,8 +633,7 @@ weak_factory_.GetWeakPtr())); } -void DevToolsUIBindings::RemoveFileSystem(int request_id, - const std::string& file_system_path) { +void DevToolsUIBindings::RemoveFileSystem(const std::string& file_system_path) { CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme)); file_helper_->RemoveFileSystem(file_system_path); base::StringValue file_system_path_value(file_system_path); @@ -641,7 +642,6 @@ } void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions( - int request_id, const std::string& file_system_url) { CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme)); file_helper_->UpgradeDraggedFileSystemPermissions( @@ -652,8 +652,7 @@ weak_factory_.GetWeakPtr())); } -void DevToolsUIBindings::IndexPath(int request_id, - int index_request_id, +void DevToolsUIBindings::IndexPath(int index_request_id, const std::string& file_system_path) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme)); @@ -681,7 +680,7 @@ file_system_path))); } -void DevToolsUIBindings::StopIndexing(int request_id, int index_request_id) { +void DevToolsUIBindings::StopIndexing(int index_request_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); IndexingJobsMap::iterator it = indexing_jobs_.find(index_request_id); if (it == indexing_jobs_.end()) @@ -690,8 +689,7 @@ indexing_jobs_.erase(it); } -void DevToolsUIBindings::SearchInPath(int request_id, - int search_request_id, +void DevToolsUIBindings::SearchInPath(int search_request_id, const std::string& file_system_path, const std::string& query) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -710,20 +708,19 @@ file_system_path)); } -void DevToolsUIBindings::SetWhitelistedShortcuts(int request_id, - const std::string& message) { +void DevToolsUIBindings::SetWhitelistedShortcuts(const std::string& message) { delegate_->SetWhitelistedShortcuts(message); } -void DevToolsUIBindings::ZoomIn(int request_id) { +void DevToolsUIBindings::ZoomIn() { ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_IN); } -void DevToolsUIBindings::ZoomOut(int request_id) { +void DevToolsUIBindings::ZoomOut() { ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT); } -void DevToolsUIBindings::ResetZoom(int request_id) { +void DevToolsUIBindings::ResetZoom() { ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_RESET); } @@ -733,7 +730,6 @@ } void DevToolsUIBindings::OpenUrlOnRemoteDeviceAndInspect( - int request_id, const std::string& browser_id, const std::string& url) { if (remote_targets_handler_) { @@ -742,8 +738,7 @@ } } -void DevToolsUIBindings::SetDeviceCountUpdatesEnabled(int request_id, - bool enabled) { +void DevToolsUIBindings::SetDeviceCountUpdatesEnabled(bool enabled) { if (device_count_updates_enabled_ == enabled) return; DevToolsAndroidBridge* adb_bridge = @@ -758,8 +753,7 @@ adb_bridge->RemoveDeviceCountListener(this); } -void DevToolsUIBindings::SetDevicesUpdatesEnabled(int request_id, - bool enabled) { +void DevToolsUIBindings::SetDevicesUpdatesEnabled(bool enabled) { if (devices_updates_enabled_ == enabled) return; devices_updates_enabled_ = enabled; @@ -773,15 +767,12 @@ } } -void DevToolsUIBindings::SendMessageToBrowser(int request_id, - const std::string& message) { +void DevToolsUIBindings::SendMessageToBrowser(const std::string& message) { if (agent_host_.get()) agent_host_->DispatchProtocolMessage(message); } -void DevToolsUIBindings::RecordActionUMA(int request_id, - const std::string& name, - int action) { +void DevToolsUIBindings::RecordActionUMA(const std::string& name, int action) { if (name == kDevToolsActionTakenHistogram) UMA_HISTOGRAM_ENUMERATION(name, action, kDevToolsActionTakenBoundary); else if (name == kDevToolsPanelShownHistogram) @@ -805,7 +796,7 @@ while (rh && rh->EnumerateHeaderLines(&iterator, &name, &value)) headers->SetString(name, value); - SendMessageAck(it->second, &response); + it->second.Run(&response); pending_requests_.erase(it); delete source; }
diff --git a/chrome/browser/devtools/devtools_ui_bindings.h b/chrome/browser/devtools/devtools_ui_bindings.h index 58aabce..268f3a5 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.h +++ b/chrome/browser/devtools/devtools_ui_bindings.h
@@ -97,56 +97,44 @@ bool replaced_with_another_client) override; // DevToolsEmbedderMessageDispatcher::Delegate implementation. - void ActivateWindow(int request_id) override; - void CloseWindow(int request_id) override; - void LoadCompleted(int request_id) override; - void SetInspectedPageBounds(int request_id, - const gfx::Rect& rect) override; - void InspectElementCompleted(int request_id) override; - void InspectedURLChanged(int request_id, const std::string& url) override; - void LoadNetworkResource(int request_id, + void ActivateWindow() override; + void CloseWindow() override; + void LoadCompleted() override; + void SetInspectedPageBounds(const gfx::Rect& rect) override; + void InspectElementCompleted() override; + void InspectedURLChanged(const std::string& url) override; + void LoadNetworkResource(const DispatchCallback& callback, const std::string& url, const std::string& headers, int stream_id) override; - void SetIsDocked(int request_id, bool is_docked) override; - void OpenInNewTab(int request_id, const std::string& url) override; - void SaveToFile(int request_id, - const std::string& url, + void SetIsDocked(const DispatchCallback& callback, bool is_docked) override; + void OpenInNewTab(const std::string& url) override; + void SaveToFile(const std::string& url, const std::string& content, bool save_as) override; - void AppendToFile(int request_id, - const std::string& url, + void AppendToFile(const std::string& url, const std::string& content) override; - void RequestFileSystems(int request_id) override; - void AddFileSystem(int request_id) override; - void RemoveFileSystem(int request_id, - const std::string& file_system_path) override; + void RequestFileSystems() override; + void AddFileSystem() override; + void RemoveFileSystem(const std::string& file_system_path) override; void UpgradeDraggedFileSystemPermissions( - int request_id, const std::string& file_system_url) override; - void IndexPath(int request_id, - int index_request_id, + void IndexPath(int index_request_id, const std::string& file_system_path) override; - void StopIndexing(int request_id, int index_request_id) override; - void SearchInPath(int request_id, - int search_request_id, + void StopIndexing(int index_request_id) override; + void SearchInPath(int search_request_id, const std::string& file_system_path, const std::string& query) override; - void SetWhitelistedShortcuts(int request_id, - const std::string& message) override; - void ZoomIn(int request_id) override; - void ZoomOut(int request_id) override; - void ResetZoom(int request_id) override; - void OpenUrlOnRemoteDeviceAndInspect(int request_id, - const std::string& browser_id, + void SetWhitelistedShortcuts(const std::string& message) override; + void ZoomIn() override; + void ZoomOut() override; + void ResetZoom() override; + void OpenUrlOnRemoteDeviceAndInspect(const std::string& browser_id, const std::string& url) override; - void SetDeviceCountUpdatesEnabled(int request_id, bool enabled) override; - void SetDevicesUpdatesEnabled(int request_id, bool enabled) override; - void SendMessageToBrowser(int request_id, - const std::string& message) override; - void RecordActionUMA(int request_id, - const std::string& name, - int action) override; + void SetDeviceCountUpdatesEnabled(bool enabled) override; + void SetDevicesUpdatesEnabled(bool enabled) override; + void SendMessageToBrowser(const std::string& message) override; + void RecordActionUMA(const std::string& name, int action) override; // net::URLFetcherDelegate overrides. void OnURLFetchComplete(const net::URLFetcher* source) override; @@ -216,7 +204,7 @@ scoped_ptr<DevToolsTargetsUIHandler> remote_targets_handler_; scoped_ptr<DevToolsEmbedderMessageDispatcher> embedder_message_dispatcher_; GURL url_; - using PendingRequestsMap = std::map<const net::URLFetcher*, int>; + using PendingRequestsMap = std::map<const net::URLFetcher*, DispatchCallback>; PendingRequestsMap pending_requests_; base::WeakPtrFactory<DevToolsUIBindings> weak_factory_;
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc index b7f0f9d..a517f18b 100644 --- a/chrome/browser/devtools/devtools_window.cc +++ b/chrome/browser/devtools/devtools_window.cc
@@ -857,6 +857,8 @@ if (target_url.SchemeIs(content::kChromeDevToolsScheme) && target_url.path().rfind("toolbox.html") != std::string::npos) { CHECK(can_dock_); + if (toolbox_web_contents_) + delete toolbox_web_contents_; toolbox_web_contents_ = new_contents; } }
diff --git a/chrome/browser/devtools/devtools_window.h b/chrome/browser/devtools/devtools_window.h index 63922fc9..d0a4d3b0 100644 --- a/chrome/browser/devtools/devtools_window.h +++ b/chrome/browser/devtools/devtools_window.h
@@ -61,6 +61,7 @@ DevToolsContentsResizingStrategy* out_strategy); static bool IsDevToolsWindow(content::WebContents* web_contents); + static DevToolsWindow* AsDevToolsWindow(content::WebContents* web_contents); // Open or reveal DevTools window, and perform the specified action. static DevToolsWindow* OpenDevToolsWindow( @@ -100,6 +101,11 @@ // Forwards an unhandled keyboard event to the DevTools frontend. bool ForwardKeyboardEvent(const content::NativeWebKeyboardEvent& event); + // content::WebContentsDelegate overrides. + content::WebContents* OpenURLFromTab( + content::WebContents* source, + const content::OpenURLParams& params) override; + // BeforeUnload interception //////////////////////////////////////////////// // In order to preserve any edits the user may have made in devtools, the @@ -218,7 +224,6 @@ bool can_dock, const std::string& settings); static DevToolsWindow* FindDevToolsWindow(content::DevToolsAgentHost*); - static DevToolsWindow* AsDevToolsWindow(content::WebContents*); static DevToolsWindow* CreateDevToolsWindowForWorker(Profile* profile); static DevToolsWindow* ToggleDevToolsWindow( content::WebContents* web_contents, @@ -227,9 +232,6 @@ const std::string& settings); // content::WebContentsDelegate: - content::WebContents* OpenURLFromTab( - content::WebContents* source, - const content::OpenURLParams& params) override; void ActivateContents(content::WebContents* contents) override; void AddNewContents(content::WebContents* source, content::WebContents* new_contents,
diff --git a/chrome/browser/diagnostics/recon_diagnostics.cc b/chrome/browser/diagnostics/recon_diagnostics.cc index 7b09d86..a0575db5 100644 --- a/chrome/browser/diagnostics/recon_diagnostics.cc +++ b/chrome/browser/diagnostics/recon_diagnostics.cc
@@ -210,7 +210,7 @@ return true; } - JSONStringValueSerializer json(json_data); + JSONStringValueDeserializer json(json_data); int error_code = base::JSONReader::JSON_NO_ERROR; std::string error_message; scoped_ptr<base::Value> json_root(
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc index 2a99948..52a151b 100644 --- a/chrome/browser/download/chrome_download_manager_delegate.cc +++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -49,6 +49,11 @@ #include "net/base/filename_util.h" #include "net/base/mime_util.h" +#if defined(OS_ANDROID) +#include "chrome/browser/android/download/chrome_download_manager_overwrite_infobar_delegate.h" +#include "chrome/browser/infobars/infobar_service.h" +#endif + #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/drive/download_handler.h" #include "chrome/browser/chromeos/drive/file_system_util.h" @@ -573,7 +578,13 @@ const base::FilePath& suggested_path, const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +#if defined(OS_ANDROID) + chrome::android::ChromeDownloadManagerOverwriteInfoBarDelegate::Create( + InfoBarService::FromWebContents(download->GetWebContents()), + suggested_path, callback); +#else DownloadFilePicker::ShowFilePicker(download, suggested_path, callback); +#endif } void ChromeDownloadManagerDelegate::DetermineLocalPath(
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc index a809400..ca8338a 100644 --- a/chrome/browser/download/download_browsertest.cc +++ b/chrome/browser/download/download_browsertest.cc
@@ -56,7 +56,10 @@ #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/website_settings/mock_permission_bubble_view.h" +#include "chrome/browser/ui/website_settings/permission_bubble_manager.h" #include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/common/safe_browsing/csd.pb.h" #include "chrome/common/url_constants.h" @@ -1090,6 +1093,12 @@ return download; } + void WaitForBubble(MockPermissionBubbleView* mock_bubble) { + if (mock_bubble->IsVisible()) + return; + content::RunMessageLoop(); + } + private: static void EnsureNoPendingDownloadJobsOnIO(bool* result) { if (net::URLRequestSlowDownloadJob::NumberOutstandingRequests()) @@ -2892,6 +2901,10 @@ ASSERT_TRUE(test_server()->Start()); + // Ensure that infobars are being used instead of bubbles. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kDisablePermissionsBubbles); + // Create a downloads observer. scoped_ptr<content::DownloadTestObserver> downloads_observer( CreateWaiter(browser(), 2)); @@ -2932,6 +2945,53 @@ DownloadItem::COMPLETE)); } +IN_PROC_BROWSER_TEST_F(DownloadTest, TestMultipleDownloadsBubble) { +#if defined(OS_WIN) && defined(USE_ASH) + // Disable this test in Metro+Ash for now (http://crbug.com/262796). + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAshBrowserTests)) + return; +#endif + +#if defined(OS_ANDROID) || defined(OS_IOS) + // Permission bubbles are not supported on mobile. + return; +#endif + + ASSERT_TRUE(test_server()->Start()); + + // Enable permision bubbles. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnablePermissionsBubbles); + + // Create a downloads observer. + scoped_ptr<content::DownloadTestObserver> downloads_observer( + CreateWaiter(browser(), 2)); + + MockPermissionBubbleView* mock_bubble_view = new MockPermissionBubbleView(); + PermissionBubbleManager::FromWebContents( + browser()->tab_strip_model()->GetActiveWebContents())-> + SetView(mock_bubble_view); + mock_bubble_view->SetBrowserTest(true); + ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( + browser(), + test_server()->GetURL("files/downloads/download-a_zip_file.html"), 1); + + WaitForBubble(mock_bubble_view); + + ASSERT_TRUE(mock_bubble_view->IsVisible()); + mock_bubble_view->Accept(); + ASSERT_FALSE(mock_bubble_view->IsVisible()); + + // Waits for the download to complete. + downloads_observer->WaitForFinished(); + EXPECT_EQ(2u, downloads_observer->NumDownloadsSeenInState( + DownloadItem::COMPLETE)); + + browser()->tab_strip_model()->GetActiveWebContents()->Close(); + delete mock_bubble_view; +} + IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadTest_Renaming) { ASSERT_TRUE(test_server()->Start()); GURL url(test_server()->GetURL("files/downloads/a_zip_file.zip"));
diff --git a/chrome/browser/download/download_commands.cc b/chrome/browser/download/download_commands.cc new file mode 100644 index 0000000..934290c3 --- /dev/null +++ b/chrome/browser/download/download_commands.cc
@@ -0,0 +1,241 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/download/download_commands.h" + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/download/download_crx_util.h" +#include "chrome/browser/download/download_item_model.h" +#include "chrome/browser/download/download_prefs.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/safe_browsing/download_protection_service.h" +#include "chrome/browser/safe_browsing/safe_browsing_service.h" +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" +#include "chrome/common/url_constants.h" +#include "chrome/grit/generated_resources.h" +#include "grit/theme_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" + +#if defined(OS_WIN) +#include "chrome/browser/download/download_target_determiner.h" +#include "chrome/browser/ui/pdf/adobe_reader_info_win.h" +#endif + +DownloadCommands::DownloadCommands(content::DownloadItem* download_item) + : download_item_(download_item) { + DCHECK(download_item); +} + +int DownloadCommands::GetCommandIconId(Command command) { + switch (command) { + case PAUSE: + return IDR_DOWNLOAD_NOTIFICATION_MENU_PAUSE; + case RESUME: + return IDR_DOWNLOAD_NOTIFICATION_MENU_RESUME; + case SHOW_IN_FOLDER: + return IDR_DOWNLOAD_NOTIFICATION_MENU_FOLDER; + case RETRY: + case KEEP: + return IDR_DOWNLOAD_NOTIFICATION_MENU_DOWNLOAD; + case DISCARD: + return IDR_DOWNLOAD_NOTIFICATION_MENU_DELETE; + case OPEN_WHEN_COMPLETE: + case ALWAYS_OPEN_TYPE: + case PLATFORM_OPEN: + case CANCEL: + case LEARN_MORE_SCANNING: + case LEARN_MORE_INTERRUPTED: + return -1; + } + NOTREACHED(); + return -1; +} + +gfx::Image DownloadCommands::GetCommandIcon(Command command) { + ResourceBundle& bundle = ResourceBundle::GetSharedInstance(); + return bundle.GetImageNamed(GetCommandIconId(command)); +} + +bool DownloadCommands::IsCommandEnabled(Command command) const { + switch (command) { + case SHOW_IN_FOLDER: + return download_item_->CanShowInFolder(); + case OPEN_WHEN_COMPLETE: + case PLATFORM_OPEN: + return download_item_->CanOpenDownload() && + !download_crx_util::IsExtensionDownload(*download_item_); + case ALWAYS_OPEN_TYPE: + // For temporary downloads, the target filename might be a temporary + // filename. Don't base an "Always open" decision based on it. Also + // exclude extensions. + return download_item_->CanOpenDownload() && + !download_crx_util::IsExtensionDownload(*download_item_); + case CANCEL: + return !download_item_->IsDone(); + case PAUSE: + return !download_item_->IsDone() && !download_item_->IsPaused() && + download_item_->GetState() == content::DownloadItem::IN_PROGRESS; + case RESUME: + return !download_item_->CanResume() && + (download_item_->IsPaused() || + download_item_->GetState() != content::DownloadItem::IN_PROGRESS); + case DISCARD: + case KEEP: + case LEARN_MORE_SCANNING: + case LEARN_MORE_INTERRUPTED: + case RETRY: + return true; + } + NOTREACHED(); + return false; +} + +bool DownloadCommands::IsCommandChecked(Command command) const { + switch (command) { + case OPEN_WHEN_COMPLETE: + return download_item_->GetOpenWhenComplete() || + download_crx_util::IsExtensionDownload(*download_item_); + case ALWAYS_OPEN_TYPE: +#if defined(OS_WIN) || defined(OS_LINUX) || \ + (defined(OS_MACOSX) && !defined(OS_IOS)) + if (CanOpenPdfInSystemViewer()) { + DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext( + download_item_->GetBrowserContext()); + return prefs->ShouldOpenPdfInSystemReader(); + } +#endif + return download_item_->ShouldOpenFileBasedOnExtension(); + case PAUSE: + case RESUME: + return download_item_->IsPaused(); + case SHOW_IN_FOLDER: + case PLATFORM_OPEN: + case CANCEL: + case DISCARD: + case KEEP: + case RETRY: + case LEARN_MORE_SCANNING: + case LEARN_MORE_INTERRUPTED: + return false; + } + return false; +} + +bool DownloadCommands::IsCommandVisible(Command command) const { + if (command == PLATFORM_OPEN) + return (DownloadItemModel(download_item_).ShouldPreferOpeningInBrowser()); + + return true; +} + +void DownloadCommands::ExecuteCommand(Command command) { + switch (command) { + case SHOW_IN_FOLDER: + download_item_->ShowDownloadInShell(); + break; + case OPEN_WHEN_COMPLETE: + download_item_->OpenDownload(); + break; + case ALWAYS_OPEN_TYPE: { + bool is_checked = IsCommandChecked(ALWAYS_OPEN_TYPE); + DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext( + download_item_->GetBrowserContext()); +#if defined(OS_WIN) || defined(OS_LINUX) || \ + (defined(OS_MACOSX) && !defined(OS_IOS)) + if (CanOpenPdfInSystemViewer()) { + prefs->SetShouldOpenPdfInSystemReader(!is_checked); + DownloadItemModel(download_item_) + .SetShouldPreferOpeningInBrowser(is_checked); + break; + } +#endif + base::FilePath path = download_item_->GetTargetFilePath(); + if (is_checked) + prefs->DisableAutoOpenBasedOnExtension(path); + else + prefs->EnableAutoOpenBasedOnExtension(path); + break; + } + case PLATFORM_OPEN: + DownloadItemModel(download_item_).OpenUsingPlatformHandler(); + break; + case CANCEL: + download_item_->Cancel(true /* Cancelled by user */); + break; + case DISCARD: + download_item_->Remove(); + break; + case KEEP: + download_item_->ValidateDangerousDownload(); + break; + case LEARN_MORE_SCANNING: { +#if defined(FULL_SAFE_BROWSING) + using safe_browsing::DownloadProtectionService; + + SafeBrowsingService* sb_service = + g_browser_process->safe_browsing_service(); + DownloadProtectionService* protection_service = + (sb_service ? sb_service->download_protection_service() : nullptr); + if (protection_service) + protection_service->ShowDetailsForDownload(*download_item_, + GetBrowser()); +#else + // Should only be getting invoked if we are using safe browsing. + NOTREACHED(); +#endif + break; + } + case LEARN_MORE_INTERRUPTED: + GetBrowser()->OpenURL(content::OpenURLParams( + GURL(chrome::kDownloadInterruptedLearnMoreURL), content::Referrer(), + NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK, false)); + break; + case PAUSE: + download_item_->Pause(); + break; + case RESUME: + download_item_->Resume(); + break; + case RETRY: + if (download_item_->CanResume()) { + download_item_->Resume(); + } else { + // TODO(yoshiki): Implement retry logic. + } + break; + } +} + +Browser* DownloadCommands::GetBrowser() const { + Profile* profile = + Profile::FromBrowserContext(download_item_->GetBrowserContext()); + chrome::ScopedTabbedBrowserDisplayer browser_displayer( + profile, chrome::GetActiveDesktop()); + DCHECK(browser_displayer.browser()); + return browser_displayer.browser(); +} + +#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) +bool DownloadCommands::IsDownloadPdf() const { + base::FilePath path = download_item_->GetTargetFilePath(); + return path.MatchesExtension(FILE_PATH_LITERAL(".pdf")); +} +#endif + +bool DownloadCommands::CanOpenPdfInSystemViewer() const { +#if defined(OS_WIN) + bool is_adobe_pdf_reader_up_to_date = false; + if (IsDownloadPdf() && IsAdobeReaderDefaultPDFViewer()) { + is_adobe_pdf_reader_up_to_date = + DownloadTargetDeterminer::IsAdobeReaderUpToDate(); + } + return IsDownloadPdf() && + (IsAdobeReaderDefaultPDFViewer() ? is_adobe_pdf_reader_up_to_date + : true); +#elif defined(OS_MACOSX) || defined(OS_LINUX) + return IsDownloadPdf(); +#endif +}
diff --git a/chrome/browser/download/download_commands.h b/chrome/browser/download/download_commands.h new file mode 100644 index 0000000..d6849b4 --- /dev/null +++ b/chrome/browser/download/download_commands.h
@@ -0,0 +1,59 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_COMMANDS_H_ +#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_COMMANDS_H_ + +#include "base/strings/string16.h" + +#include "chrome/browser/ui/browser.h" +#include "content/public/browser/download_item.h" +#include "content/public/browser/page_navigator.h" +#include "ui/gfx/image/image.h" + +class DownloadCommands { + public: + enum Command { + SHOW_IN_FOLDER = 1, // Open a folder view window with the item selected. + OPEN_WHEN_COMPLETE, // Open the download when it's finished. + ALWAYS_OPEN_TYPE, // Default this file extension to always open. + PLATFORM_OPEN, // Open using platform handler. + CANCEL, // Cancel the download. + PAUSE, // Pause a download. + RESUME, // Resume a download. + DISCARD, // Discard the malicious download. + KEEP, // Keep the malicious download. + RETRY, // Retry the download. + LEARN_MORE_SCANNING, // Show information about download scanning. + LEARN_MORE_INTERRUPTED, // Show information about interrupted downloads. + }; + + // |download_item| must outlive DownloadCommands. + explicit DownloadCommands(content::DownloadItem* download_item); + virtual ~DownloadCommands() {} + + gfx::Image GetCommandIcon(Command command); + + bool IsCommandEnabled(Command command) const; + bool IsCommandChecked(Command command) const; + bool IsCommandVisible(Command command) const; + void ExecuteCommand(Command command); + +#if defined(OS_WIN) || defined(OS_LINUX) || \ + (defined(OS_MACOSX) && !defined(OS_IOS)) + bool IsDownloadPdf() const; + bool CanOpenPdfInSystemViewer() const; +#endif + + private: + Browser* GetBrowser() const; + + int GetCommandIconId(Command command); + + int GetAlwaysOpenStringId() const; + + content::DownloadItem* const download_item_; +}; + +#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_COMMANDS_H_
diff --git a/chrome/browser/download/download_shelf_context_menu.cc b/chrome/browser/download/download_shelf_context_menu.cc index 0c87b3d..275050d 100644 --- a/chrome/browser/download/download_shelf_context_menu.cc +++ b/chrome/browser/download/download_shelf_context_menu.cc
@@ -5,18 +5,8 @@ #include "chrome/browser/download/download_shelf_context_menu.h" #include "base/command_line.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/download/download_crx_util.h" #include "chrome/browser/download/download_item_model.h" -#include "chrome/browser/download/download_prefs.h" -#include "chrome/browser/download/download_target_determiner.h" -#include "chrome/browser/safe_browsing/download_protection_service.h" -#include "chrome/browser/safe_browsing/safe_browsing_service.h" -#include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" -#include "content/public/browser/download_item.h" -#include "content/public/browser/download_manager.h" -#include "content/public/browser/page_navigator.h" #include "content/public/common/content_switches.h" #include "extensions/common/extension.h" #include "ui/base/l10n/l10n_util.h" @@ -41,21 +31,11 @@ DetachFromDownloadItem(); } -DownloadShelfContextMenu::DownloadShelfContextMenu( - DownloadItem* download_item, - content::PageNavigator* navigator) +DownloadShelfContextMenu::DownloadShelfContextMenu(DownloadItem* download_item) : download_item_(download_item), - navigator_(navigator) { + download_commands_(new DownloadCommands(download_item)) { DCHECK(download_item_); download_item_->AddObserver(this); - -#if defined(OS_WIN) - is_adobe_pdf_reader_up_to_date_ = false; - if (IsDownloadPdf() && IsAdobeReaderDefaultPDFViewer()) { - is_adobe_pdf_reader_up_to_date_ = - DownloadTargetDeterminer::IsAdobeReaderUpToDate(); - } -#endif // defined(OS_WIN) } ui::SimpleMenuModel* DownloadShelfContextMenu::GetMenuModel() { @@ -77,202 +57,127 @@ model = GetFinishedMenuModel(); else if (download_item_->GetState() == DownloadItem::INTERRUPTED) model = GetInterruptedMenuModel(); + else if (download_item_->IsPaused()) + model = GetInProgressPausedMenuModel(); else model = GetInProgressMenuModel(); return model; } bool DownloadShelfContextMenu::IsCommandIdEnabled(int command_id) const { - if (!download_item_) + if (!download_commands_) return false; - switch (static_cast<ContextMenuCommands>(command_id)) { - case SHOW_IN_FOLDER: - return download_item_->CanShowInFolder(); - case OPEN_WHEN_COMPLETE: - case PLATFORM_OPEN: - return download_item_->CanOpenDownload() && - !download_crx_util::IsExtensionDownload(*download_item_); - case ALWAYS_OPEN_TYPE: - // For temporary downloads, the target filename might be a temporary - // filename. Don't base an "Always open" decision based on it. Also - // exclude extensions. - return download_item_->CanOpenDownload() && - !download_crx_util::IsExtensionDownload(*download_item_); - case CANCEL: - return !download_item_->IsDone(); - case TOGGLE_PAUSE: - return !download_item_->IsDone(); - case DISCARD: - case KEEP: - case LEARN_MORE_SCANNING: - case LEARN_MORE_INTERRUPTED: - return true; - } - NOTREACHED(); - return false; + return download_commands_->IsCommandEnabled( + static_cast<DownloadCommands::Command>(command_id)); } bool DownloadShelfContextMenu::IsCommandIdChecked(int command_id) const { - if (!download_item_) + if (!download_commands_) return false; - switch (command_id) { - case OPEN_WHEN_COMPLETE: - return download_item_->GetOpenWhenComplete() || - download_crx_util::IsExtensionDownload(*download_item_); - case ALWAYS_OPEN_TYPE: -#if defined(OS_WIN) || defined(OS_LINUX) || \ - (defined(OS_MACOSX) && !defined(OS_IOS)) - if (CanOpenPdfInSystemViewer()) { - DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext( - download_item_->GetBrowserContext()); - return prefs->ShouldOpenPdfInSystemReader(); - } -#endif - return download_item_->ShouldOpenFileBasedOnExtension(); - case TOGGLE_PAUSE: - return download_item_->IsPaused(); - } - return false; + return download_commands_->IsCommandChecked( + static_cast<DownloadCommands::Command>(command_id)); } bool DownloadShelfContextMenu::IsCommandIdVisible(int command_id) const { - if (!download_item_) + if (!download_commands_) return false; - if (command_id == PLATFORM_OPEN) - return (DownloadItemModel(download_item_).ShouldPreferOpeningInBrowser()); - - return true; + return download_commands_->IsCommandVisible( + static_cast<DownloadCommands::Command>(command_id)); } void DownloadShelfContextMenu::ExecuteCommand(int command_id, int event_flags) { - if (!download_item_) + if (!download_commands_) return; - switch (static_cast<ContextMenuCommands>(command_id)) { - case SHOW_IN_FOLDER: - download_item_->ShowDownloadInShell(); - break; - case OPEN_WHEN_COMPLETE: - download_item_->OpenDownload(); - break; - case ALWAYS_OPEN_TYPE: { - bool is_checked = IsCommandIdChecked(ALWAYS_OPEN_TYPE); - DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext( - download_item_->GetBrowserContext()); -#if defined(OS_WIN) || defined(OS_LINUX) || \ - (defined(OS_MACOSX) && !defined(OS_IOS)) - if (CanOpenPdfInSystemViewer()) { - prefs->SetShouldOpenPdfInSystemReader(!is_checked); - DownloadItemModel(download_item_).SetShouldPreferOpeningInBrowser( - is_checked); - break; - } -#endif - base::FilePath path = download_item_->GetTargetFilePath(); - if (is_checked) - prefs->DisableAutoOpenBasedOnExtension(path); - else - prefs->EnableAutoOpenBasedOnExtension(path); - break; - } - case PLATFORM_OPEN: - DownloadItemModel(download_item_).OpenUsingPlatformHandler(); - break; - case CANCEL: - download_item_->Cancel(true /* Cancelled by user */); - break; - case TOGGLE_PAUSE: - if (download_item_->GetState() == DownloadItem::IN_PROGRESS && - !download_item_->IsPaused()) { - download_item_->Pause(); - } else { - download_item_->Resume(); - } - break; - case DISCARD: - download_item_->Remove(); - break; - case KEEP: - download_item_->ValidateDangerousDownload(); - break; - case LEARN_MORE_SCANNING: { -#if defined(FULL_SAFE_BROWSING) - using safe_browsing::DownloadProtectionService; - SafeBrowsingService* sb_service = - g_browser_process->safe_browsing_service(); - DownloadProtectionService* protection_service = - (sb_service ? sb_service->download_protection_service() : NULL); - if (protection_service) { - protection_service->ShowDetailsForDownload(*download_item_, navigator_); - } -#else - // Should only be getting invoked if we are using safe browsing. - NOTREACHED(); -#endif - break; - } - case LEARN_MORE_INTERRUPTED: - navigator_->OpenURL( - content::OpenURLParams(GURL(chrome::kDownloadInterruptedLearnMoreURL), - content::Referrer(), - NEW_FOREGROUND_TAB, - ui::PAGE_TRANSITION_LINK, - false)); - break; - } + download_commands_->ExecuteCommand( + static_cast<DownloadCommands::Command>(command_id)); } bool DownloadShelfContextMenu::GetAcceleratorForCommandId( - int command_id, ui::Accelerator* accelerator) { + int command_id, + ui::Accelerator* accelerator) { return false; } bool DownloadShelfContextMenu::IsItemForCommandIdDynamic(int command_id) const { - return command_id == TOGGLE_PAUSE; + return false; } base::string16 DownloadShelfContextMenu::GetLabelForCommandId( int command_id) const { - switch (static_cast<ContextMenuCommands>(command_id)) { - case SHOW_IN_FOLDER: - return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_SHOW); - case OPEN_WHEN_COMPLETE: + int id = -1; + + switch (static_cast<DownloadCommands::Command>(command_id)) { + case DownloadCommands::OPEN_WHEN_COMPLETE: if (download_item_ && !download_item_->IsDone()) - return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE); - return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_OPEN); - case ALWAYS_OPEN_TYPE: - return l10n_util::GetStringUTF16(GetAlwaysOpenStringId()); - case PLATFORM_OPEN: - return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PLATFORM_OPEN); - case CANCEL: - return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_CANCEL); - case TOGGLE_PAUSE: - if (download_item_ && - download_item_->GetState() == DownloadItem::IN_PROGRESS && - !download_item_->IsPaused()) - return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PAUSE_ITEM); - return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_RESUME_ITEM); - case DISCARD: - return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_DISCARD); - case KEEP: - return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_KEEP); - case LEARN_MORE_SCANNING: - return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING); - case LEARN_MORE_INTERRUPTED: - return l10n_util::GetStringUTF16( - IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED); + id = IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE; + else + id = IDS_DOWNLOAD_MENU_OPEN; + break; + case DownloadCommands::PAUSE: + id = IDS_DOWNLOAD_MENU_PAUSE_ITEM; + break; + case DownloadCommands::RESUME: + id = IDS_DOWNLOAD_MENU_RESUME_ITEM; + break; + case DownloadCommands::SHOW_IN_FOLDER: + id = IDS_DOWNLOAD_MENU_SHOW; + break; + case DownloadCommands::DISCARD: + id = IDS_DOWNLOAD_MENU_DISCARD; + break; + case DownloadCommands::KEEP: + id = IDS_DOWNLOAD_MENU_KEEP; + break; + case DownloadCommands::ALWAYS_OPEN_TYPE: { + if (download_commands_) { + bool can_open_pdf_in_system_viewer = + download_commands_->CanOpenPdfInSystemViewer(); +#if defined(OS_WIN) + if (can_open_pdf_in_system_viewer) { + id = IsAdobeReaderDefaultPDFViewer() + ? IDS_DOWNLOAD_MENU_ALWAYS_OPEN_PDF_IN_READER + : IDS_DOWNLOAD_MENU_PLATFORM_OPEN_ALWAYS; + break; + } +#elif defined(OS_MACOSX) || defined(OS_LINUX) + if (can_open_pdf_in_system_viewer) { + id = IDS_DOWNLOAD_MENU_PLATFORM_OPEN_ALWAYS; + break; + } +#endif + } + id = IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE; + break; + } + case DownloadCommands::PLATFORM_OPEN: + id = IDS_DOWNLOAD_MENU_PLATFORM_OPEN; + break; + case DownloadCommands::CANCEL: + id = IDS_DOWNLOAD_MENU_CANCEL; + break; + case DownloadCommands::LEARN_MORE_SCANNING: + id = IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING; + break; + case DownloadCommands::LEARN_MORE_INTERRUPTED: + id = IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED; + break; + case DownloadCommands::RETRY: + NOTREACHED(); + return base::string16(); } - NOTREACHED(); - return base::string16(); + CHECK(id != -1); + return l10n_util::GetStringUTF16(id); } void DownloadShelfContextMenu::DetachFromDownloadItem() { if (!download_item_) return; + download_commands_.reset(); download_item_->RemoveObserver(this); download_item_ = NULL; } @@ -288,40 +193,72 @@ in_progress_download_menu_model_.reset(new ui::SimpleMenuModel(this)); - in_progress_download_menu_model_->AddCheckItemWithStringId( - OPEN_WHEN_COMPLETE, IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE); - in_progress_download_menu_model_->AddCheckItemWithStringId( - ALWAYS_OPEN_TYPE, GetAlwaysOpenStringId()); + in_progress_download_menu_model_->AddCheckItem( + DownloadCommands::OPEN_WHEN_COMPLETE, + GetLabelForCommandId(DownloadCommands::OPEN_WHEN_COMPLETE)); + in_progress_download_menu_model_->AddCheckItem( + DownloadCommands::ALWAYS_OPEN_TYPE, + GetLabelForCommandId(DownloadCommands::ALWAYS_OPEN_TYPE)); in_progress_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); - in_progress_download_menu_model_->AddItemWithStringId( - TOGGLE_PAUSE, IDS_DOWNLOAD_MENU_PAUSE_ITEM); - in_progress_download_menu_model_->AddItemWithStringId( - SHOW_IN_FOLDER, IDS_DOWNLOAD_MENU_SHOW); + in_progress_download_menu_model_->AddItem( + DownloadCommands::PAUSE, GetLabelForCommandId(DownloadCommands::PAUSE)); + in_progress_download_menu_model_->AddItem( + DownloadCommands::SHOW_IN_FOLDER, + GetLabelForCommandId(DownloadCommands::SHOW_IN_FOLDER)); in_progress_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); - in_progress_download_menu_model_->AddItemWithStringId( - CANCEL, IDS_DOWNLOAD_MENU_CANCEL); + in_progress_download_menu_model_->AddItem( + DownloadCommands::CANCEL, GetLabelForCommandId(DownloadCommands::CANCEL)); return in_progress_download_menu_model_.get(); } +ui::SimpleMenuModel* DownloadShelfContextMenu::GetInProgressPausedMenuModel() { + if (in_progress_download_paused_menu_model_) + return in_progress_download_paused_menu_model_.get(); + + in_progress_download_paused_menu_model_.reset(new ui::SimpleMenuModel(this)); + + in_progress_download_paused_menu_model_->AddCheckItem( + DownloadCommands::OPEN_WHEN_COMPLETE, + GetLabelForCommandId(DownloadCommands::OPEN_WHEN_COMPLETE)); + in_progress_download_paused_menu_model_->AddCheckItem( + DownloadCommands::ALWAYS_OPEN_TYPE, + GetLabelForCommandId(DownloadCommands::ALWAYS_OPEN_TYPE)); + in_progress_download_paused_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); + in_progress_download_paused_menu_model_->AddItem( + DownloadCommands::RESUME, GetLabelForCommandId(DownloadCommands::RESUME)); + in_progress_download_paused_menu_model_->AddItem( + DownloadCommands::SHOW_IN_FOLDER, + GetLabelForCommandId(DownloadCommands::SHOW_IN_FOLDER)); + in_progress_download_paused_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); + in_progress_download_paused_menu_model_->AddItem( + DownloadCommands::CANCEL, GetLabelForCommandId(DownloadCommands::CANCEL)); + + return in_progress_download_paused_menu_model_.get(); +} + ui::SimpleMenuModel* DownloadShelfContextMenu::GetFinishedMenuModel() { if (finished_download_menu_model_) return finished_download_menu_model_.get(); finished_download_menu_model_.reset(new ui::SimpleMenuModel(this)); - finished_download_menu_model_->AddItemWithStringId( - OPEN_WHEN_COMPLETE, IDS_DOWNLOAD_MENU_OPEN); - finished_download_menu_model_->AddCheckItemWithStringId( - ALWAYS_OPEN_TYPE, GetAlwaysOpenStringId()); - finished_download_menu_model_->AddItemWithStringId( - PLATFORM_OPEN, IDS_DOWNLOAD_MENU_PLATFORM_OPEN); + finished_download_menu_model_->AddItem( + DownloadCommands::OPEN_WHEN_COMPLETE, + GetLabelForCommandId(DownloadCommands::OPEN_WHEN_COMPLETE)); + finished_download_menu_model_->AddCheckItem( + DownloadCommands::ALWAYS_OPEN_TYPE, + GetLabelForCommandId(DownloadCommands::ALWAYS_OPEN_TYPE)); + finished_download_menu_model_->AddItem( + DownloadCommands::PLATFORM_OPEN, + GetLabelForCommandId(DownloadCommands::PLATFORM_OPEN)); finished_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); - finished_download_menu_model_->AddItemWithStringId( - SHOW_IN_FOLDER, IDS_DOWNLOAD_MENU_SHOW); + finished_download_menu_model_->AddItem( + DownloadCommands::SHOW_IN_FOLDER, + GetLabelForCommandId(DownloadCommands::SHOW_IN_FOLDER)); finished_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); - finished_download_menu_model_->AddItemWithStringId( - CANCEL, IDS_DOWNLOAD_MENU_CANCEL); + finished_download_menu_model_->AddItem( + DownloadCommands::CANCEL, GetLabelForCommandId(DownloadCommands::CANCEL)); return finished_download_menu_model_.get(); } @@ -340,20 +277,23 @@ interrupted_download_menu_model_.reset(new ui::SimpleMenuModel(this)); if (IsDownloadResumptionEnabled()) { - interrupted_download_menu_model_->AddItemWithStringId( - TOGGLE_PAUSE, IDS_DOWNLOAD_MENU_RESUME_ITEM); + interrupted_download_menu_model_->AddItem( + DownloadCommands::RESUME, + GetLabelForCommandId(DownloadCommands::RESUME)); } #if defined(OS_WIN) // The Help Center article is currently Windows specific. // TODO(asanka): Enable this for other platforms when the article is expanded // for other platforms. - interrupted_download_menu_model_->AddItemWithStringId( - LEARN_MORE_INTERRUPTED, IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED); + interrupted_download_menu_model_->AddItem( + DownloadCommands::LEARN_MORE_INTERRUPTED, + GetLabelForCommandId(DownloadCommands::LEARN_MORE_INTERRUPTED)); #endif if (IsDownloadResumptionEnabled()) { interrupted_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); - interrupted_download_menu_model_->AddItemWithStringId( - CANCEL, IDS_DOWNLOAD_MENU_CANCEL); + interrupted_download_menu_model_->AddItem( + DownloadCommands::CANCEL, + GetLabelForCommandId(DownloadCommands::CANCEL)); } return interrupted_download_menu_model_.get(); @@ -365,11 +305,12 @@ maybe_malicious_download_menu_model_.reset(new ui::SimpleMenuModel(this)); - maybe_malicious_download_menu_model_->AddItemWithStringId( - KEEP, IDS_DOWNLOAD_MENU_KEEP); + maybe_malicious_download_menu_model_->AddItem( + DownloadCommands::KEEP, GetLabelForCommandId(DownloadCommands::KEEP)); maybe_malicious_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); - maybe_malicious_download_menu_model_->AddItemWithStringId( - LEARN_MORE_SCANNING, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING); + maybe_malicious_download_menu_model_->AddItem( + DownloadCommands::LEARN_MORE_SCANNING, + GetLabelForCommandId(DownloadCommands::LEARN_MORE_SCANNING)); return maybe_malicious_download_menu_model_.get(); } @@ -378,40 +319,9 @@ return malicious_download_menu_model_.get(); malicious_download_menu_model_.reset(new ui::SimpleMenuModel(this)); - - DownloadItemModel download_model(download_item_); - malicious_download_menu_model_->AddItemWithStringId( - LEARN_MORE_SCANNING, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING); + malicious_download_menu_model_->AddItem( + DownloadCommands::LEARN_MORE_SCANNING, + GetLabelForCommandId(DownloadCommands::LEARN_MORE_SCANNING)); return malicious_download_menu_model_.get(); } - -int DownloadShelfContextMenu::GetAlwaysOpenStringId() const { -#if defined(OS_WIN) - if (CanOpenPdfInSystemViewer()) - return IsAdobeReaderDefaultPDFViewer() - ? IDS_DOWNLOAD_MENU_ALWAYS_OPEN_PDF_IN_READER - : IDS_DOWNLOAD_MENU_PLATFORM_OPEN_ALWAYS; -#elif defined(OS_MACOSX) || defined(OS_LINUX) - if (CanOpenPdfInSystemViewer()) - return IDS_DOWNLOAD_MENU_PLATFORM_OPEN_ALWAYS; -#endif - return IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE; -} - -#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) -bool DownloadShelfContextMenu::IsDownloadPdf() const { - base::FilePath path = download_item_->GetTargetFilePath(); - return path.MatchesExtension(FILE_PATH_LITERAL(".pdf")); -} -#endif - -bool DownloadShelfContextMenu::CanOpenPdfInSystemViewer() const { -#if defined(OS_WIN) - return IsDownloadPdf() && - (IsAdobeReaderDefaultPDFViewer() ? is_adobe_pdf_reader_up_to_date_ : - true); -#elif defined(OS_MACOSX) || defined(OS_LINUX) - return IsDownloadPdf(); -#endif -}
diff --git a/chrome/browser/download/download_shelf_context_menu.h b/chrome/browser/download/download_shelf_context_menu.h index ecf9d99f..5119359 100644 --- a/chrome/browser/download/download_shelf_context_menu.h +++ b/chrome/browser/download/download_shelf_context_menu.h
@@ -9,6 +9,7 @@ #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "base/strings/string16.h" +#include "chrome/browser/download/download_commands.h" #include "content/public/browser/download_item.h" #include "ui/base/models/simple_menu_model.h" @@ -24,26 +25,12 @@ class DownloadShelfContextMenu : public ui::SimpleMenuModel::Delegate, public content::DownloadItem::Observer { public: - enum ContextMenuCommands { - SHOW_IN_FOLDER = 1, // Open a folder view window with the item selected. - OPEN_WHEN_COMPLETE, // Open the download when it's finished. - ALWAYS_OPEN_TYPE, // Default this file extension to always open. - PLATFORM_OPEN, // Open using platform handler. - CANCEL, // Cancel the download. - TOGGLE_PAUSE, // Pause or resume a download. - DISCARD, // Discard the malicious download. - KEEP, // Keep the malicious download. - LEARN_MORE_SCANNING, // Show information about download scanning. - LEARN_MORE_INTERRUPTED,// Show information about interrupted downloads. - }; - ~DownloadShelfContextMenu() override; content::DownloadItem* download_item() const { return download_item_; } protected: - DownloadShelfContextMenu(content::DownloadItem* download_item, - content::PageNavigator* navigator); + explicit DownloadShelfContextMenu(content::DownloadItem* download_item); // Returns the correct menu model depending on the state of the download item. // Returns NULL if the download was destroyed. @@ -68,22 +55,16 @@ void OnDownloadDestroyed(content::DownloadItem* download) override; ui::SimpleMenuModel* GetInProgressMenuModel(); + ui::SimpleMenuModel* GetInProgressPausedMenuModel(); ui::SimpleMenuModel* GetFinishedMenuModel(); ui::SimpleMenuModel* GetInterruptedMenuModel(); ui::SimpleMenuModel* GetMaybeMaliciousMenuModel(); ui::SimpleMenuModel* GetMaliciousMenuModel(); - int GetAlwaysOpenStringId() const; - -#if defined(OS_WIN) || defined(OS_LINUX) || \ - (defined(OS_MACOSX) && !defined(OS_IOS)) - bool IsDownloadPdf() const; - bool CanOpenPdfInSystemViewer() const; -#endif - // We show slightly different menus if the download is in progress vs. if the // download has finished. scoped_ptr<ui::SimpleMenuModel> in_progress_download_menu_model_; + scoped_ptr<ui::SimpleMenuModel> in_progress_download_paused_menu_model_; scoped_ptr<ui::SimpleMenuModel> finished_download_menu_model_; scoped_ptr<ui::SimpleMenuModel> interrupted_download_menu_model_; scoped_ptr<ui::SimpleMenuModel> maybe_malicious_download_menu_model_; @@ -91,9 +72,7 @@ // Information source. content::DownloadItem* download_item_; - - // Used to open tabs. - content::PageNavigator* navigator_; + scoped_ptr<DownloadCommands> download_commands_; #if defined(OS_WIN) bool is_adobe_pdf_reader_up_to_date_;
diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc index ad40bc0..8678dcff 100644 --- a/chrome/browser/download/download_target_determiner.cc +++ b/chrome/browser/download/download_target_determiner.cc
@@ -210,7 +210,11 @@ target_directory = download_prefs_->DownloadPath(); } virtual_path_ = target_directory.Append(generated_filename); +#if defined(OS_ANDROID) + conflict_action_ = DownloadPathReservationTracker::PROMPT; +#else conflict_action_ = DownloadPathReservationTracker::UNIQUIFY; +#endif should_notify_extensions_ = true; } else { virtual_path_ = download_->GetForcedFilePath();
diff --git a/chrome/browser/download/download_ui_controller.cc b/chrome/browser/download/download_ui_controller.cc index 5c249cd..eec0f38 100644 --- a/chrome/browser/download/download_ui_controller.cc +++ b/chrome/browser/download/download_ui_controller.cc
@@ -5,10 +5,13 @@ #include "chrome/browser/download/download_ui_controller.h" #include "base/callback.h" +#include "base/command_line.h" #include "base/stl_util.h" #include "chrome/browser/download/download_item_model.h" +#include "chrome/browser/download/notification/download_notification_manager.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_tabstrip.h" +#include "chrome/common/chrome_switches.h" #include "content/public/browser/download_item.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" @@ -17,26 +20,28 @@ #include "content/public/browser/android/download_controller_android.h" #else #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/host_desktop.h" #endif namespace { -// DefaultUIControllerDelegate{Android,} is used when a DownloadUIController is +// DownloadShelfUIControllerDelegate{Android,} is used when a +// DownloadUIController is // constructed without specifying an explicit Delegate. #if defined(OS_ANDROID) -class DefaultUIControllerDelegateAndroid - : public DownloadUIController::Delegate { +class AndroidUIControllerDelegate : public DownloadUIController::Delegate { public: - DefaultUIControllerDelegateAndroid() {} - ~DefaultUIControllerDelegateAndroid() override {} + AndroidUIControllerDelegate() {} + ~AndroidUIControllerDelegate() override {} private: // DownloadUIController::Delegate void OnNewDownloadReady(content::DownloadItem* item) override; }; -void DefaultUIControllerDelegateAndroid::OnNewDownloadReady( +void AndroidUIControllerDelegate::OnNewDownloadReady( content::DownloadItem* item) { // The Android DownloadController is only interested in IN_PROGRESS downloads. // Ones which are INTERRUPTED etc. can't be handed over to the Android @@ -52,12 +57,13 @@ #else // OS_ANDROID -class DefaultUIControllerDelegate : public DownloadUIController::Delegate { +class DownloadShelfUIControllerDelegate + : public DownloadUIController::Delegate { public: - // |profile| is required to outlive DefaultUIControllerDelegate. - explicit DefaultUIControllerDelegate(Profile* profile) + // |profile| is required to outlive DownloadShelfUIControllerDelegate. + explicit DownloadShelfUIControllerDelegate(Profile* profile) : profile_(profile) {} - ~DefaultUIControllerDelegate() override {} + ~DownloadShelfUIControllerDelegate() override {} private: // DownloadUIController::Delegate @@ -66,7 +72,7 @@ Profile* profile_; }; -void DefaultUIControllerDelegate::OnNewDownloadReady( +void DownloadShelfUIControllerDelegate::OnNewDownloadReady( content::DownloadItem* item) { content::WebContents* web_contents = item->GetWebContents(); Browser* browser = @@ -96,13 +102,19 @@ delegate_(delegate.Pass()) { if (!delegate_) { #if defined(OS_ANDROID) - delegate_.reset(new DefaultUIControllerDelegateAndroid()); + delegate_.reset(new AndroidUIControllerDelegate()); #else // The delegate should not be invoked after the profile has gone away. This // should be the case since DownloadUIController is owned by // DownloadService, which in turn is a profile keyed service. - delegate_.reset(new DefaultUIControllerDelegate( - Profile::FromBrowserContext(manager->GetBrowserContext()))); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableDownloadNotification)) { + delegate_.reset(new DownloadNotificationManager( + Profile::FromBrowserContext(manager->GetBrowserContext()))); + } else { + delegate_.reset(new DownloadShelfUIControllerDelegate( + Profile::FromBrowserContext(manager->GetBrowserContext()))); + } #endif } }
diff --git a/chrome/browser/download/notification/download_notification_item.cc b/chrome/browser/download/notification/download_notification_item.cc new file mode 100644 index 0000000..e3bd6bee --- /dev/null +++ b/chrome/browser/download/notification/download_notification_item.cc
@@ -0,0 +1,457 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/download/notification/download_notification_item.h" + +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/download/download_crx_util.h" +#include "chrome/browser/download/download_item_model.h" +#include "chrome/grit/chromium_strings.h" +#include "chrome/grit/generated_resources.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/download_item.h" +#include "content/public/browser/web_contents.h" +#include "grit/theme_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_delegate.h" + +using message_center::Notification; + +namespace { + +const char kDownloadNotificationNotifierId[] = + "chrome://settings/display/notification/id-notifier"; +const char kDownloadNotificationIdBase[] = + "chrome://settings/display/notification/id-"; + +} // anonymous namespace + +DownloadNotificationItem::NotificationWatcher::NotificationWatcher( + DownloadNotificationItem* item) + : item_(item) { +} + +DownloadNotificationItem::NotificationWatcher::~NotificationWatcher() { +} + +void DownloadNotificationItem::NotificationWatcher::Close(bool by_user) { + item_->OnNotificationClose(by_user); +} + +void DownloadNotificationItem::NotificationWatcher::Click() { + item_->OnNotificationClick(); +} + +bool DownloadNotificationItem::NotificationWatcher::HasClickedListener() { + return true; +} + +void DownloadNotificationItem::NotificationWatcher::ButtonClick( + int button_index) { + item_->OnNotificationButtonClick(button_index); +} + +void DownloadNotificationItem::NotificationWatcher::OnNotificationRemoved( + const std::string& id, + bool by_user) { + if (id != item_->notification_->id()) + return; + item_->OnNotificationRemoved(by_user); +} + +DownloadNotificationItem::DownloadNotificationItem(content::DownloadItem* item, + Delegate* delegate) + : openable_(false), + downloading_(false), + reshow_after_remove_(false), + image_resource_id_(0), + watcher_(new NotificationWatcher(this)), + item_(item), + delegate_(delegate) { + item->AddObserver(this); + + message_center_ = message_center::MessageCenter::Get(); + message_center_->AddObserver(watcher_.get()); + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + + const base::string16 timeout_message = + l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING); + const base::string16 message = + l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL); + + std::string id(kDownloadNotificationIdBase); + id += base::UintToString(item_->GetId()); + + message_center::RichNotificationData data; + notification_.reset(new Notification( + message_center::NOTIFICATION_TYPE_PROGRESS, id, message, timeout_message, + bundle.GetImageNamed(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING), + base::string16() /* display_source */, + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + kDownloadNotificationNotifierId), + data, watcher_.get())); + + notification_->set_progress(0); + notification_->set_never_timeout(false); + + UpdateNotificationData(); + + scoped_ptr<Notification> notification(new Notification(*notification_)); + message_center_->AddNotification(notification.Pass()); +} + +DownloadNotificationItem::~DownloadNotificationItem() { + if (item_) + item_->RemoveObserver(this); + message_center_->RemoveObserver(watcher_.get()); +} + +void DownloadNotificationItem::OnNotificationClose(bool by_user) { + if (item_->GetState() != content::DownloadItem::IN_PROGRESS) { + reshow_after_remove_ = false; + } else { + bool popup = false; + + const std::string id = notification_->id(); + message_center::NotificationList::PopupNotifications popups = + message_center_->GetPopupNotifications(); + for (auto it = popups.begin(); it != popups.end(); it++) { + if ((*it)->id() == id) { + popup = true; + break; + } + } + + // Reshows the notification in the notification center, if the download is + // in progress and the notifitation being closed is a popup. + reshow_after_remove_ = popup; + } + + // OnNotificationRemoved() will be called soon, just after the notification + // is removed. +} + +void DownloadNotificationItem::OnNotificationRemoved(bool by_user) { + if (reshow_after_remove_) { + // Sets the notification as read. + notification_->set_is_read(true); + + // Reshows the notification. + scoped_ptr<Notification> notification(new Notification(*notification_)); + message_center_->AddNotification(notification.Pass()); + // Show the reshown notification as a non-popup. + message_center_->MarkSinglePopupAsShown(notification_->id(), true); + + reshow_after_remove_ = false; + } else { + // Cancels the download. + item_->Cancel(by_user); + delegate_->OnDownloadRemoved(this); + } +} + +void DownloadNotificationItem::OnNotificationClick() { + if (openable_) { + if (item_->IsDone()) + item_->OpenDownload(); + else + item_->SetOpenWhenComplete(!item_->GetOpenWhenComplete()); // Toggle + } + + if (item_->IsDone()) + message_center_->RemoveNotification(notification_->id(), true); +} + +void DownloadNotificationItem::OnNotificationButtonClick(int button_index) { + if (button_index < 0 || + static_cast<size_t>(button_index) >= button_actions_->size()) { + // Out of boundary. + NOTREACHED(); + return; + } + + DownloadCommands::Command command = button_actions_->at(button_index); + DownloadCommands(item_).ExecuteCommand(command); +} + +// DownloadItem::Observer methods +void DownloadNotificationItem::OnDownloadUpdated(content::DownloadItem* item) { + DCHECK_EQ(item, item_); + + UpdateNotificationData(); + + // Updates notification. + scoped_ptr<Notification> notification(new Notification(*notification_)); + std::string id = notification->id(); + message_center_->UpdateNotification(id, notification.Pass()); +} + +void DownloadNotificationItem::UpdateNotificationData() { + DownloadItemModel model(item_); + DownloadCommands command(item_); + + if (!downloading_) { + if (item_->GetState() == content::DownloadItem::IN_PROGRESS) { + delegate_->OnDownloadStarted(this); + downloading_ = true; + } + } else { + if (item_->GetState() != content::DownloadItem::IN_PROGRESS) { + delegate_->OnDownloadStopped(this); + downloading_ = false; + } + } + + if (item_->IsDangerous()) { + notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); + notification_->set_title(GetTitle()); + notification_->set_message(GetWarningText()); + + // Show icon. + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_MALICIOUS); + } else { + notification_->set_title(GetTitle()); + notification_->set_message(model.GetStatusText()); + + bool is_off_the_record = item_->GetBrowserContext() && + item_->GetBrowserContext()->IsOffTheRecord(); + + switch (item_->GetState()) { + case content::DownloadItem::IN_PROGRESS: + notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS); + notification_->set_progress(item_->PercentComplete()); + if (is_off_the_record) { + // TODO(yoshiki): Replace the tentative image. + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_INCOGNITO); + } else { + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING); + } + break; + case content::DownloadItem::COMPLETE: + notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); + if (is_off_the_record) { + // TODO(yoshiki): Replace the tentative image. + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_INCOGNITO); + } else { + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING); + } + + // TODO(yoshiki): Popup a notification again. + break; + case content::DownloadItem::CANCELLED: + notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_WARNING); + break; + case content::DownloadItem::INTERRUPTED: + notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_WARNING); + + // TODO(yoshiki): Popup a notification again. + break; + case content::DownloadItem::MAX_DOWNLOAD_STATE: // sentinel + NOTREACHED(); + } + } + + std::vector<message_center::ButtonInfo> notification_actions; + scoped_ptr<std::vector<DownloadCommands::Command>> actions( + GetPossibleActions().Pass()); + + openable_ = false; + button_actions_.reset(new std::vector<DownloadCommands::Command>); + for (auto it = actions->begin(); it != actions->end(); it++) { + if (*it == DownloadCommands::OPEN_WHEN_COMPLETE) { + openable_ = true; + } else { + button_actions_->push_back(*it); + message_center::ButtonInfo button_info = + message_center::ButtonInfo(GetCommandLabel(*it)); + button_info.icon = command.GetCommandIcon(*it); + notification_actions.push_back(button_info); + } + } + notification_->set_buttons(notification_actions); + + if (item_->IsDone()) { + // TODO(yoshiki): If the downloaded file is an image, show the thumbnail. + } +} + +void DownloadNotificationItem::OnDownloadOpened(content::DownloadItem* item) { + DCHECK_EQ(item, item_); + // Do nothing. +} + +void DownloadNotificationItem::OnDownloadRemoved(content::DownloadItem* item) { + DCHECK_EQ(item, item_); + + // Removing the notification causes calling both |OnNotificationClose()| and + // |OnNotificationRemoved()|. + message_center_->RemoveNotification(notification_->id(), false); +} + +void DownloadNotificationItem::OnDownloadDestroyed( + content::DownloadItem* item) { + DCHECK_EQ(item, item_); + + item_ = nullptr; +} + +void DownloadNotificationItem::SetNotificationImage(int resource_id) { + if (image_resource_id_ == resource_id) + return; + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + image_resource_id_ = resource_id; + notification_->set_icon(bundle.GetImageNamed(image_resource_id_)); +} + +scoped_ptr<std::vector<DownloadCommands::Command>> +DownloadNotificationItem::GetPossibleActions() const { + scoped_ptr<std::vector<DownloadCommands::Command>> actions( + new std::vector<DownloadCommands::Command>()); + + if (item_->IsDangerous()) { + actions->push_back(DownloadCommands::DISCARD); + actions->push_back(DownloadCommands::KEEP); + return actions.Pass(); + } + + switch (item_->GetState()) { + case content::DownloadItem::IN_PROGRESS: + actions->push_back(DownloadCommands::OPEN_WHEN_COMPLETE); + if (!item_->IsPaused()) + actions->push_back(DownloadCommands::PAUSE); + else + actions->push_back(DownloadCommands::RESUME); + break; + case content::DownloadItem::CANCELLED: + case content::DownloadItem::INTERRUPTED: + actions->push_back(DownloadCommands::RETRY); + break; + case content::DownloadItem::COMPLETE: + actions->push_back(DownloadCommands::OPEN_WHEN_COMPLETE); + actions->push_back(DownloadCommands::SHOW_IN_FOLDER); + break; + case content::DownloadItem::MAX_DOWNLOAD_STATE: + NOTREACHED(); + } + return actions.Pass(); +} + +base::string16 DownloadNotificationItem::GetTitle() const { + base::string16 title_text; + base::string16 file_name = + item_->GetFileNameToReportUser().LossyDisplayName(); + switch (item_->GetState()) { + case content::DownloadItem::IN_PROGRESS: + title_text = l10n_util::GetStringFUTF16( + IDS_DOWNLOAD_STATUS_IN_PROGRESS_TITLE, file_name); + break; + case content::DownloadItem::COMPLETE: + title_text = l10n_util::GetStringFUTF16( + IDS_DOWNLOAD_STATUS_DOWNLOADED_TITLE, file_name); + case content::DownloadItem::INTERRUPTED: + title_text = l10n_util::GetStringFUTF16( + IDS_DOWNLOAD_STATUS_DOWNLOADED_TITLE, file_name); + break; + case content::DownloadItem::CANCELLED: + title_text = l10n_util::GetStringFUTF16( + IDS_DOWNLOAD_STATUS_DOWNLOAD_FAILED_TITLE, file_name); + break; + case content::DownloadItem::MAX_DOWNLOAD_STATE: + NOTREACHED(); + } + return title_text; +} + +base::string16 DownloadNotificationItem::GetCommandLabel( + DownloadCommands::Command command) const { + int id = -1; + switch (command) { + case DownloadCommands::OPEN_WHEN_COMPLETE: + if (item_ && !item_->IsDone()) + id = IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE; + else + id = IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE; + break; + case DownloadCommands::PAUSE: + // Only for non menu. + id = IDS_DOWNLOAD_LINK_PAUSE; + break; + case DownloadCommands::RESUME: + // Only for non menu. + id = IDS_DOWNLOAD_LINK_RESUME; + break; + case DownloadCommands::SHOW_IN_FOLDER: + id = IDS_DOWNLOAD_LINK_SHOW; + break; + case DownloadCommands::RETRY: + // Only for non menu. + id = IDS_DOWNLOAD_LINK_RETRY; + break; + case DownloadCommands::DISCARD: + id = IDS_DISCARD_DOWNLOAD; + break; + case DownloadCommands::KEEP: + id = IDS_CONFIRM_DOWNLOAD; + break; + case DownloadCommands::ALWAYS_OPEN_TYPE: + case DownloadCommands::PLATFORM_OPEN: + case DownloadCommands::CANCEL: + case DownloadCommands::LEARN_MORE_SCANNING: + case DownloadCommands::LEARN_MORE_INTERRUPTED: + // Only for menu. + NOTREACHED(); + return base::string16(); + } + CHECK(id != -1); + return l10n_util::GetStringUTF16(id); +} + +base::string16 DownloadNotificationItem::GetWarningText() const { + // Should only be called if IsDangerous(). + DCHECK(item_->IsDangerous()); + base::string16 elided_filename = + item_->GetFileNameToReportUser().LossyDisplayName(); + switch (item_->GetDangerType()) { + case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: { + return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL); + } + case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: { + if (download_crx_util::IsExtensionDownload(*item_)) { + return l10n_util::GetStringUTF16( + IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION); + } else { + return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD, + elided_filename); + } + } + case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: + case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: { + return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT, + elided_filename); + } + case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: { + return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT, + elided_filename); + } + case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: { + return l10n_util::GetStringFUTF16(IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, + elided_filename); + } + case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: + case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: + case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: + case content::DOWNLOAD_DANGER_TYPE_MAX: { + break; + } + } + NOTREACHED(); + return base::string16(); +}
diff --git a/chrome/browser/download/notification/download_notification_item.h b/chrome/browser/download/notification/download_notification_item.h new file mode 100644 index 0000000..6470e7a --- /dev/null +++ b/chrome/browser/download/notification/download_notification_item.h
@@ -0,0 +1,104 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_DOWNLOAD_NOTIFICATION_DOWNLOAD_NOTIFICATION_ITEM_H_ +#define CHROME_BROWSER_DOWNLOAD_NOTIFICATION_DOWNLOAD_NOTIFICATION_ITEM_H_ + +#include "chrome/browser/download/notification/download_notification_item.h" + +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/download/download_commands.h" +#include "content/public/browser/download_item.h" +#include "grit/theme_resources.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/message_center_observer.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_delegate.h" + +using message_center::Notification; + +namespace test { +class DownloadNotificationItemTest; +} + +class DownloadNotificationItem : public content::DownloadItem::Observer { + public: + class Delegate { + public: + virtual void OnDownloadStarted(DownloadNotificationItem* item) = 0; + virtual void OnDownloadStopped(DownloadNotificationItem* item) = 0; + virtual void OnDownloadRemoved(DownloadNotificationItem* item) = 0; + }; + + DownloadNotificationItem(content::DownloadItem* item, Delegate* delegate); + + ~DownloadNotificationItem() override; + + private: + class NotificationWatcher : public message_center::NotificationDelegate, + public message_center::MessageCenterObserver { + public: + explicit NotificationWatcher(DownloadNotificationItem* item); + + private: + ~NotificationWatcher() override; + + // message_center::NotificationDelegate overrides: + void Close(bool by_user) override; + void Click() override; + bool HasClickedListener() override; + void ButtonClick(int button_index) override; + + // message_center::MessageCenterObserver overrides: + void OnNotificationRemoved(const std::string& id, bool by_user) override; + + DownloadNotificationItem* item_; + }; + + void OnNotificationClick(); + void OnNotificationButtonClick(int button_index); + void OnNotificationClose(bool by_user); + void OnNotificationRemoved(bool by_user); + + // DownloadItem::Observer overrides: + void OnDownloadUpdated(content::DownloadItem* item) override; + void OnDownloadOpened(content::DownloadItem* item) override; + void OnDownloadRemoved(content::DownloadItem* item) override; + void OnDownloadDestroyed(content::DownloadItem* item) override; + + void UpdateNotificationData(); + void SetNotificationImage(int resource_id); + + // Returns a short one-line status string for the download. + base::string16 GetTitle() const; + + // Returns a short one-line status string for a download command. + base::string16 GetCommandLabel(DownloadCommands::Command command) const; + + // Get the warning test to notify a dangerous download. Should only be called + // if IsDangerous() is true. + base::string16 GetWarningText() const; + + scoped_ptr<std::vector<DownloadCommands::Command>> GetPossibleActions() const; + + bool openable_; + bool downloading_; + bool reshow_after_remove_; + int image_resource_id_; + scoped_refptr<NotificationWatcher> watcher_; + + message_center::MessageCenter* message_center_; + scoped_ptr<Notification> notification_; + + content::DownloadItem* item_; + scoped_ptr<std::vector<DownloadCommands::Command>> button_actions_; + + Delegate* const delegate_; + + friend class test::DownloadNotificationItemTest; + + DISALLOW_COPY_AND_ASSIGN(DownloadNotificationItem); +}; + +#endif // CHROME_BROWSER_DOWNLOAD_NOTIFICATION_DOWNLOAD_NOTIFICATION_ITEM_H_
diff --git a/chrome/browser/download/notification/download_notification_item_unittest.cc b/chrome/browser/download/notification/download_notification_item_unittest.cc new file mode 100644 index 0000000..693ee03 --- /dev/null +++ b/chrome/browser/download/notification/download_notification_item_unittest.cc
@@ -0,0 +1,269 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/download/notification/download_notification_item.h" + +#include "base/run_loop.h" +#include "base/test/test_simple_task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "content/public/test/mock_download_item.h" +#include "content/public/test/mock_download_manager.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/message_center/fake_message_center.h" + +using testing::NiceMock; +using testing::Return; +using testing::_; + +namespace { + +class MockDownloadNotificationItemDelegate + : public DownloadNotificationItem::Delegate { + public: + MockDownloadNotificationItemDelegate() + : on_download_removed_call_count_(0u), + on_download_started_call_count_(0u), + on_download_stopped_call_count_(0u) {} + + void OnDownloadRemoved(DownloadNotificationItem* item) override { + on_download_removed_call_count_++; + } + + void OnDownloadStarted(DownloadNotificationItem* item) override { + on_download_started_call_count_++; + } + + void OnDownloadStopped(DownloadNotificationItem* item) override { + on_download_stopped_call_count_++; + } + + size_t GetOnDownloadRemovedCallCount() { + return on_download_removed_call_count_; + } + + size_t GetOnDownloadStartedCallCount() { + return on_download_started_call_count_; + } + + size_t GetOnDownloadStoppedCallCount() { + return on_download_stopped_call_count_; + } + + private: + size_t on_download_removed_call_count_; + size_t on_download_started_call_count_; + size_t on_download_stopped_call_count_; +}; + +} // anonymous namespace + +namespace test { + +class DownloadNotificationItemTest : public testing::Test { + public: + DownloadNotificationItemTest() + : runner_(new base::TestSimpleTaskRunner), runner_handler_(runner_) {} + + void SetUp() override { + testing::Test::SetUp(); + message_center::MessageCenter::Initialize(); + + download_item_.reset(new NiceMock<content::MockDownloadItem>()); + ON_CALL(*download_item_, GetId()).WillByDefault(Return(12345)); + ON_CALL(*download_item_, GetState()) + .WillByDefault(Return(content::DownloadItem::IN_PROGRESS)); + ON_CALL(*download_item_, IsDangerous()).WillByDefault(Return(false)); + ON_CALL(*download_item_, GetFileNameToReportUser()) + .WillByDefault(Return(base::FilePath("TITLE.bin"))); + ON_CALL(*download_item_, GetDangerType()) + .WillByDefault(Return(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)); + ON_CALL(*download_item_, IsDone()).WillByDefault(Return(false)); + } + + void TearDown() override { + download_notification_item_.reset(); + message_center::MessageCenter::Shutdown(); + testing::Test::TearDown(); + } + + protected: + message_center::MessageCenter* message_center() { + return message_center::MessageCenter::Get(); + } + + std::string notification_id() { + return download_notification_item_->notification_->id(); + } + + message_center::Notification* notification() { + return message_center()->FindVisibleNotificationById(notification_id()); + } + + // Trampoline methods to access a private method in DownloadNotificationItem. + void NotificationItemClick() { + return download_notification_item_->OnNotificationClick(); + } + void NotificationItemButtonClick(int index) { + return download_notification_item_->OnNotificationButtonClick(index); + } + + bool IsPopupNotification(const std::string& notification_id) { + message_center::NotificationList::PopupNotifications popups = + message_center()->GetPopupNotifications(); + for (auto it = popups.begin(); it != popups.end(); it++) { + if ((*it)->id() == notification_id) { + return true; + } + } + return false; + } + + void CreateDownloadNotificationItem() { + download_notification_item_.reset( + new DownloadNotificationItem(download_item_.get(), &delegate_)); + } + + scoped_refptr<base::TestSimpleTaskRunner> runner_; + base::ThreadTaskRunnerHandle runner_handler_; + + MockDownloadNotificationItemDelegate delegate_; + scoped_ptr<NiceMock<content::MockDownloadItem>> download_item_; + scoped_ptr<DownloadNotificationItem> download_notification_item_; +}; + +TEST_F(DownloadNotificationItemTest, ShowAndCloseNotification) { + EXPECT_EQ(0u, message_center()->NotificationCount()); + + // Shows a notification + CreateDownloadNotificationItem(); + download_item_->NotifyObserversDownloadOpened(); + + // Confirms that the notification is shown as a popup. + EXPECT_EQ(1u, message_center()->NotificationCount()); + EXPECT_TRUE(IsPopupNotification(notification_id())); + + // Makes sure the DownloadItem::Cancel() is not called. + EXPECT_CALL(*download_item_, Cancel(_)).Times(0); + // Closes it once. + message_center()->RemoveNotification(notification_id(), true); + + // Confirms that the notification is shown but is not a popup. + EXPECT_EQ(1u, message_center()->NotificationCount()); + EXPECT_FALSE(IsPopupNotification(notification_id())); + + // Makes sure the DownloadItem::Cancel() is called once. + EXPECT_CALL(*download_item_, Cancel(_)).Times(1); + // Closes it again. + message_center()->RemoveNotification(notification_id(), true); + + // Confirms that the notification is closed. + EXPECT_EQ(0u, message_center()->NotificationCount()); +} + +TEST_F(DownloadNotificationItemTest, PauseAndResumeNotification) { + // Shows a notification + CreateDownloadNotificationItem(); + download_item_->NotifyObserversDownloadOpened(); + + // Confirms that the notification is shown as a popup. + EXPECT_EQ(message_center()->NotificationCount(), 1u); + EXPECT_TRUE(IsPopupNotification(notification_id())); + + // Pauses and makes sure the DownloadItem::Pause() is called. + EXPECT_CALL(*download_item_, Pause()).Times(1); + EXPECT_CALL(*download_item_, IsPaused()).WillRepeatedly(Return(true)); + NotificationItemButtonClick(0); + download_item_->NotifyObserversDownloadUpdated(); + + // Resumes and makes sure the DownloadItem::Resume() is called. + EXPECT_CALL(*download_item_, Resume()).Times(1); + EXPECT_CALL(*download_item_, IsPaused()).WillRepeatedly(Return(false)); + NotificationItemButtonClick(0); + download_item_->NotifyObserversDownloadUpdated(); +} + +TEST_F(DownloadNotificationItemTest, OpenDownload) { + EXPECT_CALL(*download_item_, GetState()) + .WillRepeatedly(Return(content::DownloadItem::COMPLETE)); + EXPECT_CALL(*download_item_, IsDone()).WillRepeatedly(Return(true)); + + // Shows a notification. + CreateDownloadNotificationItem(); + download_item_->NotifyObserversDownloadOpened(); + download_item_->NotifyObserversDownloadUpdated(); + + // Clicks and confirms that the OpenDownload() is called. + EXPECT_CALL(*download_item_, OpenDownload()).Times(1); + EXPECT_CALL(*download_item_, SetOpenWhenComplete(_)).Times(0); + NotificationItemClick(); +} + +TEST_F(DownloadNotificationItemTest, OpenWhenComplete) { + // Shows a notification + CreateDownloadNotificationItem(); + download_item_->NotifyObserversDownloadOpened(); + + EXPECT_CALL(*download_item_, OpenDownload()).Times(0); + + // Toggles open-when-complete (new value: true). + EXPECT_CALL(*download_item_, SetOpenWhenComplete(true)) + .Times(1) + .WillOnce(Return()); + NotificationItemClick(); + EXPECT_CALL(*download_item_, GetOpenWhenComplete()) + .WillRepeatedly(Return(true)); + + // Toggles open-when-complete (new value: false). + EXPECT_CALL(*download_item_, SetOpenWhenComplete(false)) + .Times(1) + .WillOnce(Return()); + NotificationItemClick(); + EXPECT_CALL(*download_item_, GetOpenWhenComplete()) + .WillRepeatedly(Return(false)); + + // Sets open-when-complete. + EXPECT_CALL(*download_item_, SetOpenWhenComplete(true)) + .Times(1) + .WillOnce(Return()); + NotificationItemClick(); + EXPECT_CALL(*download_item_, GetOpenWhenComplete()) + .WillRepeatedly(Return(true)); + + // Downloading is completed. + EXPECT_CALL(*download_item_, GetState()) + .WillRepeatedly(Return(content::DownloadItem::COMPLETE)); + EXPECT_CALL(*download_item_, IsDone()).WillRepeatedly(Return(true)); + download_item_->NotifyObserversDownloadUpdated(); + + // DownloadItem::OpenDownload must not be called since the file opens + // automatically due to the open-when-complete flag. +} + +TEST_F(DownloadNotificationItemTest, DownloadNotificationItemDelegate) { + // Shows a notification and checks OnDownloadStarted(). + EXPECT_EQ(0u, delegate_.GetOnDownloadStartedCallCount()); + CreateDownloadNotificationItem(); + EXPECT_EQ(1u, delegate_.GetOnDownloadStartedCallCount()); + + download_item_->NotifyObserversDownloadOpened(); + download_item_->NotifyObserversDownloadUpdated(); + + // Checks OnDownloadStopped(). + EXPECT_EQ(0u, delegate_.GetOnDownloadStoppedCallCount()); + EXPECT_CALL(*download_item_, GetState()) + .WillRepeatedly(Return(content::DownloadItem::COMPLETE)); + EXPECT_CALL(*download_item_, IsDone()).WillRepeatedly(Return(true)); + download_item_->NotifyObserversDownloadUpdated(); + EXPECT_EQ(1u, delegate_.GetOnDownloadStoppedCallCount()); + + // Checks OnDownloadRemoved(). + EXPECT_EQ(0u, delegate_.GetOnDownloadRemovedCallCount()); + download_item_->NotifyObserversDownloadRemoved(); + EXPECT_EQ(1u, delegate_.GetOnDownloadRemovedCallCount()); + + download_item_.reset(); +} + +} // namespace test
diff --git a/chrome/browser/download/notification/download_notification_manager.cc b/chrome/browser/download/notification/download_notification_manager.cc new file mode 100644 index 0000000..0727530 --- /dev/null +++ b/chrome/browser/download/notification/download_notification_manager.cc
@@ -0,0 +1,48 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/download/notification/download_notification_manager.h" + +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/download/download_item_model.h" +#include "chrome/browser/download/notification/download_notification_item.h" +#include "chrome/grit/chromium_strings.h" +#include "content/public/browser/download_item.h" +#include "grit/theme_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_delegate.h" + +using message_center::Notification; + +DownloadNotificationManager::DownloadNotificationManager(Profile* profile) + : items_deleter_(&items_) { +} + +DownloadNotificationManager::~DownloadNotificationManager() { +} + +void DownloadNotificationManager::OnDownloadStarted( + DownloadNotificationItem* item) { + downloading_items_.insert(item); +} + +void DownloadNotificationManager::OnDownloadStopped( + DownloadNotificationItem* item) { + downloading_items_.erase(item); +} + +void DownloadNotificationManager::OnDownloadRemoved( + DownloadNotificationItem* item) { + downloading_items_.erase(item); + items_.erase(item); +} + +void DownloadNotificationManager::OnNewDownloadReady( + content::DownloadItem* download) { + DownloadNotificationItem* item = new DownloadNotificationItem(download, this); + items_.insert(item); +}
diff --git a/chrome/browser/download/notification/download_notification_manager.h b/chrome/browser/download/notification/download_notification_manager.h new file mode 100644 index 0000000..0fade34 --- /dev/null +++ b/chrome/browser/download/notification/download_notification_manager.h
@@ -0,0 +1,37 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_DOWNLOAD_NOTIFICATION_DOWNLOAD_NOTIFICATION_MANAGER_H_ +#define CHROME_BROWSER_DOWNLOAD_NOTIFICATION_DOWNLOAD_NOTIFICATION_MANAGER_H_ + +#include <set> + +#include "chrome/browser/download/download_ui_controller.h" +#include "chrome/browser/download/notification/download_notification_item.h" +#include "chrome/browser/profiles/profile.h" + +class Profile; + +class DownloadNotificationManager : public DownloadUIController::Delegate, + public DownloadNotificationItem::Delegate { + public: + explicit DownloadNotificationManager(Profile* profile); + ~DownloadNotificationManager() override; + + // DownloadUIController::Delegate: + void OnNewDownloadReady(content::DownloadItem* item) override; + + // DownloadNotificationItem::Delegate: + void OnDownloadStarted(DownloadNotificationItem* item) override; + void OnDownloadStopped(DownloadNotificationItem* item) override; + void OnDownloadRemoved(DownloadNotificationItem* item) override; + + private: + std::set<DownloadNotificationItem*> downloading_items_; + std::set<DownloadNotificationItem*> items_; + + STLElementDeleter<std::set<DownloadNotificationItem*>> items_deleter_; +}; + +#endif // CHROME_BROWSER_DOWNLOAD_NOTIFICATION_DOWNLOAD_NOTIFICATION_MANAGER_H_
diff --git a/chrome/browser/drive/fake_drive_service.cc b/chrome/browser/drive/fake_drive_service.cc index f34c0d62..7f9b585b 100644 --- a/chrome/browser/drive/fake_drive_service.cc +++ b/chrome/browser/drive/fake_drive_service.cc
@@ -280,7 +280,7 @@ ReplaceSubstringsAfterOffset( &app_json, 0, "$Removable", is_removable ? "true" : "false"); - JSONStringValueSerializer json(app_json); + JSONStringValueDeserializer json(app_json); std::string error_message; scoped_ptr<base::Value> value(json.Deserialize(NULL, &error_message)); CHECK_EQ(base::Value::TYPE_DICTIONARY, value->GetType());
diff --git a/chrome/browser/errorpage_browsertest.cc b/chrome/browser/errorpage_browsertest.cc index 6c4708a..2ae8dbe 100644 --- a/chrome/browser/errorpage_browsertest.cc +++ b/chrome/browser/errorpage_browsertest.cc
@@ -941,7 +941,7 @@ EXPECT_EQ(2, interceptor()->requests()); ToggleHelpBox(browser()); - EXPECT_TRUE(IsDisplayingNetError(browser(), net::ERR_CONNECTION_RESET)); + EXPECT_TRUE(IsDisplayingText(browser(), "error.page.auto.reload")); content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); @@ -949,7 +949,7 @@ web_contents->GetMainFrame()->ExecuteJavaScript( base::ASCIIToUTF16("document.getElementById('reload-button').click();")); nav_observer.Wait(); - EXPECT_FALSE(IsDisplayingNetError(browser(), net::ERR_CONNECTION_RESET)); + EXPECT_FALSE(IsDisplayingText(browser(), "error.page.auto.reload")); } // Interceptor that fails all requests with net::ERR_ADDRESS_UNREACHABLE.
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc index 337f58e1f..9470e78 100644 --- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc +++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -96,6 +96,10 @@ "Cannot modify the extension by policy."; const char kRequiresUserGestureError[] = "This action requires a user gesture."; +const char kCouldNotShowSelectFileDialogError[] = + "Could not show a file chooser."; +const char kFileSelectionCanceled[] = + "File selection was canceled."; const char kUnpackedAppsFolder[] = "apps_target"; @@ -752,7 +756,9 @@ if (!extension) return RespondNow(Error(kNoSuchExtensionError)); - bool fail_quietly = params->options && params->options->fail_quietly; + bool fail_quietly = params->options && + params->options->fail_quietly && + *params->options->fail_quietly; ExtensionService* service = GetExtensionService(browser_context()); if (fail_quietly) @@ -867,67 +873,83 @@ DeveloperPrivateInspectFunction::~DeveloperPrivateInspectFunction() {} -bool DeveloperPrivateLoadUnpackedFunction::RunAsync() { - base::string16 select_title = - l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); +DeveloperPrivateLoadUnpackedFunction::DeveloperPrivateLoadUnpackedFunction() + : fail_quietly_(false) { +} - // Balanced in FileSelected / FileSelectionCanceled. - AddRef(); - bool result = ShowPicker( - ui::SelectFileDialog::SELECT_FOLDER, - DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(), - select_title, - ui::SelectFileDialog::FileTypeInfo(), - 0); - return result; +ExtensionFunction::ResponseAction DeveloperPrivateLoadUnpackedFunction::Run() { + scoped_ptr<developer_private::LoadUnpacked::Params> params( + developer_private::LoadUnpacked::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params); + + if (!ShowPicker( + ui::SelectFileDialog::SELECT_FOLDER, + l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY), + ui::SelectFileDialog::FileTypeInfo(), + 0 /* file_type_index */)) { + return RespondNow(Error(kCouldNotShowSelectFileDialogError)); + } + + fail_quietly_ = params->options && + params->options->fail_quietly && + *params->options->fail_quietly; + + AddRef(); // Balanced in FileSelected / FileSelectionCanceled. + return RespondLater(); } void DeveloperPrivateLoadUnpackedFunction::FileSelected( const base::FilePath& path) { - ExtensionService* service = GetExtensionService(GetProfile()); - UnpackedInstaller::Create(service)->Load(path); - DeveloperPrivateAPI::Get(GetProfile())->SetLastUnpackedDirectory(path); - SendResponse(true); - Release(); + scoped_refptr<UnpackedInstaller> installer( + UnpackedInstaller::Create(GetExtensionService(browser_context()))); + installer->set_be_noisy_on_failure(!fail_quietly_); + installer->set_completion_callback( + base::Bind(&DeveloperPrivateLoadUnpackedFunction::OnLoadComplete, this)); + installer->Load(path); + + DeveloperPrivateAPI::Get(browser_context())->SetLastUnpackedDirectory(path); + + Release(); // Balanced in Run(). } void DeveloperPrivateLoadUnpackedFunction::FileSelectionCanceled() { - SendResponse(false); - Release(); + // This isn't really an error, but we should keep it like this for + // backward compatability. + Respond(Error(kFileSelectionCanceled)); + Release(); // Balanced in Run(). +} + +void DeveloperPrivateLoadUnpackedFunction::OnLoadComplete( + const Extension* extension, + const base::FilePath& file_path, + const std::string& error) { + Respond(extension ? NoArguments() : Error(error)); } bool DeveloperPrivateChooseEntryFunction::ShowPicker( ui::SelectFileDialog::Type picker_type, - const base::FilePath& last_directory, const base::string16& select_title, const ui::SelectFileDialog::FileTypeInfo& info, int file_type_index) { - AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile()); - DCHECK(registry); - AppWindow* app_window = - registry->GetAppWindowForRenderViewHost(render_view_host()); - if (!app_window) { + content::WebContents* web_contents = GetSenderWebContents(); + if (!web_contents) return false; - } // The entry picker will hold a reference to this function instance, // and subsequent sending of the function response) until the user has // selected a file or cancelled the picker. At that point, the picker will // delete itself. new EntryPicker(this, - app_window->web_contents(), + web_contents, picker_type, - last_directory, + DeveloperPrivateAPI::Get(browser_context())-> + GetLastUnpackedDirectory(), select_title, info, file_type_index); return true; } -bool DeveloperPrivateChooseEntryFunction::RunAsync() { - return false; -} - DeveloperPrivateChooseEntryFunction::~DeveloperPrivateChooseEntryFunction() {} void DeveloperPrivatePackDirectoryFunction::OnPackSuccess( @@ -937,9 +959,8 @@ response.message = base::UTF16ToUTF8( PackExtensionJob::StandardSuccessMessage(crx_file, pem_file)); response.status = developer::PACK_STATUS_SUCCESS; - results_ = developer::PackDirectory::Results::Create(response); - SendResponse(true); - Release(); + Respond(OneArgument(response.ToValue().release())); + Release(); // Balanced in Run(). } void DeveloperPrivatePackDirectoryFunction::OnPackFailure( @@ -955,15 +976,14 @@ } else { response.status = developer::PACK_STATUS_ERROR; } - results_ = developer::PackDirectory::Results::Create(response); - SendResponse(true); - Release(); + Respond(OneArgument(response.ToValue().release())); + Release(); // Balanced in Run(). } -bool DeveloperPrivatePackDirectoryFunction::RunAsync() { +ExtensionFunction::ResponseAction DeveloperPrivatePackDirectoryFunction::Run() { scoped_ptr<PackDirectory::Params> params( PackDirectory::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get()); + EXTENSION_FUNCTION_VALIDATE(params); int flags = params->flags ? *params->flags : 0; item_path_str_ = params->path; @@ -972,7 +992,6 @@ base::FilePath root_directory = base::FilePath::FromUTF8Unsafe(item_path_str_); - base::FilePath key_file = base::FilePath::FromUTF8Unsafe(key_path_str_); developer::PackDirectoryResponse response; @@ -985,33 +1004,29 @@ IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID); response.status = developer::PACK_STATUS_ERROR; - results_ = developer::PackDirectory::Results::Create(response); - SendResponse(true); - return true; + return RespondNow(OneArgument(response.ToValue().release())); } if (!key_path_str_.empty() && key_file.empty()) { response.message = l10n_util::GetStringUTF8( IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID); response.status = developer::PACK_STATUS_ERROR; - results_ = developer::PackDirectory::Results::Create(response); - SendResponse(true); - return true; + return RespondNow(OneArgument(response.ToValue().release())); } - // Balanced in OnPackSuccess / OnPackFailure. - AddRef(); + AddRef(); // Balanced in OnPackSuccess / OnPackFailure. + // TODO(devlin): Why is PackExtensionJob ref-counted? pack_job_ = new PackExtensionJob(this, root_directory, key_file, flags); pack_job_->Start(); - return true; + return RespondLater(); } -DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction() -{} +DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction() { +} -DeveloperPrivatePackDirectoryFunction::~DeveloperPrivatePackDirectoryFunction() -{} +DeveloperPrivatePackDirectoryFunction:: +~DeveloperPrivatePackDirectoryFunction() {} DeveloperPrivateLoadUnpackedFunction::~DeveloperPrivateLoadUnpackedFunction() {} @@ -1246,16 +1261,16 @@ DeveloperPrivateLoadDirectoryFunction::~DeveloperPrivateLoadDirectoryFunction() {} -bool DeveloperPrivateChoosePathFunction::RunAsync() { +ExtensionFunction::ResponseAction DeveloperPrivateChoosePathFunction::Run() { scoped_ptr<developer::ChoosePath::Params> params( developer::ChoosePath::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); + EXTENSION_FUNCTION_VALIDATE(params); ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER; ui::SelectFileDialog::FileTypeInfo info; - if (params->select_type == developer::SELECT_TYPE_FILE) { + + if (params->select_type == developer::SELECT_TYPE_FILE) type = ui::SelectFileDialog::SELECT_OPEN_FILE; - } base::string16 select_title; int file_type_index = 0; @@ -1264,8 +1279,8 @@ } else if (params->file_type == developer::FILE_TYPE_PEM) { select_title = l10n_util::GetStringUTF16( IDS_EXTENSION_PACK_DIALOG_SELECT_KEY); - info.extensions.push_back(std::vector<base::FilePath::StringType>()); - info.extensions.front().push_back(FILE_PATH_LITERAL("pem")); + info.extensions.push_back(std::vector<base::FilePath::StringType>( + 1, FILE_PATH_LITERAL("pem"))); info.extension_description_overrides.push_back( l10n_util::GetStringUTF16( IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION)); @@ -1275,26 +1290,28 @@ NOTREACHED(); } - // Balanced by FileSelected / FileSelectionCanceled. - AddRef(); - bool result = ShowPicker( - type, - DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(), - select_title, - info, - file_type_index); - return result; + if (!ShowPicker( + type, + select_title, + info, + file_type_index)) { + return RespondNow(Error(kCouldNotShowSelectFileDialogError)); + } + + AddRef(); // Balanced by FileSelected / FileSelectionCanceled. + return RespondLater(); } void DeveloperPrivateChoosePathFunction::FileSelected( const base::FilePath& path) { - SetResult(new base::StringValue(base::UTF16ToUTF8(path.LossyDisplayName()))); - SendResponse(true); + Respond(OneArgument(new base::StringValue(path.LossyDisplayName()))); Release(); } void DeveloperPrivateChoosePathFunction::FileSelectionCanceled() { - SendResponse(false); + // This isn't really an error, but we should keep it like this for + // backward compatability. + Respond(Error(kFileSelectionCanceled)); Release(); }
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h index 2164d14..cf95fc17 100644 --- a/chrome/browser/extensions/api/developer_private/developer_private_api.h +++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -296,20 +296,14 @@ std::string extension_id_; }; -class DeveloperPrivateChooseEntryFunction : public ChromeAsyncExtensionFunction, +class DeveloperPrivateChooseEntryFunction : public UIThreadExtensionFunction, public EntryPickerClient { protected: ~DeveloperPrivateChooseEntryFunction() override; - bool RunAsync() override; bool ShowPicker(ui::SelectFileDialog::Type picker_type, - const base::FilePath& last_directory, const base::string16& select_title, const ui::SelectFileDialog::FileTypeInfo& info, int file_type_index); - - // EntryPickerClient functions. - void FileSelected(const base::FilePath& path) override = 0; - void FileSelectionCanceled() override = 0; }; @@ -318,14 +312,24 @@ public: DECLARE_EXTENSION_FUNCTION("developerPrivate.loadUnpacked", DEVELOPERPRIVATE_LOADUNPACKED); + DeveloperPrivateLoadUnpackedFunction(); protected: ~DeveloperPrivateLoadUnpackedFunction() override; - bool RunAsync() override; + ResponseAction Run() override; - // EntryPickerCLient implementation. + // EntryPickerClient: void FileSelected(const base::FilePath& path) override; void FileSelectionCanceled() override; + + // Callback for the UnpackedLoader. + void OnLoadComplete(const Extension* extension, + const base::FilePath& file_path, + const std::string& error); + + private: + // Whether or not we should fail quietly in the event of a load error. + bool fail_quietly_; }; class DeveloperPrivateChoosePathFunction @@ -336,15 +340,15 @@ protected: ~DeveloperPrivateChoosePathFunction() override; - bool RunAsync() override; + ResponseAction Run() override; - // EntryPickerClient functions. + // EntryPickerClient: void FileSelected(const base::FilePath& path) override; void FileSelectionCanceled() override; }; class DeveloperPrivatePackDirectoryFunction - : public ChromeAsyncExtensionFunction, + : public DeveloperPrivateAPIFunction, public PackExtensionJob::Client { public: @@ -361,7 +365,7 @@ protected: ~DeveloperPrivatePackDirectoryFunction() override; - bool RunAsync() override; + ResponseAction Run() override; private: scoped_refptr<PackExtensionJob> pack_job_;
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc index 59bac37..b7d90d2 100644 --- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc +++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -9,20 +9,32 @@ #include "chrome/browser/extensions/extension_service_test_base.h" #include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/extensions/test_extension_dir.h" +#include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/extensions/unpacked_installer.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/host_desktop.h" +#include "chrome/common/extensions/api/developer_private.h" #include "chrome/test/base/test_browser_window.h" +#include "content/public/test/test_web_contents_factory.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/extension.h" #include "extensions/common/extension_set.h" +#include "extensions/common/manifest_constants.h" #include "extensions/common/test_util.h" namespace extensions { +namespace { + +KeyedService* BuildAPI(content::BrowserContext* context) { + return new DeveloperPrivateAPI(context); +} + +} // namespace + class DeveloperPrivateApiUnitTest : public ExtensionServiceTestBase { protected: DeveloperPrivateApiUnitTest() {} @@ -43,6 +55,11 @@ void TestExtensionPrefSetting( bool (*has_pref)(const std::string&, content::BrowserContext*)); + testing::AssertionResult TestPackExtensionFunction( + const base::ListValue& args, + api::developer_private::PackStatus expected_status, + int expected_flags); + Browser* browser() { return browser_.get(); } private: @@ -134,6 +151,37 @@ EXPECT_FALSE(has_pref(extension_id, profile())); } +testing::AssertionResult DeveloperPrivateApiUnitTest::TestPackExtensionFunction( + const base::ListValue& args, + api::developer_private::PackStatus expected_status, + int expected_flags) { + scoped_refptr<UIThreadExtensionFunction> function( + new api::DeveloperPrivatePackDirectoryFunction()); + if (!RunFunction(function, args)) + return testing::AssertionFailure() << "Could not run function."; + + // Extract the result. We don't have to test this here, since it's verified as + // part of the general extension api system. + const base::Value* response_value = nullptr; + CHECK(function->GetResultList()->Get(0u, &response_value)); + scoped_ptr<api::developer_private::PackDirectoryResponse> response = + api::developer_private::PackDirectoryResponse::FromValue(*response_value); + CHECK(response); + + if (response->status != expected_status) { + return testing::AssertionFailure() << "Expected status: " << + expected_status << ", found status: " << response->status << + ", message: " << response->message; + } + + if (response->override_flags != expected_flags) { + return testing::AssertionFailure() << "Expected flags: " << + expected_flags << ", found flags: " << response->override_flags; + } + + return testing::AssertionSuccess(); +} + void DeveloperPrivateApiUnitTest::SetUp() { ExtensionServiceTestBase::SetUp(); InitializeEmptyExtensionService(); @@ -143,6 +191,13 @@ params.type = Browser::TYPE_TABBED; params.window = browser_window_.get(); browser_.reset(new Browser(params)); + + // Allow the API to be created. + static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile()))-> + SetEventRouter(make_scoped_ptr( + new EventRouter(profile(), ExtensionPrefs::Get(profile())))); + DeveloperPrivateAPI::GetFactoryInstance()->SetTestingFactory( + profile(), &BuildAPI); } void DeveloperPrivateApiUnitTest::TearDown() { @@ -183,4 +238,138 @@ &util::AllowFileAccess); } +// Test developerPrivate.packDirectory. +TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivatePackFunction) { + ResetThreadBundle(content::TestBrowserThreadBundle::DEFAULT); + + base::FilePath root_path = data_dir().AppendASCII("good_unpacked"); + base::FilePath crx_path = data_dir().AppendASCII("good_unpacked.crx"); + base::FilePath pem_path = data_dir().AppendASCII("good_unpacked.pem"); + + // First, test a directory that should pack properly. + base::ListValue pack_args; + pack_args.AppendString(root_path.AsUTF8Unsafe()); + EXPECT_TRUE(TestPackExtensionFunction( + pack_args, api::developer_private::PACK_STATUS_SUCCESS, 0)); + + // Should have created crx file and pem file. + EXPECT_TRUE(base::PathExists(crx_path)); + EXPECT_TRUE(base::PathExists(pem_path)); + + // Deliberately don't cleanup the files, and append the pem path. + pack_args.AppendString(pem_path.AsUTF8Unsafe()); + + // Try to pack again - we should get a warning abot overwriting the crx. + EXPECT_TRUE(TestPackExtensionFunction( + pack_args, + api::developer_private::PACK_STATUS_WARNING, + ExtensionCreator::kOverwriteCRX)); + + // Try to pack again, with the overwrite flag; this should succeed. + pack_args.AppendInteger(ExtensionCreator::kOverwriteCRX); + EXPECT_TRUE(TestPackExtensionFunction( + pack_args, api::developer_private::PACK_STATUS_SUCCESS, 0)); + + // Try to pack a final time when omitting (an existing) pem file. We should + // get an error. + base::DeleteFile(crx_path, false); + EXPECT_TRUE(pack_args.Remove(1u, nullptr)); // Remove the pem key argument. + EXPECT_TRUE(pack_args.Remove(1u, nullptr)); // Remove the flags argument. + EXPECT_TRUE(TestPackExtensionFunction( + pack_args, api::developer_private::PACK_STATUS_ERROR, 0)); + + base::DeleteFile(crx_path, false); + base::DeleteFile(pem_path, false); +} + +// Test developerPrivate.choosePath. +TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateChoosePath) { + ResetThreadBundle(content::TestBrowserThreadBundle::DEFAULT); + content::TestWebContentsFactory web_contents_factory; + content::WebContents* web_contents = + web_contents_factory.CreateWebContents(profile()); + + base::FilePath expected_dir_path = data_dir().AppendASCII("good_unpacked"); + api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&expected_dir_path); + + // Try selecting a directory. + base::ListValue choose_args; + choose_args.AppendString("FOLDER"); + choose_args.AppendString("LOAD"); + scoped_refptr<UIThreadExtensionFunction> function( + new api::DeveloperPrivateChoosePathFunction()); + function->SetRenderViewHost(web_contents->GetRenderViewHost()); + EXPECT_TRUE(RunFunction(function, choose_args)) << function->GetError(); + std::string path; + EXPECT_TRUE(function->GetResultList() && + function->GetResultList()->GetString(0, &path)); + EXPECT_EQ(path, expected_dir_path.AsUTF8Unsafe()); + + // Try selecting a pem file. + base::FilePath expected_file_path = + data_dir().AppendASCII("good_unpacked.pem"); + api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&expected_file_path); + choose_args.Clear(); + choose_args.AppendString("FILE"); + choose_args.AppendString("PEM"); + function = new api::DeveloperPrivateChoosePathFunction(); + function->SetRenderViewHost(web_contents->GetRenderViewHost()); + EXPECT_TRUE(RunFunction(function, choose_args)) << function->GetError(); + EXPECT_TRUE(function->GetResultList() && + function->GetResultList()->GetString(0, &path)); + EXPECT_EQ(path, expected_file_path.AsUTF8Unsafe()); + + // Try canceling the file dialog. + api::EntryPicker::SkipPickerAndAlwaysCancelForTest(); + function = new api::DeveloperPrivateChoosePathFunction(); + function->SetRenderViewHost(web_contents->GetRenderViewHost()); + EXPECT_FALSE(RunFunction(function, choose_args)); + EXPECT_EQ(std::string("File selection was canceled."), function->GetError()); +} + +// Test developerPrivate.loadUnpacked. +TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateLoadUnpacked) { + ResetThreadBundle(content::TestBrowserThreadBundle::DEFAULT); + content::TestWebContentsFactory web_contents_factory; + content::WebContents* web_contents = + web_contents_factory.CreateWebContents(profile()); + + base::FilePath path = data_dir().AppendASCII("good_unpacked"); + api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&path); + + // Try loading a good extension (it should succeed, and the extension should + // be added). + scoped_refptr<UIThreadExtensionFunction> function( + new api::DeveloperPrivateLoadUnpackedFunction()); + function->SetRenderViewHost(web_contents->GetRenderViewHost()); + ExtensionIdSet current_ids = registry()->enabled_extensions().GetIDs(); + EXPECT_TRUE(RunFunction(function, base::ListValue())) << function->GetError(); + // We should have added one new extension. + ExtensionIdSet id_difference = base::STLSetDifference<ExtensionIdSet>( + registry()->enabled_extensions().GetIDs(), current_ids); + ASSERT_EQ(1u, id_difference.size()); + // The new extension should have the same path. + EXPECT_EQ( + path, + registry()->enabled_extensions().GetByID(*id_difference.begin())->path()); + + path = data_dir().AppendASCII("empty_manifest"); + api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&path); + + // Try loading a bad extension (it should fail, and we should get an error). + function = new api::DeveloperPrivateLoadUnpackedFunction(); + function->SetRenderViewHost(web_contents->GetRenderViewHost()); + base::ListValue unpacked_args; + scoped_ptr<base::DictionaryValue> options(new base::DictionaryValue()); + options->SetBoolean("failQuietly", true); + unpacked_args.Append(options.release()); + current_ids = registry()->enabled_extensions().GetIDs(); + EXPECT_FALSE(RunFunction(function, unpacked_args)); + EXPECT_EQ(manifest_errors::kManifestUnreadable, function->GetError()); + // We should have no new extensions installed. + EXPECT_EQ(0u, base::STLSetDifference<ExtensionIdSet>( + registry()->enabled_extensions().GetIDs(), + current_ids).size()); +} + } // namespace extensions
diff --git a/chrome/browser/extensions/api/developer_private/entry_picker.cc b/chrome/browser/extensions/api/developer_private/entry_picker.cc index 9e3b6af..65d5638f 100644 --- a/chrome/browser/extensions/api/developer_private/entry_picker.cc +++ b/chrome/browser/extensions/api/developer_private/entry_picker.cc
@@ -32,29 +32,29 @@ const ui::SelectFileDialog::FileTypeInfo& info, int file_type_index) : client_(client) { - select_file_dialog_ = ui::SelectFileDialog::Create( - this, new ChromeSelectFilePolicy(web_contents)); - - gfx::NativeWindow owning_window = web_contents ? - platform_util::GetTopLevel(web_contents->GetNativeView()) : - NULL; - if (g_skip_picker_for_test) { if (g_path_to_be_picked_for_test) { content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, base::Bind( &EntryPicker::FileSelected, base::Unretained(this), *g_path_to_be_picked_for_test, 1, - static_cast<void*>(NULL))); + static_cast<void*>(nullptr))); } else { content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, base::Bind( &EntryPicker::FileSelectionCanceled, - base::Unretained(this), static_cast<void*>(NULL))); + base::Unretained(this), static_cast<void*>(nullptr))); } return; } + select_file_dialog_ = ui::SelectFileDialog::Create( + this, new ChromeSelectFilePolicy(web_contents)); + + gfx::NativeWindow owning_window = web_contents ? + platform_util::GetTopLevel(web_contents->GetNativeView()) : + nullptr; + select_file_dialog_->SelectFile(picker_type, select_title, last_directory, @@ -62,7 +62,7 @@ file_type_index, base::FilePath::StringType(), owning_window, - NULL); + nullptr); } EntryPicker::~EntryPicker() {} @@ -79,6 +79,13 @@ delete this; } +void EntryPicker::MultiFilesSelected(const std::vector<base::FilePath>& files, + void* params) { + NOTREACHED(); + client_->FileSelectionCanceled(); + delete this; +} + // static void EntryPicker::SkipPickerAndAlwaysSelectPathForTest( base::FilePath* path) {
diff --git a/chrome/browser/extensions/api/developer_private/entry_picker.h b/chrome/browser/extensions/api/developer_private/entry_picker.h index 5fafbc64..da4421c 100644 --- a/chrome/browser/extensions/api/developer_private/entry_picker.h +++ b/chrome/browser/extensions/api/developer_private/entry_picker.h
@@ -42,12 +42,13 @@ ~EntryPicker() override; private: - // ui::SelectFileDialog::Listener implementation. + // ui::SelectFileDialog::Listener: void FileSelected(const base::FilePath& path, int index, void* params) override; - void FileSelectionCanceled(void* params) override; + void MultiFilesSelected(const std::vector<base::FilePath>& files, + void* params) override; scoped_refptr<ui::SelectFileDialog> select_file_dialog_; EntryPickerClient* client_;
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.cc b/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.cc index 5366620..8479b13 100644 --- a/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.cc +++ b/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.cc
@@ -43,8 +43,8 @@ std::string* error_message) { DCHECK(error_message); - JSONFileValueSerializer serializer(file_path); - scoped_ptr<base::Value> parsed(serializer.Deserialize(NULL, error_message)); + JSONFileValueDeserializer deserializer(file_path); + scoped_ptr<base::Value> parsed(deserializer.Deserialize(NULL, error_message)); if (!parsed) { return scoped_ptr<NativeMessagingHostManifest>(); }
diff --git a/chrome/browser/extensions/api/permissions/permissions_api.cc b/chrome/browser/extensions/api/permissions/permissions_api.cc index 86f4aa9ac..d7346ec 100644 --- a/chrome/browser/extensions/api/permissions/permissions_api.cc +++ b/chrome/browser/extensions/api/permissions/permissions_api.cc
@@ -208,6 +208,11 @@ requested_permissions_ = PermissionSet::CreateDifference( requested_permissions_.get(), granted.get()); + // Filter out the active permissions. + requested_permissions_ = PermissionSet::CreateDifference( + requested_permissions_.get(), + extension()->permissions_data()->active_permissions().get()); + AddRef(); // Balanced in InstallUIProceed() / InstallUIAbort(). // We don't need to show the prompt if there are no new warnings, or if
diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc index 86d48df..5830c48 100644 --- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc +++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
@@ -55,7 +55,7 @@ #include "extensions/browser/api/bluetooth/bluetooth_private_api.h" #include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h" #include "extensions/browser/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h" -#include "extensions/browser/api/power/power_api_manager.h" +#include "extensions/browser/api/power/power_api.h" #include "extensions/browser/api/usb/usb_device_resource.h" #include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_private_api.h" #include "extensions/browser/api/web_request/web_request_api.h" @@ -121,7 +121,7 @@ #if defined(ENABLE_PLUGINS) extensions::PluginManager::GetFactoryInstance(); #endif // defined(ENABLE_PLUGINS) - extensions::PowerApiManager::GetFactoryInstance(); + extensions::PowerAPI::GetFactoryInstance(); extensions::PreferenceAPI::GetFactoryInstance(); extensions::ProcessesAPI::GetFactoryInstance(); extensions::PushMessagingAPI::GetFactoryInstance();
diff --git a/chrome/browser/extensions/chrome_info_map_unittest.cc b/chrome/browser/extensions/chrome_info_map_unittest.cc index 4a3eb1c..5ee4a1f6 100644 --- a/chrome/browser/extensions/chrome_info_map_unittest.cc +++ b/chrome/browser/extensions/chrome_info_map_unittest.cc
@@ -24,8 +24,8 @@ PathService::Get(chrome::DIR_TEST_DATA, &path); path = path.AppendASCII("extensions").AppendASCII(dir).AppendASCII(test_file); - JSONFileValueSerializer serializer(path); - scoped_ptr<base::Value> result(serializer.Deserialize(NULL, NULL)); + JSONFileValueDeserializer deserializer(path); + scoped_ptr<base::Value> result(deserializer.Deserialize(NULL, NULL)); if (!result) return NULL;
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc index 3c40959..ed34824 100644 --- a/chrome/browser/extensions/component_loader.cc +++ b/chrome/browser/extensions/component_loader.cc
@@ -144,8 +144,8 @@ base::DictionaryValue* ComponentLoader::ParseManifest( const std::string& manifest_contents) const { - JSONStringValueSerializer serializer(manifest_contents); - scoped_ptr<base::Value> manifest(serializer.Deserialize(NULL, NULL)); + JSONStringValueDeserializer deserializer(manifest_contents); + scoped_ptr<base::Value> manifest(deserializer.Deserialize(NULL, NULL)); if (!manifest.get() || !manifest->IsType(base::Value::TYPE_DICTIONARY)) { LOG(ERROR) << "Failed to parse extension manifest.";
diff --git a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc index 4292ed4..3d45e15 100644 --- a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc +++ b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
@@ -107,10 +107,12 @@ test_file = test_file.AppendASCII("extensions/api_test").AppendASCII(name); int error_code = 0; std::string error; - JSONFileValueSerializer serializer(test_file.AppendASCII("manifest.json")); + JSONFileValueDeserializer deserializer( + test_file.AppendASCII("manifest.json")); scoped_ptr<base::DictionaryValue> valid_value( - static_cast<base::DictionaryValue*>(serializer.Deserialize(&error_code, - &error))); + static_cast<base::DictionaryValue*>( + deserializer.Deserialize(&error_code, + &error))); EXPECT_EQ(0, error_code) << error; if (error_code != 0) return NULL;
diff --git a/chrome/browser/extensions/extension_bindings_apitest.cc b/chrome/browser/extensions/extension_bindings_apitest.cc index ca0f4d4..c78fb200 100644 --- a/chrome/browser/extensions/extension_bindings_apitest.cc +++ b/chrome/browser/extensions/extension_bindings_apitest.cc
@@ -92,5 +92,9 @@ << message_; } +IN_PROC_BROWSER_TEST_F(ExtensionBindingsApiTest, ApiEnums) { + ASSERT_TRUE(RunExtensionTest("bindings/api_enums")) << message_; +}; + } // namespace } // namespace extensions
diff --git a/chrome/browser/extensions/extension_icon_manager_unittest.cc b/chrome/browser/extensions/extension_icon_manager_unittest.cc index 36dbf5a6..004c196 100644 --- a/chrome/browser/extensions/extension_icon_manager_unittest.cc +++ b/chrome/browser/extensions/extension_icon_manager_unittest.cc
@@ -108,9 +108,10 @@ base::FilePath manifest_path = test_dir.AppendASCII( "extensions/image_loading_tracker/app.json"); - JSONFileValueSerializer serializer(manifest_path); + JSONFileValueDeserializer deserializer(manifest_path); scoped_ptr<base::DictionaryValue> manifest( - static_cast<base::DictionaryValue*>(serializer.Deserialize(NULL, NULL))); + static_cast<base::DictionaryValue*>(deserializer.Deserialize(NULL, + NULL))); ASSERT_TRUE(manifest.get() != NULL); std::string error; @@ -150,9 +151,10 @@ base::FilePath manifest_path = test_dir.AppendASCII( "extensions/file_manager/app.json"); - JSONFileValueSerializer serializer(manifest_path); + JSONFileValueDeserializer deserializer(manifest_path); scoped_ptr<base::DictionaryValue> manifest( - static_cast<base::DictionaryValue*>(serializer.Deserialize(NULL, NULL))); + static_cast<base::DictionaryValue*>(deserializer.Deserialize(NULL, + NULL))); ASSERT_TRUE(manifest.get() != NULL); std::string error;
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc index 00146cf..45047b8 100644 --- a/chrome/browser/extensions/extension_install_prompt.cc +++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -36,6 +36,7 @@ #include "extensions/common/manifest.h" #include "extensions/common/manifest_constants.h" #include "extensions/common/manifest_handlers/icons_handler.h" +#include "extensions/common/manifest_handlers/permissions_parser.h" #include "extensions/common/permissions/permission_message_provider.h" #include "extensions/common/permissions/permission_set.h" #include "extensions/common/permissions/permissions_data.h" @@ -924,6 +925,15 @@ .InitializePermissions(extension_); permissions_to_display = extension_->permissions_data()->active_permissions(); + // For delegated installs, all optional permissions are pre-approved by the + // person who triggers the install, so add them to the list. + if (prompt_->type() == DELEGATED_PERMISSIONS_PROMPT) { + scoped_refptr<const PermissionSet> optional_permissions = + extensions::PermissionsParser::GetOptionalPermissions(extension_); + permissions_to_display = PermissionSet::CreateUnion( + permissions_to_display.get(), + optional_permissions.get()); + } } if (permissions_to_display.get() &&
diff --git a/chrome/browser/extensions/extension_install_prompt_unittest.cc b/chrome/browser/extensions/extension_install_prompt_unittest.cc index 75967df..e1a671c 100644 --- a/chrome/browser/extensions/extension_install_prompt_unittest.cc +++ b/chrome/browser/extensions/extension_install_prompt_unittest.cc
@@ -53,14 +53,14 @@ .Set("version", "1.0") .Set("manifest_version", 2) .Set("description", "Random Ext")).Build(); - ExtensionInstallPrompt prompt(NULL /* no web contents in this test */); + ExtensionInstallPrompt prompt(nullptr /* no web contents in this test */); base::RunLoop run_loop; prompt.set_callback_for_test( base::Bind(&VerifyPromptPermissionsCallback, run_loop.QuitClosure(), 1u, // |regular_permissions_count|. 0u)); // |withheld_permissions_count|. - prompt.ConfirmPermissions(NULL, // no delegate + prompt.ConfirmPermissions(nullptr, // no delegate extension.get(), permission_set.get()); run_loop.Run(); @@ -73,24 +73,24 @@ FeatureSwitch::ScopedOverride enable_scripts_switch( FeatureSwitch::scripts_require_action(), true); - ListBuilder permissions; - permissions.Append("http://*/*"); - permissions.Append("http://www.google.com/"); - permissions.Append("tabs"); scoped_refptr<const Extension> extension = ExtensionBuilder().SetManifest( DictionaryBuilder().Set("name", "foo") .Set("version", "1.0") .Set("manifest_version", 2) .Set("description", "Random Ext") - .Set("permissions", permissions)).Build(); - ExtensionInstallPrompt prompt(NULL /* no web contents in this test */); + .Set("permissions", + ListBuilder().Append("http://*/*") + .Append("http://www.google.com/") + .Append("tabs"))) + .Build(); + ExtensionInstallPrompt prompt(nullptr /* no web contents in this test */); base::RunLoop run_loop; // We expect <all_hosts> to be withheld, but http://www.google.com/ and tabs // permissions should be granted as regular permissions. prompt.ConfirmInstall( - NULL, + nullptr, extension.get(), base::Bind(&VerifyPromptPermissionsCallback, run_loop.QuitClosure(), @@ -99,4 +99,30 @@ run_loop.Run(); } +TEST(ExtensionInstallPromptUnittest, DelegatedPromptShowsOptionalPermissions) { + content::TestBrowserThreadBundle thread_bundle; + scoped_refptr<const Extension> extension = + ExtensionBuilder().SetManifest( + DictionaryBuilder().Set("name", "foo") + .Set("version", "1.0") + .Set("manifest_version", 2) + .Set("description", "Random Ext") + .Set("permissions", ListBuilder().Append("tabs")) + .Set("optional_permissions", + ListBuilder().Append("location"))) + .Build(); + ExtensionInstallPrompt prompt(nullptr /* no web contents in this test */); + base::RunLoop run_loop; + prompt.set_callback_for_test( + base::Bind(&VerifyPromptPermissionsCallback, + run_loop.QuitClosure(), + 2u, // |regular_permissions_count|. + 0u)); // |withheld_permissions_count|. + prompt.ConfirmPermissionsForDelegatedInstall(nullptr, // no delegate + extension.get(), + "Username", + nullptr); // no icon + run_loop.Run(); +} + } // namespace extensions
diff --git a/chrome/browser/extensions/extension_management.cc b/chrome/browser/extensions/extension_management.cc index e9b922f..4d3adbc 100644 --- a/chrome/browser/extensions/extension_management.cc +++ b/chrome/browser/extensions/extension_management.cc
@@ -9,9 +9,11 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/logging.h" +#include "base/metrics/histogram_macros.h" #include "base/prefs/pref_service.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" +#include "base/trace_event/trace_event.h" #include "base/version.h" #include "chrome/browser/extensions/extension_management_constants.h" #include "chrome/browser/extensions/extension_management_internal.h" @@ -35,6 +37,8 @@ ExtensionManagement::ExtensionManagement(PrefService* pref_service) : pref_service_(pref_service) { + TRACE_EVENT0("browser,startup", + "ExtensionManagement::ExtensionManagement::ctor"); pref_change_registrar_.Init(pref_service_); base::Closure pref_change_callback = base::Bind( &ExtensionManagement::OnExtensionPrefChanged, base::Unretained(this)); @@ -234,6 +238,8 @@ } void ExtensionManagement::Refresh() { + TRACE_EVENT0("browser,startup", "ExtensionManagement::Refresh"); + SCOPED_UMA_HISTOGRAM_TIMER("Extensions.ExtensionManagement_RefreshTime"); // Load all extension management settings preferences. const base::ListValue* allowed_list_pref = static_cast<const base::ListValue*>(LoadPreference( @@ -474,6 +480,8 @@ KeyedService* ExtensionManagementFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { + TRACE_EVENT0("browser,startup", + "ExtensionManagementFactory::BuildServiceInstanceFor"); return new ExtensionManagement( Profile::FromBrowserContext(context)->GetPrefs()); }
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 3708493..97ea32e 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc
@@ -84,6 +84,11 @@ #include "extensions/common/permissions/permission_message_provider.h" #include "extensions/common/permissions/permissions_data.h" +#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 + #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/extensions/install_limiter.h" #include "storage/browser/fileapi/file_system_backend.h" @@ -110,13 +115,18 @@ using extensions::SharedModuleService; using extensions::UnloadedExtensionInfo; -namespace errors = extensions::manifest_errors; - namespace { // Wait this many seconds after an extensions becomes idle before updating it. const int kUpdateIdleDelay = 5; +#if defined(ENABLE_SUPERVISED_USERS) +// Callback for SupervisedUserService::AddExtensionUpdateRequest. +void ExtensionUpdateRequestSent(const std::string& id, bool success) { + LOG_IF(WARNING, !success) << "Failed sending update request for " << id; +} +#endif + } // namespace // ExtensionService. @@ -276,6 +286,7 @@ shared_module_service_(new extensions::SharedModuleService(profile_)), app_data_migrator_(new extensions::AppDataMigrator(profile_, registry_)) { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + TRACE_EVENT0("browser,startup", "ExtensionService::ExtensionService::ctor"); // Figure out if extension installation should be enabled. if (extensions::ExtensionsBrowserClient::Get()->AreExtensionsDisabled( @@ -298,7 +309,7 @@ extensions::ExtensionManagementFactory::GetForBrowserContext(profile_) ->AddObserver(this); - // Set up the ExtensionUpdater + // Set up the ExtensionUpdater. if (autoupdate_enabled) { int update_frequency = extensions::kDefaultUpdateFrequencySeconds; if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) { @@ -1660,6 +1671,19 @@ } extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED); extension_prefs_->SetDidExtensionEscalatePermissions(extension, true); + +#if defined(ENABLE_SUPERVISED_USERS) + // If a custodian-installed extension is disabled for a supervised user due + // to a permissions increase, send a request to the custodian, since the + // supervised user itself can't re-enable the extension. + if (extensions::util::IsExtensionSupervised(extension, profile_)) { + SupervisedUserService* supervised_user_service = + SupervisedUserServiceFactory::GetForProfile(profile_); + supervised_user_service->AddExtensionUpdateRequest( + extension->id(), + base::Bind(ExtensionUpdateRequestSent, extension->id())); + } +#endif } if (disable_reasons != Extension::DISABLE_NONE) { extension_prefs_->AddDisableReason( @@ -2108,7 +2132,8 @@ const base::FilePath& path, Manifest::Location location, int creation_flags, - bool mark_acknowledged) { + bool mark_acknowledged, + bool install_immediately) { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); CHECK(crx_file::id_util::IdIsValid(id)); if (extension_prefs_->IsExternalExtensionUninstalled(id)) @@ -2159,6 +2184,7 @@ installer->set_expected_id(id); installer->set_expected_version(*version); installer->set_install_cause(extension_misc::INSTALL_CAUSE_EXTERNAL_FILE); + installer->set_install_immediately(install_immediately); installer->set_creation_flags(creation_flags); #if defined(OS_CHROMEOS) extensions::InstallLimiter::Get(profile_)->Add(installer, path);
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index cc5f7ae..04d0f4ed 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h
@@ -232,7 +232,8 @@ const base::FilePath& path, extensions::Manifest::Location location, int creation_flags, - bool mark_acknowledged) override; + bool mark_acknowledged, + bool install_immediately) override; bool OnExternalExtensionUpdateUrlFound( const std::string& id, const std::string& install_parameter,
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index 0e9e757..39d6514d 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -134,6 +134,7 @@ #include "url/gurl.h" #if defined(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/supervised_user/permission_request_creator.h" #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" #endif @@ -270,7 +271,7 @@ visitor_->OnExternalExtensionFileFound( i->first, &version, i->second.second, location_, - Extension::NO_FLAGS, false); + Extension::NO_FLAGS, false, false); } visitor_->OnExternalProviderReady(this); } @@ -352,8 +353,8 @@ // We also parse the file into a dictionary to compare what we get back // from the provider. - JSONStringValueSerializer serializer(json_data); - base::Value* json_value = serializer.Deserialize(NULL, NULL); + JSONStringValueDeserializer deserializer(json_data); + base::Value* json_value = deserializer.Deserialize(NULL, NULL); if (!json_value || !json_value->IsType(base::Value::TYPE_DICTIONARY)) { NOTREACHED() << "Unable to deserialize json data"; @@ -377,7 +378,8 @@ const base::FilePath& path, Manifest::Location unused, int creation_flags, - bool mark_acknowledged) override { + bool mark_acknowledged, + bool install_immediately) override { EXPECT_EQ(expected_creation_flags_, creation_flags); ++ids_found_; @@ -1564,12 +1566,14 @@ content::WindowedNotificationObserver observer( extensions::NOTIFICATION_CRX_INSTALLER_DONE, content::NotificationService::AllSources()); - if (service()->OnExternalExtensionFileFound(good_crx, - &version, - path, - Manifest::EXTERNAL_PREF, - Extension::FROM_BOOKMARK, - false /* mark_acknowledged */)) { + if (service()->OnExternalExtensionFileFound( + good_crx, + &version, + path, + Manifest::EXTERNAL_PREF, + Extension::FROM_BOOKMARK, + false /* mark_acknowledged */, + false /* install_immediately */)) { observer.Wait(); } @@ -1604,6 +1608,7 @@ path, Manifest::EXTERNAL_PREF, Extension::NO_FLAGS, + false, false)) { observer.Wait(); } @@ -1621,6 +1626,7 @@ path, Manifest::EXTERNAL_PREF, Extension::NO_FLAGS, + false, false); base::RunLoop().RunUntilIdle(); ASSERT_TRUE(NULL == service()->GetExtensionById(good_crx, false)); @@ -1635,6 +1641,7 @@ path, Manifest::EXTERNAL_PREF, Extension::NO_FLAGS, + false, false); base::RunLoop().RunUntilIdle(); ASSERT_TRUE(NULL == service()->GetExtensionById(good_crx, false)); @@ -1702,6 +1709,7 @@ path, Manifest::EXTERNAL_PREF, Extension::NO_FLAGS, + false, false); observer.Wait(); @@ -1716,6 +1724,7 @@ path, Manifest::EXTERNAL_PREF, Extension::NO_FLAGS, + false, false)) { observer2.Wait(); } @@ -1739,6 +1748,7 @@ path, Manifest::EXTERNAL_PREF, Extension::NO_FLAGS, + false, false); observer.Wait(); @@ -1755,6 +1765,7 @@ path, Manifest::EXTERNAL_PREF, Extension::NO_FLAGS, + false, false)) { observer2.Wait(); } @@ -6599,6 +6610,26 @@ } #if defined(ENABLE_SUPERVISED_USERS) +class MockPermissionRequestCreator : public PermissionRequestCreator { + public: + MockPermissionRequestCreator() {} + ~MockPermissionRequestCreator() override {} + + bool IsEnabled() const override { return true; } + + void CreateURLAccessRequest(const GURL& url_requested, + const SuccessCallback& callback) override { + FAIL(); + } + + MOCK_METHOD2(CreateExtensionUpdateRequest, + void(const std::string& extension_id, + const SupervisedUserService::SuccessCallback& callback)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockPermissionRequestCreator); +}; + TEST_F(ExtensionServiceTest, SupervisedUser_InstallOnlyAllowedByCustodian) { ExtensionServiceInitParams params = CreateDefaultInitParams(); params.profile_is_supervised = true; @@ -6666,6 +6697,9 @@ SupervisedUserService* supervised_user_service = SupervisedUserServiceFactory::GetForProfile(profile()); GetManagementPolicy()->RegisterProvider(supervised_user_service); + MockPermissionRequestCreator* creator = new MockPermissionRequestCreator; + supervised_user_service->AddPermissionRequestCreator( + make_scoped_ptr(creator)); base::FilePath base_path = data_dir().AppendASCII("permissions_increase"); base::FilePath pem_path = base_path.AppendASCII("permissions.pem"); @@ -6684,6 +6718,7 @@ std::string old_version = extension->VersionString(); // Update to a new version with increased permissions. + EXPECT_CALL(*creator, CreateExtensionUpdateRequest(id, testing::_)); path = base_path.AppendASCII("v2"); PackCRXAndUpdateExtension(id, path, pem_path, DISABLED); @@ -6825,6 +6860,7 @@ const int kCreationFlags = 0; const bool kDontMarkAcknowledged = false; + const bool kDontInstallImmediately = false; InitializeEmptyExtensionService(); @@ -6852,12 +6888,14 @@ content::WindowedNotificationObserver observer( extensions::NOTIFICATION_CRX_INSTALLER_DONE, content::NotificationService::AllSources()); - EXPECT_TRUE(service()->OnExternalExtensionFileFound(kGoodId, - &older_version, - kInvalidPathToCrx, - Manifest::INTERNAL, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_TRUE(service()->OnExternalExtensionFileFound( + kGoodId, + &older_version, + kInvalidPathToCrx, + Manifest::INTERNAL, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE(pending->IsIdPending(kGoodId)); observer.Wait(); VerifyCrxInstall(kInvalidPathToCrx, INSTALL_FAILED); @@ -6868,12 +6906,14 @@ content::WindowedNotificationObserver observer( extensions::NOTIFICATION_CRX_INSTALLER_DONE, content::NotificationService::AllSources()); - EXPECT_TRUE(service()->OnExternalExtensionFileFound(kGoodId, - &older_version, - kInvalidPathToCrx, - Manifest::EXTERNAL_PREF, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_TRUE(service()->OnExternalExtensionFileFound( + kGoodId, + &older_version, + kInvalidPathToCrx, + Manifest::EXTERNAL_PREF, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE(pending->IsIdPending(kGoodId)); observer.Wait(); VerifyCrxInstall(kInvalidPathToCrx, INSTALL_FAILED); @@ -6882,21 +6922,25 @@ // Simulate an external source adding as EXTERNAL_PREF again. // This is rejected because the version and the location are the same as // the previous installation, which is still pending. - EXPECT_FALSE(service()->OnExternalExtensionFileFound(kGoodId, - &older_version, - kInvalidPathToCrx, - Manifest::EXTERNAL_PREF, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_FALSE(service()->OnExternalExtensionFileFound( + kGoodId, + &older_version, + kInvalidPathToCrx, + Manifest::EXTERNAL_PREF, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE(pending->IsIdPending(kGoodId)); // Try INTERNAL again. Should fail. - EXPECT_FALSE(service()->OnExternalExtensionFileFound(kGoodId, - &older_version, - kInvalidPathToCrx, - Manifest::INTERNAL, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_FALSE(service()->OnExternalExtensionFileFound( + kGoodId, + &older_version, + kInvalidPathToCrx, + Manifest::INTERNAL, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE(pending->IsIdPending(kGoodId)); { @@ -6904,33 +6948,38 @@ content::WindowedNotificationObserver observer( extensions::NOTIFICATION_CRX_INSTALLER_DONE, content::NotificationService::AllSources()); - EXPECT_TRUE( - service()->OnExternalExtensionFileFound(kGoodId, - &older_version, - kInvalidPathToCrx, - Manifest::EXTERNAL_REGISTRY, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_TRUE(service()->OnExternalExtensionFileFound( + kGoodId, + &older_version, + kInvalidPathToCrx, + Manifest::EXTERNAL_REGISTRY, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE(pending->IsIdPending(kGoodId)); observer.Wait(); VerifyCrxInstall(kInvalidPathToCrx, INSTALL_FAILED); } // Registry outranks both external pref and internal, so both fail. - EXPECT_FALSE(service()->OnExternalExtensionFileFound(kGoodId, - &older_version, - kInvalidPathToCrx, - Manifest::EXTERNAL_PREF, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_FALSE(service()->OnExternalExtensionFileFound( + kGoodId, + &older_version, + kInvalidPathToCrx, + Manifest::EXTERNAL_PREF, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE(pending->IsIdPending(kGoodId)); - EXPECT_FALSE(service()->OnExternalExtensionFileFound(kGoodId, - &older_version, - kInvalidPathToCrx, - Manifest::INTERNAL, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_FALSE(service()->OnExternalExtensionFileFound( + kGoodId, + &older_version, + kInvalidPathToCrx, + Manifest::INTERNAL, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE(pending->IsIdPending(kGoodId)); pending->Remove(kGoodId); @@ -6954,70 +7003,83 @@ // older, or the same, and succeed if the version is newer. // Older than the installed version... - EXPECT_FALSE(service()->OnExternalExtensionFileFound(kGoodId, - &older_version, - kInvalidPathToCrx, - Manifest::INTERNAL, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_FALSE(service()->OnExternalExtensionFileFound( + kGoodId, + &older_version, + kInvalidPathToCrx, + Manifest::INTERNAL, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_FALSE(pending->IsIdPending(kGoodId)); // Same version as the installed version... - EXPECT_FALSE(service()->OnExternalExtensionFileFound(kGoodId, - ext->version(), - kInvalidPathToCrx, - Manifest::INTERNAL, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_FALSE(service()->OnExternalExtensionFileFound( + kGoodId, + ext->version(), + kInvalidPathToCrx, + Manifest::INTERNAL, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_FALSE(pending->IsIdPending(kGoodId)); // Newer than the installed version... - EXPECT_TRUE(service()->OnExternalExtensionFileFound(kGoodId, - &newer_version, - kInvalidPathToCrx, - Manifest::INTERNAL, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_TRUE(service()->OnExternalExtensionFileFound( + kGoodId, + &newer_version, + kInvalidPathToCrx, + Manifest::INTERNAL, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE(pending->IsIdPending(kGoodId)); // An external install for a higher priority install source should succeed // if the version is greater. |older_version| is not... - EXPECT_FALSE(service()->OnExternalExtensionFileFound(kGoodId, - &older_version, - kInvalidPathToCrx, - Manifest::EXTERNAL_PREF, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_FALSE(service()->OnExternalExtensionFileFound( + kGoodId, + &older_version, + kInvalidPathToCrx, + Manifest::EXTERNAL_PREF, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE(pending->IsIdPending(kGoodId)); // |newer_version| is newer. - EXPECT_TRUE(service()->OnExternalExtensionFileFound(kGoodId, - &newer_version, - kInvalidPathToCrx, - Manifest::EXTERNAL_PREF, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_TRUE(service()->OnExternalExtensionFileFound( + kGoodId, + &newer_version, + kInvalidPathToCrx, + Manifest::EXTERNAL_PREF, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE(pending->IsIdPending(kGoodId)); // An external install for an even higher priority install source should // succeed if the version is greater. - EXPECT_TRUE( - service()->OnExternalExtensionFileFound(kGoodId, - &newer_version, - kInvalidPathToCrx, - Manifest::EXTERNAL_REGISTRY, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_TRUE(service()->OnExternalExtensionFileFound( + kGoodId, + &newer_version, + kInvalidPathToCrx, + Manifest::EXTERNAL_REGISTRY, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE(pending->IsIdPending(kGoodId)); // Because EXTERNAL_PREF is a lower priority source than EXTERNAL_REGISTRY, // adding from external pref will now fail. - EXPECT_FALSE(service()->OnExternalExtensionFileFound(kGoodId, - &newer_version, - kInvalidPathToCrx, - Manifest::EXTERNAL_PREF, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_FALSE(service()->OnExternalExtensionFileFound( + kGoodId, + &newer_version, + kInvalidPathToCrx, + Manifest::EXTERNAL_PREF, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE(pending->IsIdPending(kGoodId)); } @@ -7028,6 +7090,7 @@ const base::FilePath kInvalidPathToCrx(FILE_PATH_LITERAL("invalid_path")); const int kCreationFlags = 0; const bool kDontMarkAcknowledged = false; + const bool kDontInstallImmediately = false; InitializeEmptyExtensionService(); @@ -7036,48 +7099,55 @@ EXPECT_FALSE(pending->IsIdPending(kGoodId)); // An external provider starts installing from a local crx. - EXPECT_TRUE(service()->OnExternalExtensionFileFound(kGoodId, - &kVersion123, - kInvalidPathToCrx, - Manifest::EXTERNAL_PREF, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_TRUE(service()->OnExternalExtensionFileFound( + kGoodId, + &kVersion123, + kInvalidPathToCrx, + Manifest::EXTERNAL_PREF, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); const extensions::PendingExtensionInfo* info; EXPECT_TRUE((info = pending->GetById(kGoodId))); EXPECT_TRUE(info->version().IsValid()); EXPECT_TRUE(info->version().Equals(kVersion123)); // Adding a newer version overrides the currently pending version. - EXPECT_TRUE(service()->OnExternalExtensionFileFound(kGoodId, - &kVersion124, - kInvalidPathToCrx, - Manifest::EXTERNAL_PREF, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_TRUE(service()->OnExternalExtensionFileFound( + kGoodId, + &kVersion124, + kInvalidPathToCrx, + Manifest::EXTERNAL_PREF, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE((info = pending->GetById(kGoodId))); EXPECT_TRUE(info->version().IsValid()); EXPECT_TRUE(info->version().Equals(kVersion124)); // Adding an older version fails. - EXPECT_FALSE(service()->OnExternalExtensionFileFound(kGoodId, - &kVersion123, - kInvalidPathToCrx, - Manifest::EXTERNAL_PREF, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_FALSE(service()->OnExternalExtensionFileFound( + kGoodId, + &kVersion123, + kInvalidPathToCrx, + Manifest::EXTERNAL_PREF, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE((info = pending->GetById(kGoodId))); EXPECT_TRUE(info->version().IsValid()); EXPECT_TRUE(info->version().Equals(kVersion124)); // Adding an older version fails even when coming from a higher-priority // location. - EXPECT_FALSE( - service()->OnExternalExtensionFileFound(kGoodId, - &kVersion123, - kInvalidPathToCrx, - Manifest::EXTERNAL_REGISTRY, - kCreationFlags, - kDontMarkAcknowledged)); + EXPECT_FALSE(service()->OnExternalExtensionFileFound( + kGoodId, + &kVersion123, + kInvalidPathToCrx, + Manifest::EXTERNAL_REGISTRY, + kCreationFlags, + kDontMarkAcknowledged, + kDontInstallImmediately)); EXPECT_TRUE((info = pending->GetById(kGoodId))); EXPECT_TRUE(info->version().IsValid()); EXPECT_TRUE(info->version().Equals(kVersion124)); @@ -7150,6 +7220,7 @@ crx_path_, Manifest::EXTERNAL_PREF, Extension::NO_FLAGS, + false, false); }
diff --git a/chrome/browser/extensions/extension_system_impl.cc b/chrome/browser/extensions/extension_system_impl.cc index 625c95b..c154a3e1 100644 --- a/chrome/browser/extensions/extension_system_impl.cc +++ b/chrome/browser/extensions/extension_system_impl.cc
@@ -315,7 +315,7 @@ #if defined(OS_CHROMEOS) if (!extensions_enabled) autoupdate_enabled = false; -#endif +#endif // defined(OS_CHROMEOS) extension_service_.reset(new ExtensionService( profile_, base::CommandLine::ForCurrentProcess(), profile_->GetPath().AppendASCII(extensions::kInstallDirectoryName), @@ -334,7 +334,7 @@ ContentVerifierDelegateImpl::GetDefaultMode(); #if defined(OS_CHROMEOS) mode = std::max(mode, ContentVerifierDelegate::BOOTSTRAP); -#endif +#endif // defined(OS_CHROMEOS) if (mode >= ContentVerifierDelegate::BOOTSTRAP) content_verifier_->Start(); info_map()->SetContentVerifier(content_verifier_.get());
diff --git a/chrome/browser/extensions/extension_toolbar_model.cc b/chrome/browser/extensions/extension_toolbar_model.cc index 21451194..e5a05cb 100644 --- a/chrome/browser/extensions/extension_toolbar_model.cc +++ b/chrome/browser/extensions/extension_toolbar_model.cc
@@ -11,6 +11,7 @@ #include "base/metrics/histogram.h" #include "base/metrics/histogram_base.h" #include "base/prefs/pref_service.h" +#include "base/profiler/scoped_tracker.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" #include "chrome/browser/extensions/extension_action_manager.h" @@ -425,14 +426,37 @@ void ExtensionToolbarModel::InitializeExtensionList() { DCHECK(toolbar_items_.empty()); // We shouldn't have any items yet. + // TODO(robliao): Remove ScopedTracker below once crbug.com/463337 is fixed. + tracked_objects::ScopedTracker tracking_profile1( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "463337 ExtensionToolbarModel::InitializeExtensionList1")); last_known_positions_ = extension_prefs_->GetToolbarOrder(); - if (profile_->IsOffTheRecord()) + if (profile_->IsOffTheRecord()) { + // TODO(robliao): Remove ScopedTracker below once crbug.com/463337 is fixed. + tracked_objects::ScopedTracker tracking_profile2( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "463337 ExtensionToolbarModel::InitializeExtensionList2")); IncognitoPopulate(); - else + } else { + // TODO(robliao): Remove ScopedTracker below once crbug.com/463337 is fixed. + tracked_objects::ScopedTracker tracking_profile3( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "463337 ExtensionToolbarModel::InitializeExtensionList3")); Populate(&last_known_positions_); + } extensions_initialized_ = true; + + // TODO(robliao): Remove ScopedTracker below once crbug.com/463337 is fixed. + tracked_objects::ScopedTracker tracking_profile4( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "463337 ExtensionToolbarModel::InitializeExtensionList4")); MaybeUpdateVisibilityPrefs(); + + // TODO(robliao): Remove ScopedTracker below once crbug.com/463337 is fixed. + tracked_objects::ScopedTracker tracking_profile5( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "463337 ExtensionToolbarModel::InitializeExtensionList5")); FOR_EACH_OBSERVER(Observer, observers_, OnToolbarModelInitialized()); }
diff --git a/chrome/browser/extensions/extension_ui_unittest.cc b/chrome/browser/extensions/extension_ui_unittest.cc index 76d643d..0b6c17d 100644 --- a/chrome/browser/extensions/extension_ui_unittest.cc +++ b/chrome/browser/extensions/extension_ui_unittest.cc
@@ -70,8 +70,8 @@ std::string *error) { base::Value* value; - JSONFileValueSerializer serializer(path); - value = serializer.Deserialize(NULL, error); + JSONFileValueDeserializer deserializer(path); + value = deserializer.Deserialize(NULL, error); return static_cast<base::DictionaryValue*>(value); }
diff --git a/chrome/browser/extensions/extension_view_host.cc b/chrome/browser/extensions/extension_view_host.cc index ee79eba..1d0ef9cf 100644 --- a/chrome/browser/extensions/extension_view_host.cc +++ b/chrome/browser/extensions/extension_view_host.cc
@@ -107,9 +107,9 @@ if (!ExtensionSystem::Get(browser_context())-> runtime_data()->IsBackgroundPageReady(extension())) { // Make sure the background page loads before any others. - registrar()->Add(this, - extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY, - content::Source<Extension>(extension())); + registrar_.Add(this, + extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY, + content::Source<Extension>(extension())); return; } @@ -296,13 +296,11 @@ void ExtensionViewHost::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { - if (type == extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY) { - DCHECK(ExtensionSystem::Get(browser_context())-> - runtime_data()->IsBackgroundPageReady(extension())); - LoadInitialURL(); - return; - } - ExtensionHost::Observe(type, source, details); + DCHECK_EQ(type, extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY); + DCHECK(ExtensionSystem::Get(browser_context()) + ->runtime_data() + ->IsBackgroundPageReady(extension())); + LoadInitialURL(); } } // namespace extensions
diff --git a/chrome/browser/extensions/extension_view_host.h b/chrome/browser/extensions/extension_view_host.h index 63cb61e..861d6be9 100644 --- a/chrome/browser/extensions/extension_view_host.h +++ b/chrome/browser/extensions/extension_view_host.h
@@ -9,6 +9,8 @@ #include "components/web_modal/popup_manager.h" #include "components/web_modal/web_contents_modal_dialog_host.h" #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" #include "extensions/browser/extension_host.h" class Browser; @@ -29,7 +31,8 @@ class ExtensionViewHost : public ExtensionHost, public web_modal::WebContentsModalDialogManagerDelegate, - public web_modal::WebContentsModalDialogHost { + public web_modal::WebContentsModalDialogHost, + public content::NotificationObserver { public: ExtensionViewHost(const Extension* extension, content::SiteInstance* site_instance, @@ -127,6 +130,8 @@ // a parent window. scoped_ptr<web_modal::PopupManager> popup_manager_; + content::NotificationRegistrar registrar_; + DISALLOW_COPY_AND_ASSIGN(ExtensionViewHost); };
diff --git a/chrome/browser/extensions/external_policy_loader_unittest.cc b/chrome/browser/extensions/external_policy_loader_unittest.cc index 571c3cb..11e7448 100644 --- a/chrome/browser/extensions/external_policy_loader_unittest.cc +++ b/chrome/browser/extensions/external_policy_loader_unittest.cc
@@ -74,7 +74,8 @@ const base::FilePath& path, Manifest::Location unused, int unused2, - bool unused3) override { + bool unused3, + bool unused4) override { ADD_FAILURE() << "There should be no external extensions from files."; return false; }
diff --git a/chrome/browser/extensions/external_pref_loader.cc b/chrome/browser/extensions/external_pref_loader.cc index 61be159..8e9a1336 100644 --- a/chrome/browser/extensions/external_pref_loader.cc +++ b/chrome/browser/extensions/external_pref_loader.cc
@@ -15,7 +15,9 @@ #include "base/path_service.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/defaults.h" #include "chrome/browser/prefs/pref_service_syncable.h" +#include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/common/chrome_paths.h" #include "content/public/browser/browser_thread.h" @@ -68,10 +70,11 @@ // occurs). An empty dictionary is returned in case of failure (e.g. invalid // path or json content). // Caller takes ownership of the returned dictionary. -base::DictionaryValue* ExtractExtensionPrefs(base::ValueSerializer* serializer, - const base::FilePath& path) { +base::DictionaryValue* ExtractExtensionPrefs( + base::ValueDeserializer* deserializer, + const base::FilePath& path) { std::string error_msg; - base::Value* extensions = serializer->Deserialize(NULL, &error_msg); + base::Value* extensions = deserializer->Deserialize(NULL, &error_msg); if (!extensions) { LOG(WARNING) << "Unable to deserialize json data: " << error_msg << " in file " << path.value() << "."; @@ -113,12 +116,23 @@ void ExternalPrefLoader::StartLoading() { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (options_ & DELAY_LOAD_UNTIL_PRIORITY_SYNC) { + if ((options_ & DELAY_LOAD_UNTIL_PRIORITY_SYNC) && + (profile_ && profile_->IsSyncAccessible())) { if (!PostLoadIfPrioritySyncReady()) { DCHECK(profile_); PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_); DCHECK(prefs); syncable_pref_observer_.Add(prefs); + ProfileSyncService* service = + ProfileSyncServiceFactory::GetForProfile(profile_); + DCHECK(service); + if (service->IsSyncEnabledAndLoggedIn() && + (service->HasSyncSetupCompleted() || + browser_defaults::kSyncAutoStarts)) { + service->AddObserver(this); + } else { + PostLoadAndRemoveObservers(); + } } } else { BrowserThread::PostTask( @@ -131,6 +145,15 @@ PostLoadIfPrioritySyncReady(); } +void ExternalPrefLoader::OnStateChanged() { + ProfileSyncService* service = + ProfileSyncServiceFactory::GetForProfile(profile_); + DCHECK(service); + if (!service->IsSyncEnabledAndLoggedIn()) { + PostLoadAndRemoveObservers(); + } +} + bool ExternalPrefLoader::PostLoadIfPrioritySyncReady() { DCHECK(options_ & DELAY_LOAD_UNTIL_PRIORITY_SYNC); DCHECK(profile_); @@ -138,16 +161,28 @@ PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_); DCHECK(prefs); if (prefs->IsPrioritySyncing()) { - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - base::Bind(&ExternalPrefLoader::LoadOnFileThread, this)); - syncable_pref_observer_.Remove(prefs); + PostLoadAndRemoveObservers(); return true; } return false; } +void ExternalPrefLoader::PostLoadAndRemoveObservers() { + PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_); + DCHECK(prefs); + syncable_pref_observer_.Remove(prefs); + + ProfileSyncService* service = + ProfileSyncServiceFactory::GetForProfile(profile_); + DCHECK(service); + service->RemoveObserver(this); + + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + base::Bind(&ExternalPrefLoader::LoadOnFileThread, this)); +} + void ExternalPrefLoader::LoadOnFileThread() { CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); @@ -220,9 +255,9 @@ #endif // defined(OS_MACOSX) } - JSONFileValueSerializer serializer(json_file); + JSONFileValueDeserializer deserializer(json_file); scoped_ptr<base::DictionaryValue> ext_prefs( - ExtractExtensionPrefs(&serializer, json_file)); + ExtractExtensionPrefs(&deserializer, json_file)); if (ext_prefs) prefs->MergeDictionary(ext_prefs.get()); } @@ -258,9 +293,9 @@ DVLOG(1) << "Reading json file: " << extension_candidate_path.LossyDisplayName(); - JSONFileValueSerializer serializer(extension_candidate_path); + JSONFileValueDeserializer deserializer(extension_candidate_path); scoped_ptr<base::DictionaryValue> ext_prefs( - ExtractExtensionPrefs(&serializer, extension_candidate_path)); + ExtractExtensionPrefs(&deserializer, extension_candidate_path)); if (ext_prefs) { DVLOG(1) << "Adding extension with id: " << id; prefs->Set(id, ext_prefs.release()); @@ -273,9 +308,9 @@ const base::FilePath& fake_base_path) : fake_base_path_(fake_base_path) { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - JSONStringValueSerializer serializer(json_data); + JSONStringValueDeserializer deserializer(json_data); base::FilePath fake_json_path = fake_base_path.AppendASCII("fake.json"); - testing_prefs_.reset(ExtractExtensionPrefs(&serializer, fake_json_path)); + testing_prefs_.reset(ExtractExtensionPrefs(&deserializer, fake_json_path)); } void ExternalTestingLoader::StartLoading() {
diff --git a/chrome/browser/extensions/external_pref_loader.h b/chrome/browser/extensions/external_pref_loader.h index dca6dad..d951db8 100644 --- a/chrome/browser/extensions/external_pref_loader.h +++ b/chrome/browser/extensions/external_pref_loader.h
@@ -13,6 +13,8 @@ #include "base/values.h" #include "chrome/browser/extensions/external_loader.h" #include "chrome/browser/prefs/pref_service_syncable_observer.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/profile_sync_service_observer.h" class PrefServiceSyncable; class Profile; @@ -24,7 +26,8 @@ // Instances of this class are expected to be created and destroyed on the UI // thread and they are expecting public method calls from the UI thread. class ExternalPrefLoader : public ExternalLoader, - public PrefServiceSyncableObserver { + public PrefServiceSyncableObserver, + public ProfileSyncServiceObserver { public: enum Options { NONE = 0, @@ -67,9 +70,15 @@ // PrefServiceSyncableObserver: void OnIsSyncingChanged() override; + // ProfileSyncServiceObserver + void OnStateChanged() override; + // If priority sync ready posts LoadOnFileThread and return true. bool PostLoadIfPrioritySyncReady(); + // Post LoadOnFileThread and stop observing for sync service states. + void PostLoadAndRemoveObservers(); + // Actually searches for and loads candidate standalone extension preference // files in the path corresponding to |base_path_id|. // Must be called on the file thread.
diff --git a/chrome/browser/extensions/external_provider_impl.cc b/chrome/browser/extensions/external_provider_impl.cc index 9966755..f312288 100644 --- a/chrome/browser/extensions/external_provider_impl.cc +++ b/chrome/browser/extensions/external_provider_impl.cc
@@ -13,6 +13,7 @@ #include "base/memory/linked_ptr.h" #include "base/metrics/field_trial.h" #include "base/strings/string_util.h" +#include "base/trace_event/trace_event.h" #include "base/values.h" #include "base/version.h" #include "chrome/browser/app_mode/app_mode_utils.h" @@ -80,7 +81,8 @@ loader_(loader), profile_(profile), creation_flags_(creation_flags), - auto_acknowledge_(false) { + auto_acknowledge_(false), + install_immediately_(false) { loader_->Init(this); } @@ -271,7 +273,8 @@ } service_->OnExternalExtensionFileFound(extension_id, &version, path, crx_location_, creation_flags, - auto_acknowledge_); + auto_acknowledge_, + install_immediately_); } else { // if (has_external_update_url) CHECK(has_external_update_url); // Checking of keys above ensures this. if (download_location_ == Manifest::INVALID_LOCATION) { @@ -362,6 +365,8 @@ VisitorInterface* service, Profile* profile, ProviderCollection* provider_list) { + TRACE_EVENT0("browser,startup", + "ExternalProviderImpl::CreateExternalProviders"); scoped_refptr<ExternalLoader> external_loader; scoped_refptr<ExternalLoader> external_recommended_loader; extensions::Manifest::Location crx_location = Manifest::INVALID_LOCATION; @@ -423,13 +428,15 @@ chromeos::KioskAppManager::Get(); DCHECK(kiosk_app_manager); if (kiosk_app_manager && !kiosk_app_manager->external_loader_created()) { - provider_list->push_back(linked_ptr<ExternalProviderInterface>( - new ExternalProviderImpl(service, - kiosk_app_manager->CreateExternalLoader(), - profile, - Manifest::EXTERNAL_PREF, - Manifest::INVALID_LOCATION, - Extension::NO_FLAGS))); + scoped_ptr<ExternalProviderImpl> kiosk_app_provider( + new ExternalProviderImpl( + service, kiosk_app_manager->CreateExternalLoader(), profile, + Manifest::EXTERNAL_PREF, Manifest::INVALID_LOCATION, + Extension::NO_FLAGS)); + kiosk_app_provider->set_auto_acknowledge(true); + kiosk_app_provider->set_install_immediately(true); + provider_list->push_back( + linked_ptr<ExternalProviderInterface>(kiosk_app_provider.release())); } #endif return; @@ -473,15 +480,15 @@ int external_apps_path_id = profile->IsSupervised() ? chrome::DIR_SUPERVISED_USERS_DEFAULT_APPS : chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS; + ExternalPrefLoader::Options pref_load_flags = + profile->IsNewProfile() + ? ExternalPrefLoader::DELAY_LOAD_UNTIL_PRIORITY_SYNC + : ExternalPrefLoader::NONE; provider_list->push_back( linked_ptr<ExternalProviderInterface>(new ExternalProviderImpl( - service, - new ExternalPrefLoader(external_apps_path_id, - ExternalPrefLoader::NONE, - profile), - profile, - Manifest::EXTERNAL_PREF, - Manifest::EXTERNAL_PREF_DOWNLOAD, + service, new ExternalPrefLoader(external_apps_path_id, + pref_load_flags, profile), + profile, Manifest::EXTERNAL_PREF, Manifest::EXTERNAL_PREF_DOWNLOAD, bundled_extension_creation_flags))); // OEM default apps. @@ -498,7 +505,7 @@ oem_extension_creation_flags))); } #elif defined(OS_LINUX) - if (!profile->IsSupervised()) { + if (!profile->IsLegacySupervised()) { provider_list->push_back( linked_ptr<ExternalProviderInterface>( new ExternalProviderImpl( @@ -514,7 +521,7 @@ } #endif - if (!profile->IsSupervised()) { + if (!profile->IsLegacySupervised()) { #if defined(OS_WIN) provider_list->push_back( linked_ptr<ExternalProviderInterface>( @@ -570,17 +577,17 @@ Extension::FROM_WEBSTORE | Extension::WAS_INSTALLED_BY_DEFAULT))); #endif - - provider_list->push_back( - linked_ptr<ExternalProviderInterface>( - new ExternalProviderImpl( - service, - new ExternalComponentLoader(profile), - profile, - Manifest::INVALID_LOCATION, - Manifest::EXTERNAL_COMPONENT, - Extension::FROM_WEBSTORE | Extension::WAS_INSTALLED_BY_DEFAULT))); } + + provider_list->push_back( + linked_ptr<ExternalProviderInterface>( + new ExternalProviderImpl( + service, + new ExternalComponentLoader(profile), + profile, + Manifest::INVALID_LOCATION, + Manifest::EXTERNAL_COMPONENT, + Extension::FROM_WEBSTORE | Extension::WAS_INSTALLED_BY_DEFAULT))); } } // namespace extensions
diff --git a/chrome/browser/extensions/external_provider_impl.h b/chrome/browser/extensions/external_provider_impl.h index 0ba5e516..6217fb7 100644 --- a/chrome/browser/extensions/external_provider_impl.h +++ b/chrome/browser/extensions/external_provider_impl.h
@@ -78,6 +78,10 @@ auto_acknowledge_ = auto_acknowledge; } + void set_install_immediately(bool install_immediately) { + install_immediately_ = install_immediately; + } + private: // Location for external extensions that are provided by this provider from // local crx files. @@ -113,6 +117,9 @@ // the user doesn't see an alert about them. bool auto_acknowledge_; + // Whether the extensions from this provider should be installed immediately. + bool install_immediately_; + DISALLOW_COPY_AND_ASSIGN(ExternalProviderImpl); };
diff --git a/chrome/browser/extensions/install_verifier.cc b/chrome/browser/extensions/install_verifier.cc index 2f23209a..bc1d690 100644 --- a/chrome/browser/extensions/install_verifier.cc +++ b/chrome/browser/extensions/install_verifier.cc
@@ -13,6 +13,7 @@ #include "base/metrics/histogram.h" #include "base/prefs/pref_service.h" #include "base/stl_util.h" +#include "base/trace_event/trace_event.h" #include "chrome/browser/extensions/extension_management.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/install_signer.h" @@ -204,6 +205,7 @@ } void InstallVerifier::Init() { + TRACE_EVENT0("browser,startup", "extensions::InstallVerifier::Init"); UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ExperimentStatus", GetExperimentStatus(), VERIFY_STATUS_MAX); UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ActualStatus",
diff --git a/chrome/browser/extensions/unpacked_installer.cc b/chrome/browser/extensions/unpacked_installer.cc index b4f3976..36368aca 100644 --- a/chrome/browser/extensions/unpacked_installer.cc +++ b/chrome/browser/extensions/unpacked_installer.cc
@@ -350,6 +350,11 @@ service_weak_->profile(), be_noisy_on_failure_); } + + if (!callback_.is_null()) { + callback_.Run(nullptr, extension_path_, error); + callback_.Reset(); + } } void UnpackedInstaller::InstallExtension() { @@ -361,6 +366,11 @@ service_weak_->OnExtensionInstalled( extension(), syncer::StringOrdinal(), kInstallFlagInstallImmediately); + + if (!callback_.is_null()) { + callback_.Run(extension(), extension_path_, std::string()); + callback_.Reset(); + } } } // namespace extensions
diff --git a/chrome/browser/extensions/unpacked_installer.h b/chrome/browser/extensions/unpacked_installer.h index 853cc39..db95a07 100644 --- a/chrome/browser/extensions/unpacked_installer.h +++ b/chrome/browser/extensions/unpacked_installer.h
@@ -29,8 +29,9 @@ class UnpackedInstaller : public base::RefCountedThreadSafe<UnpackedInstaller> { public: - typedef base::Callback<void(const base::FilePath&, const std::string&)> - OnFailureCallback; + using CompletionCallback = base::Callback<void(const Extension* extension, + const base::FilePath&, + const std::string&)>; static scoped_refptr<UnpackedInstaller> Create( ExtensionService* extension_service); @@ -68,6 +69,10 @@ be_noisy_on_failure_ = be_noisy_on_failure; } + void set_completion_callback(const CompletionCallback& callback) { + callback_ = callback; + } + private: friend class base::RefCountedThreadSafe<UnpackedInstaller>; @@ -133,6 +138,8 @@ // installed. ExtensionInstallChecker install_checker_; + CompletionCallback callback_; + DISALLOW_COPY_AND_ASSIGN(UnpackedInstaller); };
diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc index a8269f3..40a4406 100644 --- a/chrome/browser/extensions/user_script_listener_unittest.cc +++ b/chrome/browser/extensions/user_script_listener_unittest.cc
@@ -77,9 +77,9 @@ base::DictionaryValue* LoadManifestFile(const base::FilePath path, std::string* error) { EXPECT_TRUE(base::PathExists(path)); - JSONFileValueSerializer serializer(path); + JSONFileValueDeserializer deserializer(path); return static_cast<base::DictionaryValue*>( - serializer.Deserialize(NULL, error)); + deserializer.Deserialize(NULL, error)); } scoped_refptr<Extension> LoadExtension(const std::string& filename,
diff --git a/chrome/browser/geolocation/geolocation_permission_context.cc b/chrome/browser/geolocation/geolocation_permission_context.cc index a183871..7110b4f 100644 --- a/chrome/browser/geolocation/geolocation_permission_context.cc +++ b/chrome/browser/geolocation/geolocation_permission_context.cc
@@ -36,12 +36,14 @@ web_contents, id, id.bridge_id(), requesting_frame_origin, user_gesture, callback, &permission_set, &new_permission)) { if (permission_set) { + ContentSetting content_setting = + new_permission ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; NotifyPermissionSet(id, requesting_frame_origin, web_contents->GetLastCommittedURL().GetOrigin(), callback, true, - new_permission); + content_setting); } return; }
diff --git a/chrome/browser/geolocation/geolocation_permission_context_android.cc b/chrome/browser/geolocation/geolocation_permission_context_android.cc index dbf865d1..3a38c25 100644 --- a/chrome/browser/geolocation/geolocation_permission_context_android.cc +++ b/chrome/browser/geolocation/geolocation_permission_context_android.cc
@@ -28,7 +28,7 @@ if (!location_settings_->IsLocationEnabled()) { PermissionDecided(id, requesting_frame_origin, web_contents->GetLastCommittedURL().GetOrigin(), - callback, false /* persist */, false /* granted */); + callback, false /* persist */, CONTENT_SETTING_BLOCK); return; }
diff --git a/chrome/browser/geolocation/geolocation_permission_context_extensions.cc b/chrome/browser/geolocation/geolocation_permission_context_extensions.cc index 88456258..15a32092a 100644 --- a/chrome/browser/geolocation/geolocation_permission_context_extensions.cc +++ b/chrome/browser/geolocation/geolocation_permission_context_extensions.cc
@@ -20,6 +20,18 @@ using extensions::ExtensionRegistry; #endif +namespace { + +#if ENABLE_EXTENSIONS +void CallbackContentSettingWrapper( + const base::Callback<void(ContentSetting)>& callback, + bool allowed) { + callback.Run(allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK); +} +#endif // ENABLE_EXTENSIONS + +} // anonymous namespace + GeolocationPermissionContextExtensions:: GeolocationPermissionContextExtensions(Profile* profile) : profile_(profile) { @@ -35,7 +47,7 @@ int bridge_id, const GURL& requesting_frame, bool user_gesture, - base::Callback<void(bool)> callback, + const base::Callback<void(ContentSetting)>& callback, bool* permission_set, bool* new_permission) { #if defined(ENABLE_EXTENSIONS) @@ -45,7 +57,8 @@ extensions::WebViewPermissionHelper::FromWebContents(web_contents); if (web_view_permission_helper) { web_view_permission_helper->RequestGeolocationPermission( - bridge_id, requesting_frame, user_gesture, callback); + bridge_id, requesting_frame, user_gesture, + base::Bind(&CallbackContentSettingWrapper, callback)); *permission_set = false; *new_permission = false; return true;
diff --git a/chrome/browser/geolocation/geolocation_permission_context_extensions.h b/chrome/browser/geolocation/geolocation_permission_context_extensions.h index e073b14f..a7bcaf9 100644 --- a/chrome/browser/geolocation/geolocation_permission_context_extensions.h +++ b/chrome/browser/geolocation/geolocation_permission_context_extensions.h
@@ -7,6 +7,7 @@ #include "base/callback_forward.h" #include "base/macros.h" +#include "components/content_settings/core/common/content_settings.h" namespace content { class WebContents; @@ -30,7 +31,7 @@ int bridge_id, const GURL& requesting_frame, bool user_gesture, - base::Callback<void(bool)> callback, + const base::Callback<void(ContentSetting)>& callback, bool* permission_set, bool* new_permission);
diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc index 111844d8..37e84062 100644 --- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc +++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
@@ -129,7 +129,7 @@ bool user_gesture); void PermissionResponse(const PermissionRequestID& id, - bool allowed); + ContentSetting content_setting); void CheckPermissionMessageSent(int bridge_id, bool allowed); void CheckPermissionMessageSentForTab(int tab, int bridge_id, bool allowed); void CheckPermissionMessageSentInternal(MockRenderProcessHost* process, @@ -190,8 +190,9 @@ void GeolocationPermissionContextTests::PermissionResponse( const PermissionRequestID& id, - bool allowed) { - responses_[id.render_process_id()] = std::make_pair(id.bridge_id(), allowed); + ContentSetting content_setting) { + responses_[id.render_process_id()] = + std::make_pair(id.bridge_id(), content_setting == CONTENT_SETTING_ALLOW); } void GeolocationPermissionContextTests::CheckPermissionMessageSent(
diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc b/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc index 61da9d5d..4896760 100644 --- a/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc +++ b/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc
@@ -19,6 +19,15 @@ namespace extensions { +namespace { + +void CallbackContentSettingWrapper(const base::Callback<void(bool)>& callback, + ContentSetting content_setting) { + callback.Run(content_setting == CONTENT_SETTING_ALLOW); +} + +} // anonymous namespace + ChromeWebViewPermissionHelperDelegate::ChromeWebViewPermissionHelperDelegate( WebViewPermissionHelper* web_view_permission_helper) : WebViewPermissionHelperDelegate(web_view_permission_helper), @@ -192,12 +201,10 @@ // ChromeWebViewPermissionHelperDelegate::SetPermission. const WebViewPermissionHelper::PermissionResponseCallback permission_callback = - base::Bind(&ChromeWebViewPermissionHelperDelegate:: - OnGeolocationPermissionResponse, - weak_factory_.GetWeakPtr(), - bridge_id, - user_gesture, - callback); + base::Bind(&ChromeWebViewPermissionHelperDelegate:: + OnGeolocationPermissionResponse, + weak_factory_.GetWeakPtr(), bridge_id, user_gesture, + base::Bind(&CallbackContentSettingWrapper, callback)); int request_id = web_view_permission_helper()->RequestPermission( WEB_VIEW_PERMISSION_TYPE_GEOLOCATION, request_info, @@ -209,7 +216,7 @@ void ChromeWebViewPermissionHelperDelegate::OnGeolocationPermissionResponse( int bridge_id, bool user_gesture, - const base::Callback<void(bool)>& callback, + const base::Callback<void(ContentSetting)>& callback, bool allow, const std::string& user_input) { // The <webview> embedder has allowed the permission. We now need to make sure @@ -217,7 +224,7 @@ RemoveBridgeID(bridge_id); if (!allow || !web_view_guest()->attached()) { - callback.Run(false); + callback.Run(CONTENT_SETTING_BLOCK); return; }
diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.h b/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.h index 6a8cda47..ed7e2ffe 100644 --- a/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.h +++ b/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_GUEST_VIEW_WEB_VIEW_CHROME_WEB_VIEW_PERMISSION_HELPER_DELEGATE_H_ #define CHROME_BROWSER_GUEST_VIEW_WEB_VIEW_CHROME_WEB_VIEW_PERMISSION_HELPER_DELEGATE_H_ +#include "components/content_settings/core/common/content_settings.h" #include "extensions/browser/guest_view/web_view/web_view_permission_helper.h" #include "extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.h" @@ -78,7 +79,7 @@ void OnGeolocationPermissionResponse( int bridge_id, bool user_gesture, - const base::Callback<void(bool)>& callback, + const base::Callback<void(ContentSetting)>& callback, bool allow, const std::string& user_input);
diff --git a/chrome/browser/history/chrome_history_client.cc b/chrome/browser/history/chrome_history_client.cc index 0b482f2..eb112dd 100644 --- a/chrome/browser/history/chrome_history_client.cc +++ b/chrome/browser/history/chrome_history_client.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/history/chrome_history_client.h" #include "base/logging.h" +#include "chrome/browser/history/history_utils.h" #include "chrome/browser/ui/profile_error_dialog.h" #include "chrome/common/chrome_version_info.h" #include "chrome/grit/chromium_strings.h" @@ -62,6 +63,10 @@ } } +bool ChromeHistoryClient::CanAddURL(const GURL& url) { + return CanAddURLToHistory(url); +} + void ChromeHistoryClient::NotifyProfileError(sql::InitStatus init_status) { ShowProfileErrorDialog( PROFILE_ERROR_HISTORY,
diff --git a/chrome/browser/history/chrome_history_client.h b/chrome/browser/history/chrome_history_client.h index 30195c1..a229b35 100644 --- a/chrome/browser/history/chrome_history_client.h +++ b/chrome/browser/history/chrome_history_client.h
@@ -26,6 +26,7 @@ void BlockUntilBookmarksLoaded() override; bool IsBookmarked(const GURL& url) override; void GetBookmarks(std::vector<history::URLAndTitle>* bookmarks) override; + bool CanAddURL(const GURL& url) override; void NotifyProfileError(sql::InitStatus init_status) override; bool ShouldReportDatabaseError() override; #if defined(OS_ANDROID)
diff --git a/chrome/browser/history/history_service.cc b/chrome/browser/history/history_service.cc index 3ead68b..d57d8afd 100644 --- a/chrome/browser/history/history_service.cc +++ b/chrome/browser/history/history_service.cc
@@ -31,8 +31,6 @@ #include "chrome/browser/history/history_backend.h" #include "chrome/browser/history/in_memory_history_backend.h" #include "chrome/browser/history/in_memory_url_index.h" -#include "chrome/common/url_constants.h" -#include "components/dom_distiller/core/url_constants.h" #include "components/history/core/browser/download_row.h" #include "components/history/core/browser/history_client.h" #include "components/history/core/browser/history_database_params.h" @@ -396,7 +394,7 @@ // large part of history (think iframes for ads) and we never display them in // history UI. We will still add manual subframes, which are ones the user // has clicked on to get. - if (!CanAddURL(add_page_args.url)) + if (history_client_ && !history_client_->CanAddURL(add_page_args.url)) return; // Inform VisitedDelegate of all links and redirects. @@ -422,7 +420,7 @@ const base::string16& title) { DCHECK(thread_) << "History service being called after cleanup"; DCHECK(thread_checker_.CalledOnValidThread()); - if (!CanAddURL(url)) + if (history_client_ && !history_client_->CanAddURL(url)) return; ScheduleTask(PRIORITY_NORMAL, @@ -460,7 +458,7 @@ DCHECK(thread_) << "History service being called after cleanup"; DCHECK(thread_checker_.CalledOnValidThread()); // Filter out unwanted URLs. - if (!CanAddURL(url)) + if (history_client_ && !history_client_->CanAddURL(url)) return; // Inform VisitDelegate of the URL. @@ -620,7 +618,7 @@ const gfx::Size& pixel_size) { DCHECK(thread_) << "History service being called after cleanup"; DCHECK(thread_checker_.CalledOnValidThread()); - if (!CanAddURL(page_url)) + if (history_client_ && !history_client_->CanAddURL(page_url)) return; ScheduleTask( @@ -636,7 +634,7 @@ const std::vector<SkBitmap>& bitmaps) { DCHECK(thread_) << "History service being called after cleanup"; DCHECK(thread_checker_.CalledOnValidThread()); - if (!CanAddURL(page_url)) + if (history_client_ && !history_client_->CanAddURL(page_url)) return; ScheduleTask(PRIORITY_NORMAL, @@ -977,31 +975,6 @@ thread_->message_loop()->PostTask(FROM_HERE, task); } -// static -bool HistoryService::CanAddURL(const GURL& url) { - if (!url.is_valid()) - return false; - - // TODO: We should allow kChromeUIScheme URLs if they have been explicitly - // typed. Right now, however, these are marked as typed even when triggered - // by a shortcut or menu action. - if (url.SchemeIs(url::kJavaScriptScheme) || - url.SchemeIs(content::kChromeDevToolsScheme) || - url.SchemeIs(content::kChromeUIScheme) || - url.SchemeIs(content::kViewSourceScheme) || - url.SchemeIs(chrome::kChromeNativeScheme) || - url.SchemeIs(chrome::kChromeSearchScheme) || - url.SchemeIs(dom_distiller::kDomDistillerScheme)) - return false; - - // Allow all about: and chrome: URLs except about:blank, since the user may - // like to see "chrome://memory/", etc. in their history and autocomplete. - if (url == GURL(url::kAboutBlankURL)) - return false; - - return true; -} - base::WeakPtr<HistoryService> HistoryService::AsWeakPtr() { DCHECK(thread_checker_.CalledOnValidThread()); return weak_ptr_factory_.GetWeakPtr();
diff --git a/chrome/browser/history/history_service.h b/chrome/browser/history/history_service.h index 2a43211..036e0c56 100644 --- a/chrome/browser/history/history_service.h +++ b/chrome/browser/history/history_service.h
@@ -487,10 +487,6 @@ void AddPagesWithDetails(const history::URLRows& info, history::VisitSource visit_source); - // Returns true if this looks like the type of URL we want to add to the - // history. We filter out some URLs such as JavaScript. - static bool CanAddURL(const GURL& url); - base::WeakPtr<HistoryService> AsWeakPtr(); // syncer::SyncableService implementation. @@ -778,19 +774,19 @@ base::ThreadChecker thread_checker_; // The thread used by the history service to run complicated operations. - // |thread_| is NULL once |Cleanup| is NULL. + // |thread_| is null once Cleanup() is called. base::Thread* thread_; // This class has most of the implementation and runs on the 'thread_'. // You MUST communicate with this class ONLY through the thread_'s // message_loop(). // - // This pointer will be NULL once Cleanup() has been called, meaning no + // This pointer will be null once Cleanup() has been called, meaning no // more calls should be made to the history thread. scoped_refptr<history::HistoryBackend> history_backend_; // A cache of the user-typed URLs kept in memory that is used by the - // autocomplete system. This will be NULL until the database has been created + // autocomplete system. This will be null until the database has been created // on the background thread. // TODO(mrossetti): Consider changing ownership. See http://crbug.com/138321 scoped_ptr<history::InMemoryHistoryBackend> in_memory_backend_;
diff --git a/chrome/browser/history/history_utils.cc b/chrome/browser/history/history_utils.cc new file mode 100644 index 0000000..1bc5e8d --- /dev/null +++ b/chrome/browser/history/history_utils.cc
@@ -0,0 +1,33 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/history/history_utils.h" + +#include "chrome/common/url_constants.h" +#include "components/dom_distiller/core/url_constants.h" +#include "url/gurl.h" + +bool CanAddURLToHistory(const GURL& url) { + if (!url.is_valid()) + return false; + + // TODO: We should allow kChromeUIScheme URLs if they have been explicitly + // typed. Right now, however, these are marked as typed even when triggered + // by a shortcut or menu action. + if (url.SchemeIs(url::kJavaScriptScheme) || + url.SchemeIs(content::kChromeDevToolsScheme) || + url.SchemeIs(content::kChromeUIScheme) || + url.SchemeIs(content::kViewSourceScheme) || + url.SchemeIs(chrome::kChromeNativeScheme) || + url.SchemeIs(chrome::kChromeSearchScheme) || + url.SchemeIs(dom_distiller::kDomDistillerScheme)) + return false; + + // Allow all about: and chrome: URLs except about:blank, since the user may + // like to see "chrome://memory/", etc. in their history and autocomplete. + if (url == GURL(url::kAboutBlankURL)) + return false; + + return true; +}
diff --git a/chrome/browser/history/history_utils.h b/chrome/browser/history/history_utils.h new file mode 100644 index 0000000..d5b80f30 --- /dev/null +++ b/chrome/browser/history/history_utils.h
@@ -0,0 +1,14 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_HISTORY_HISTORY_UTILS_H_ +#define CHROME_BROWSER_HISTORY_HISTORY_UTILS_H_ + +class GURL; + +// Returns true if this looks like the type of URL that should be added to the +// history. This filters out URLs such a JavaScript. +bool CanAddURLToHistory(const GURL& url); + +#endif // CHROME_BROWSER_HISTORY_HISTORY_UTILS_H_
diff --git a/chrome/browser/history/top_sites_impl.cc b/chrome/browser/history/top_sites_impl.cc index 70dc274..94f365b 100644 --- a/chrome/browser/history/top_sites_impl.cc +++ b/chrome/browser/history/top_sites_impl.cc
@@ -24,6 +24,7 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/history/history_backend.h" #include "chrome/browser/history/history_service_factory.h" +#include "chrome/browser/history/history_utils.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" #include "components/history/core/browser/history_db_task.h" @@ -149,7 +150,7 @@ } } - if (!HistoryService::CanAddURL(url)) + if (!CanAddURLToHistory(url)) return false; // It's not a real webpage. scoped_refptr<base::RefCountedBytes> thumbnail_data; @@ -188,7 +189,7 @@ } } - if (!HistoryService::CanAddURL(url)) + if (!CanAddURLToHistory(url)) return false; // It's not a real webpage. if (add_temp_thumbnail) { @@ -743,7 +744,7 @@ if (!load_details) return; const GURL& url = load_details->entry->GetURL(); - if (!cache_->IsKnownURL(url) && HistoryService::CanAddURL(url)) { + if (!cache_->IsKnownURL(url) && CanAddURLToHistory(url)) { // To avoid slamming history we throttle requests when the url updates. // To do otherwise negatively impacts perf tests. RestartQueryForTopSitesTimer(GetUpdateDelay());
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index 309e627..62016fe 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc
@@ -1024,12 +1024,8 @@ ¶ms->quic_always_require_handshake_confirmation); globals.quic_disable_connection_pooling.CopyToIfSet( ¶ms->quic_disable_connection_pooling); - globals.quic_load_server_info_timeout_ms.CopyToIfSet( - ¶ms->quic_load_server_info_timeout_ms); globals.quic_load_server_info_timeout_srtt_multiplier.CopyToIfSet( ¶ms->quic_load_server_info_timeout_srtt_multiplier); - globals.quic_enable_truncated_connection_ids.CopyToIfSet( - ¶ms->quic_enable_truncated_connection_ids); globals.quic_enable_connection_racing.CopyToIfSet( ¶ms->quic_enable_connection_racing); globals.quic_enable_non_blocking_io.CopyToIfSet( @@ -1156,16 +1152,6 @@ ShouldQuicAlwaysRequireHandshakeConfirmation(quic_trial_params)); globals->quic_disable_connection_pooling.set( ShouldQuicDisableConnectionPooling(quic_trial_params)); - int load_server_info_timeout_ms = - GetQuicLoadServerInfoTimeout(quic_trial_params); - if (load_server_info_timeout_ms != 0) { - globals->quic_load_server_info_timeout_ms.set( - load_server_info_timeout_ms); - } - globals->quic_enable_truncated_connection_ids.set( - ShouldQuicEnableTruncatedConnectionIds(quic_trial_params)); - globals->quic_enable_connection_racing.set( - ShouldQuicEnableConnectionRacing(quic_trial_params)); int receive_buffer_size = GetQuicSocketReceiveBufferSize(quic_trial_params); if (receive_buffer_size != 0) { globals->quic_socket_receive_buffer_size.set(receive_buffer_size); @@ -1176,8 +1162,6 @@ globals->quic_load_server_info_timeout_srtt_multiplier.set( load_server_info_timeout_srtt_multiplier); } - globals->quic_enable_truncated_connection_ids.set( - ShouldQuicEnableTruncatedConnectionIds(quic_trial_params)); globals->quic_enable_connection_racing.set( ShouldQuicEnableConnectionRacing(quic_trial_params)); globals->quic_enable_non_blocking_io.set( @@ -1349,18 +1333,6 @@ } // static -int IOThread::GetQuicLoadServerInfoTimeout( - const VariationParameters& quic_trial_params) { - int value; - if (base::StringToInt(GetVariationParam(quic_trial_params, - "load_server_info_timeout"), - &value)) { - return value; - } - return 0; -} - -// static float IOThread::GetQuicLoadServerInfoTimeoutSrttMultiplier( const VariationParameters& quic_trial_params) { double value; @@ -1373,14 +1345,6 @@ } // static -bool IOThread::ShouldQuicEnableTruncatedConnectionIds( - const VariationParameters& quic_trial_params) { - return LowerCaseEqualsASCII( - GetVariationParam(quic_trial_params, "enable_truncated_connection_ids"), - "true"); -} - -// static bool IOThread::ShouldQuicEnableConnectionRacing( const VariationParameters& quic_trial_params) { return LowerCaseEqualsASCII(
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h index c081e64d..6a8a8b3 100644 --- a/chrome/browser/io_thread.h +++ b/chrome/browser/io_thread.h
@@ -186,9 +186,7 @@ Optional<bool> enable_quic_port_selection; Optional<bool> quic_always_require_handshake_confirmation; Optional<bool> quic_disable_connection_pooling; - Optional<int> quic_load_server_info_timeout_ms; Optional<float> quic_load_server_info_timeout_srtt_multiplier; - Optional<bool> quic_enable_truncated_connection_ids; Optional<bool> quic_enable_connection_racing; Optional<bool> quic_enable_non_blocking_io; Optional<bool> quic_disable_disk_cache; @@ -366,22 +364,12 @@ static bool ShouldQuicDisableConnectionPooling( const VariationParameters& quic_trial_params); - // Returns the timeout value for loading of QUIC sever information from disk - // cache based on field trial. Returns 0 if there is an error parsing the - // field trial params, or if the default value should be used. - static int GetQuicLoadServerInfoTimeout( - const VariationParameters& quic_trial_params); - // Returns the ratio of time to load QUIC sever information from disk cache to // 'smoothed RTT' based on field trial. Returns 0 if there is an error parsing // the field trial params, or if the default value should be used. static float GetQuicLoadServerInfoTimeoutSrttMultiplier( const VariationParameters& quic_trial_params); - // Returns true if QUIC's TruncatedConnectionIds should be enabled. - static bool ShouldQuicEnableTruncatedConnectionIds( - const VariationParameters& quic_trial_params); - // Returns true if QUIC's connection racing should be enabled. static bool ShouldQuicEnableConnectionRacing( const VariationParameters& quic_trial_params);
diff --git a/chrome/browser/io_thread_unittest.cc b/chrome/browser/io_thread_unittest.cc index 12c846c9..143ac484 100644 --- a/chrome/browser/io_thread_unittest.cc +++ b/chrome/browser/io_thread_unittest.cc
@@ -135,9 +135,7 @@ EXPECT_EQ(net::QuicTagVector(), params.quic_connection_options); EXPECT_FALSE(params.quic_always_require_handshake_confirmation); EXPECT_FALSE(params.quic_disable_connection_pooling); - EXPECT_EQ(0, params.quic_load_server_info_timeout_ms); - EXPECT_EQ(0.0f, params.quic_load_server_info_timeout_srtt_multiplier); - EXPECT_FALSE(params.quic_enable_truncated_connection_ids); + EXPECT_EQ(0.25f, params.quic_load_server_info_timeout_srtt_multiplier); EXPECT_FALSE(params.quic_enable_connection_racing); EXPECT_FALSE(params.quic_enable_non_blocking_io); EXPECT_FALSE(params.quic_disable_disk_cache); @@ -294,15 +292,6 @@ EXPECT_TRUE(params.quic_disable_connection_pooling); } -TEST_F(IOThreadTest, QuicLoadServerInfoTimeoutFromFieldTrialParams) { - field_trial_group_ = "Enabled"; - field_trial_params_["load_server_info_timeout"] = "50"; - ConfigureQuicGlobals(); - net::HttpNetworkSession::Params params; - InitializeNetworkSessionParams(¶ms); - EXPECT_EQ(50, params.quic_load_server_info_timeout_ms); -} - TEST_F(IOThreadTest, QuicLoadServerInfoTimeToSmoothedRttFromFieldTrialParams) { field_trial_group_ = "Enabled"; field_trial_params_["load_server_info_time_to_srtt"] = "0.5"; @@ -312,15 +301,6 @@ EXPECT_EQ(0.5f, params.quic_load_server_info_timeout_srtt_multiplier); } -TEST_F(IOThreadTest, QuicEnableTruncatedConnectionIds) { - field_trial_group_ = "Enabled"; - field_trial_params_["enable_truncated_connection_ids"] = "true"; - ConfigureQuicGlobals(); - net::HttpNetworkSession::Params params; - InitializeNetworkSessionParams(¶ms); - EXPECT_TRUE(params.quic_enable_truncated_connection_ids); -} - TEST_F(IOThreadTest, QuicEnableConnectionRacing) { field_trial_group_ = "Enabled"; field_trial_params_["enable_connection_racing"] = "true";
diff --git a/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc b/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc index 7b9a0f95..72b66105 100644 --- a/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc +++ b/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc
@@ -77,6 +77,7 @@ // running this test on Linux. // // On Mac: +// TODO(phoglund): download sox from gs instead. // 1. Get SoundFlower: http://rogueamoeba.com/freebies/soundflower/download.php // 2. Install it + reboot. // 3. Install MacPorts (http://www.macports.org/). @@ -304,8 +305,7 @@ // silence trimming. See http://sox.sourceforge.net. base::CommandLine MakeSoxCommandLine() { #if defined(OS_WIN) - base::FilePath sox_path = test::GetReferenceFilesDir().Append( - FILE_PATH_LITERAL("tools/sox.exe")); + base::FilePath sox_path = test::GetToolForPlatform("sox"); if (!base::PathExists(sox_path)) { LOG(ERROR) << "Missing sox.exe binary in " << sox_path.value() << "; you may have to provide this binary yourself."; @@ -313,6 +313,8 @@ } base::CommandLine command_line(sox_path); #else + // TODO(phoglund): call checked-in sox rather than system sox on mac/linux. + // Same for rec invocations on Mac, above. base::CommandLine command_line(base::FilePath(FILE_PATH_LITERAL("sox"))); #endif return command_line; @@ -418,17 +420,7 @@ EXPECT_LT(reference_file.value().length(), 128u); EXPECT_LT(actual_file.value().length(), 128u); -#if defined(OS_WIN) - base::FilePath pesq_path = - test::GetReferenceFilesDir().Append(FILE_PATH_LITERAL("tools/pesq.exe")); -#elif defined(OS_MACOSX) - base::FilePath pesq_path = - test::GetReferenceFilesDir().Append(FILE_PATH_LITERAL("tools/pesq_mac")); -#else - base::FilePath pesq_path = - test::GetReferenceFilesDir().Append(FILE_PATH_LITERAL("tools/pesq")); -#endif - + base::FilePath pesq_path = test::GetToolForPlatform("pesq"); if (!base::PathExists(pesq_path)) { LOG(ERROR) << "Missing PESQ binary in " << pesq_path.value() << "; you may have to provide this binary yourself.";
diff --git a/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc b/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc index 7d1347e..8a1e193 100644 --- a/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc +++ b/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc
@@ -157,12 +157,13 @@ bool RunARGBtoI420Converter(int width, int height, const base::FilePath& captured_video_filename) { - base::FilePath path_to_converter = base::MakeAbsoluteFilePath( - GetBrowserDir().Append(kArgbToI420ConverterExecutable)); + base::FilePath path_to_converter = + GetBrowserDir().Append(kArgbToI420ConverterExecutable); if (!base::PathExists(path_to_converter)) { LOG(ERROR) << "Missing ARGB->I420 converter: should be in " - << path_to_converter.value(); + << path_to_converter.value() + << ". Try building the chromium_builder_webrtc target."; return false; } @@ -208,7 +209,8 @@ if (!base::PathExists(path_to_analyzer)) { LOG(ERROR) << "Missing frame analyzer: should be in " - << path_to_analyzer.value(); + << path_to_analyzer.value() + << ". Try building the chromium_builder_webrtc target."; return false; } if (!base::PathExists(path_to_compare_script)) { @@ -217,6 +219,17 @@ return false; } + base::FilePath path_to_zxing = test::GetToolForPlatform("zxing"); + if (!base::PathExists(path_to_zxing)) { + LOG(ERROR) << "Missing zxing: should be in " << path_to_zxing.value(); + return false; + } + base::FilePath path_to_ffmpeg = test::GetToolForPlatform("ffmpeg"); + if (!base::PathExists(path_to_ffmpeg)) { + LOG(ERROR) << "Missing ffmpeg: should be in " << path_to_ffmpeg.value(); + return false; + } + // Note: don't append switches to this command since it will mess up the // -u in the python invocation! base::CommandLine compare_command(base::CommandLine::NO_PROGRAM); @@ -234,6 +247,10 @@ compare_command.AppendArg(base::StringPrintf("%d", width)); compare_command.AppendArg("--yuv_frame_height"); compare_command.AppendArg(base::StringPrintf("%d", height)); + compare_command.AppendArg("--zxing_path"); + compare_command.AppendArgPath(path_to_zxing); + compare_command.AppendArg("--ffmpeg_path"); + compare_command.AppendArgPath(path_to_ffmpeg); compare_command.AppendArg("--stats_file"); compare_command.AppendArgPath(stats_file);
diff --git a/chrome/browser/media/media_stream_devices_controller.cc b/chrome/browser/media/media_stream_devices_controller.cc index 35cfaa9..cc371d5 100644 --- a/chrome/browser/media/media_stream_devices_controller.cc +++ b/chrome/browser/media/media_stream_devices_controller.cc
@@ -423,9 +423,8 @@ DLOG(WARNING) << "MediaStreamDevicesController::Deny: " << result; NotifyUIRequestDenied(); - if (update_content_setting && request_.all_ancestors_have_same_origin) { - // Store sticky permissions if |update_content_setting| and the request - // is not done from an iframe where the ancestor has a different origin. + if (update_content_setting) { + // Store sticky permissions if |update_content_setting|. CHECK_EQ(content::MEDIA_DEVICE_PERMISSION_DENIED, result); StorePermission(false); } @@ -500,11 +499,6 @@ } bool MediaStreamDevicesController::IsRequestAllowedByDefault() const { - // If not all ancestors of the requesting frame have the same origin, do not - // allow the request per default. - if (!request_.all_ancestors_have_same_origin) - return false; - // The request from internal objects like chrome://URLs is always allowed. if (CheckAllowAllMediaStreamContentForOrigin(profile_, request_.security_origin)) {
diff --git a/chrome/browser/media/protected_media_identifier_permission_context.cc b/chrome/browser/media/protected_media_identifier_permission_context.cc index 05e8a68a..5b95217e 100644 --- a/chrome/browser/media/protected_media_identifier_permission_context.cc +++ b/chrome/browser/media/protected_media_identifier_permission_context.cc
@@ -52,7 +52,7 @@ if (!requesting_origin.is_valid() || !embedding_origin.is_valid() || !IsProtectedMediaIdentifierEnabled()) { NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, - false /* persist */, false /* granted */); + false /* persist */, CONTENT_SETTING_BLOCK); return; } @@ -65,24 +65,18 @@ ContentSetting content_setting = GetPermissionStatus(requesting_origin, embedding_origin); - switch (content_setting) { - case CONTENT_SETTING_BLOCK: - NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, - false /* persist */, false /* granted */); - return; - case CONTENT_SETTING_ALLOW: - NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, - false /* persist */, true /* granted */); - return; - default: - break; + if (content_setting == CONTENT_SETTING_ALLOW || + content_setting == CONTENT_SETTING_BLOCK) { + NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, + false /* persist */, content_setting); + return; } // Since the dialog is modal, we only support one prompt per |web_contents|. // Reject the new one if there is already one pending. See // http://crbug.com/447005 if (pending_requests_.count(web_contents)) { - callback.Run(false); + callback.Run(CONTENT_SETTING_DEFAULT); return; } @@ -189,17 +183,25 @@ DCHECK(request->second.second.Equals(id)); pending_requests_.erase(request); - if (response == PlatformVerificationFlow::CONSENT_RESPONSE_NONE) { - // Deny request and do not save to content settings. - NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, - false, // Do not save to content settings. - false); // Do not allow the permission. - return; + ContentSetting content_setting = CONTENT_SETTING_DEFAULT; + bool persist = false; // Whether the ContentSetting should be saved. + switch (response) { + case PlatformVerificationFlow::CONSENT_RESPONSE_NONE: + content_setting = CONTENT_SETTING_DEFAULT; + persist = false; + break; + case PlatformVerificationFlow::CONSENT_RESPONSE_ALLOW: + content_setting = CONTENT_SETTING_ALLOW; + persist = true; + break; + case PlatformVerificationFlow::CONSENT_RESPONSE_DENY: + content_setting = CONTENT_SETTING_BLOCK; + persist = true; + break; } NotifyPermissionSet( id, requesting_origin, embedding_origin, callback, - true, // Save to content settings. - response == PlatformVerificationFlow::CONSENT_RESPONSE_ALLOW); + persist, content_setting); } #endif
diff --git a/chrome/browser/media/webrtc_browsertest_common.cc b/chrome/browser/media/webrtc_browsertest_common.cc index 34d35a7..f30ecf9 100644 --- a/chrome/browser/media/webrtc_browsertest_common.cc +++ b/chrome/browser/media/webrtc_browsertest_common.cc
@@ -45,6 +45,24 @@ return test_data_dir.Append(kReferenceFilesDirName); } +base::FilePath GetToolForPlatform(const std::string& tool_name) { + base::FilePath tools_dir = + GetReferenceFilesDir().Append(FILE_PATH_LITERAL("tools")); +#if defined(OS_WIN) + return tools_dir + .Append(FILE_PATH_LITERAL("win")) + .AppendASCII(tool_name) + .AddExtension(FILE_PATH_LITERAL("exe")); +#elif defined(OS_MACOSX) + return tools_dir.Append(FILE_PATH_LITERAL("mac")).AppendASCII(tool_name); +#elif defined(OS_LINUX) + return tools_dir.Append(FILE_PATH_LITERAL("linux")).AppendASCII(tool_name); +#else + CHECK(false) << "Can't retrieve tool " << tool_name << " on this platform."; + return base::FilePath(); +#endif +} + bool HasReferenceFilesInCheckout() { if (!base::PathExists(GetReferenceFilesDir())) { LOG(ERROR)
diff --git a/chrome/browser/media/webrtc_browsertest_common.h b/chrome/browser/media/webrtc_browsertest_common.h index 27ab604..40b99d3 100644 --- a/chrome/browser/media/webrtc_browsertest_common.h +++ b/chrome/browser/media/webrtc_browsertest_common.h
@@ -31,6 +31,13 @@ // Retrieves the reference files dir, to which file names can be appended. base::FilePath GetReferenceFilesDir(); +// Retrieves a tool binary path from chrome/test/data/webrtc/resources/tools, +// according to platform. If we're running on Linux, requesting pesq will yield +// chrome/test/data/webrtc/resources/tools/linux/pesq, whereas the same call on +// Windows will yield chrome/test/data/webrtc/resources/tools/win/pesq.exe. +// This function does not check the binary actually exists. +base::FilePath GetToolForPlatform(const std::string& tool_name); + extern const base::FilePath::CharType kReferenceFileName360p[]; extern const base::FilePath::CharType kReferenceFileName720p[]; extern const base::FilePath::CharType kYuvFileExtension[];
diff --git a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc index 2245ba6..c106f654 100644 --- a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc +++ b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
@@ -79,6 +79,13 @@ callback.Run(error, AsyncFileUtil::EntryList(), false /*no more*/); } +// Called when CopyInForeignFile method call failed. +void OnCopyInForeignFileError(const AsyncFileUtil::StatusCallback& callback, + base::File::Error error) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + callback.Run(error); +} + // Called on a blocking pool thread to create a snapshot file to hold the // contents of |device_file_path|. The snapshot file is created in the // "profile_path/kDeviceMediaAsyncFileUtilTempDir" directory. Return the @@ -330,6 +337,7 @@ OnReadDirectoryError(callback, base::File::FILE_ERROR_NOT_FOUND); return; } + delegate->ReadDirectory( url.path(), base::Bind(&DeviceMediaAsyncFileUtil::OnDidReadDirectory, @@ -389,8 +397,22 @@ const FileSystemURL& dest_url, const StatusCallback& callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - NOTIMPLEMENTED(); - callback.Run(base::File::FILE_ERROR_SECURITY); + + MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(dest_url); + if (!delegate) { + OnCopyInForeignFileError(callback, base::File::FILE_ERROR_NOT_FOUND); + return; + } + if (delegate->IsReadOnly()) { + OnCopyInForeignFileError(callback, base::File::FILE_ERROR_SECURITY); + return; + } + + delegate->CopyFileFromLocal( + src_file_path, dest_url.path(), + base::Bind(&DeviceMediaAsyncFileUtil::OnDidCopyInForeignFile, + weak_ptr_factory_.GetWeakPtr(), callback), + base::Bind(&OnCopyInForeignFileError, callback)); } void DeviceMediaAsyncFileUtil::DeleteFile( @@ -511,6 +533,13 @@ base::Bind(&OnDidCheckMediaForReadDirectory, callback, has_more)); } +void DeviceMediaAsyncFileUtil::OnDidCopyInForeignFile( + const StatusCallback& callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + callback.Run(base::File::FILE_OK); +} + bool DeviceMediaAsyncFileUtil::validate_media_files() const { return media_path_filter_wrapper_.get() != NULL; }
diff --git a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h index 3716c44..96c6b1d 100644 --- a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h +++ b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h
@@ -141,6 +141,10 @@ const EntryList& file_list, bool has_more); + // Called when CopyInForeignFile method call succeeds. |callback| is invoked + // to complete the CopyInForeignFile request. + void OnDidCopyInForeignFile(const StatusCallback& callback); + bool validate_media_files() const; // Profile path.
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h index f73c3f77..79555a3 100644 --- a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h +++ b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
@@ -63,6 +63,9 @@ ErrorCallback error_callback; }; + // A callback to be called when CopyFileFromLocal method call succeeds. + typedef base::Closure CopyFileFromLocalSuccessCallback; + // Gets information about the given |file_path| and invokes the appropriate // callback asynchronously when complete. virtual void GetFileInfo( @@ -99,6 +102,16 @@ const ReadBytesSuccessCallback& success_callback, const ErrorCallback& error_callback) = 0; + // Returns true if storage is opened for read only. + virtual bool IsReadOnly() = 0; + + // Copies a file from |source_file_path| to |device_file_path|. + virtual void CopyFileFromLocal( + const base::FilePath& source_file_path, + const base::FilePath& device_file_path, + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback) = 0; + // Called when the // (1) Browser application is in shutdown mode (or) // (2) Last extension using this MTP device is destroyed (or) @@ -119,6 +132,7 @@ void CreateMTPDeviceAsyncDelegate( const base::FilePath::StringType& device_location, + const bool read_only, const CreateMTPDeviceAsyncDelegateCallback& callback); #endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MTP_DEVICE_ASYNC_DELEGATE_H_
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc index b85a9bb9..6941878 100644 --- a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc +++ b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc
@@ -26,64 +26,101 @@ void MTPDeviceMapService::RegisterMTPFileSystem( const base::FilePath::StringType& device_location, - const std::string& fsid) { + const std::string& filesystem_id, + const bool read_only) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(!device_location.empty()); + DCHECK(!filesystem_id.empty()); - if (!ContainsKey(mtp_device_usage_map_, device_location)) { + const AsyncDelegateKey key = GetAsyncDelegateKey(device_location, read_only); + if (!ContainsKey(mtp_device_usage_map_, key)) { // Note that this initializes the delegate asynchronously, but since // the delegate will only be used from the IO thread, it is guaranteed // to be created before use of it expects it to be there. - CreateMTPDeviceAsyncDelegate(device_location, + CreateMTPDeviceAsyncDelegate( + device_location, read_only, base::Bind(&MTPDeviceMapService::AddAsyncDelegate, - base::Unretained(this), device_location)); - mtp_device_usage_map_[device_location] = 0; + base::Unretained(this), device_location, read_only)); + mtp_device_usage_map_[key] = 0; } - mtp_device_usage_map_[device_location]++; - mtp_device_map_[fsid] = device_location; + mtp_device_usage_map_[key]++; + mtp_device_map_[filesystem_id] = make_pair(device_location, read_only); } -void MTPDeviceMapService::RevokeMTPFileSystem(const std::string& fsid) { +void MTPDeviceMapService::RevokeMTPFileSystem( + const std::string& filesystem_id) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(!filesystem_id.empty()); - MTPDeviceFileSystemMap::iterator it = mtp_device_map_.find(fsid); + MTPDeviceFileSystemMap::iterator it = mtp_device_map_.find(filesystem_id); if (it != mtp_device_map_.end()) { - base::FilePath::StringType device_location = it->second; + const base::FilePath::StringType device_location = it->second.first; + const bool read_only = it->second.second; + mtp_device_map_.erase(it); - MTPDeviceUsageMap::iterator delegate_it = - mtp_device_usage_map_.find(device_location); + + const AsyncDelegateKey key = + GetAsyncDelegateKey(device_location, read_only); + MTPDeviceUsageMap::iterator delegate_it = mtp_device_usage_map_.find(key); DCHECK(delegate_it != mtp_device_usage_map_.end()); - mtp_device_usage_map_[device_location]--; - if (mtp_device_usage_map_[device_location] == 0) { + + mtp_device_usage_map_[key]--; + if (mtp_device_usage_map_[key] == 0) { mtp_device_usage_map_.erase(delegate_it); - RemoveAsyncDelegate(device_location); + RemoveAsyncDelegate(device_location, read_only); } } } void MTPDeviceMapService::AddAsyncDelegate( const base::FilePath::StringType& device_location, + const bool read_only, MTPDeviceAsyncDelegate* delegate) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK(delegate); DCHECK(!device_location.empty()); - if (ContainsKey(async_delegate_map_, device_location)) + + const AsyncDelegateKey key = GetAsyncDelegateKey(device_location, read_only); + if (ContainsKey(async_delegate_map_, key)) return; - async_delegate_map_[device_location] = delegate; + async_delegate_map_[key] = delegate; } void MTPDeviceMapService::RemoveAsyncDelegate( - const base::FilePath::StringType& device_location) { + const base::FilePath::StringType& device_location, + const bool read_only) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - AsyncDelegateMap::iterator it = async_delegate_map_.find(device_location); + DCHECK(!device_location.empty()); + + const AsyncDelegateKey key = GetAsyncDelegateKey(device_location, read_only); + AsyncDelegateMap::iterator it = async_delegate_map_.find(key); DCHECK(it != async_delegate_map_.end()); it->second->CancelPendingTasksAndDeleteDelegate(); async_delegate_map_.erase(it); } +// static +MTPDeviceMapService::AsyncDelegateKey MTPDeviceMapService::GetAsyncDelegateKey( + const base::FilePath::StringType& device_location, + const bool read_only) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + base::FilePath::StringType key; + key.append(read_only ? FILE_PATH_LITERAL("ReadOnly") + : FILE_PATH_LITERAL("ReadWrite")); + key.append(FILE_PATH_LITERAL("|")); + key.append(device_location); + return key; +} + MTPDeviceAsyncDelegate* MTPDeviceMapService::GetMTPDeviceAsyncDelegate( const std::string& filesystem_id) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(!filesystem_id.empty()); + + // File system may be already revoked on ExternalMountPoints side, we check + // here that the file system is still valid. base::FilePath device_path; if (!storage::ExternalMountPoints::GetSystemInstance()->GetRegisteredPath( filesystem_id, &device_path)) { @@ -91,10 +128,21 @@ } const base::FilePath::StringType& device_location = device_path.value(); - DCHECK(!device_location.empty()); - AsyncDelegateMap::const_iterator it = - async_delegate_map_.find(device_location); - return (it != async_delegate_map_.end()) ? it->second : NULL; + + MTPDeviceFileSystemMap::const_iterator mtp_device_map_it = + mtp_device_map_.find(filesystem_id); + if (mtp_device_map_it == mtp_device_map_.end()) + return NULL; + + DCHECK_EQ(device_path.value(), mtp_device_map_it->second.first); + const bool read_only = mtp_device_map_it->second.second; + const AsyncDelegateKey key = GetAsyncDelegateKey(device_location, read_only); + + AsyncDelegateMap::const_iterator async_delegate_map_it = + async_delegate_map_.find(key); + return (async_delegate_map_it != async_delegate_map_.end()) + ? async_delegate_map_it->second + : NULL; } MTPDeviceMapService::MTPDeviceMapService() {
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h index d64742e..0f24b14 100644 --- a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h +++ b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h
@@ -29,14 +29,14 @@ const std::string& filesystem_id); // Register that an MTP filesystem is in use for the given |device_location|. - void RegisterMTPFileSystem( - const base::FilePath::StringType& device_location, - const std::string& fsid); + void RegisterMTPFileSystem(const base::FilePath::StringType& device_location, + const std::string& filesystem_id, + const bool read_only); // Removes the MTP entry associated with the given // |device_location|. Signals the MTPDeviceMapService to destroy the // delegate if there are no more uses of it. - void RevokeMTPFileSystem(const std::string& fsid); + void RevokeMTPFileSystem(const std::string& filesystem_id); private: friend struct base::DefaultLazyInstanceTraits<MTPDeviceMapService>; @@ -45,27 +45,34 @@ // specifies the mount location of the MTP device. // Called on the IO thread. void AddAsyncDelegate(const base::FilePath::StringType& device_location, + const bool read_only, MTPDeviceAsyncDelegate* delegate); // Removes the MTP device delegate from the map service. |device_location| // specifies the mount location of the MTP device. // Called on the IO thread. - void RemoveAsyncDelegate(const base::FilePath::StringType& device_location); + void RemoveAsyncDelegate(const base::FilePath::StringType& device_location, + const bool read_only); + + // A key to be used in AsyncDelegateMap and MTPDeviceUsageMap. + typedef base::FilePath::StringType AsyncDelegateKey; + + // Gets a key from |device_location| and |read_only|. + static AsyncDelegateKey GetAsyncDelegateKey( + const base::FilePath::StringType& device_location, + const bool read_only); // Mapping of device_location and MTPDeviceAsyncDelegate* object. It is safe // to store and access the raw pointer. This class operates on the IO thread. - typedef std::map<base::FilePath::StringType, MTPDeviceAsyncDelegate*> - AsyncDelegateMap; + typedef std::map<AsyncDelegateKey, MTPDeviceAsyncDelegate*> AsyncDelegateMap; // Map a filesystem id (fsid) to an MTP device location. - typedef std::map<std::string, base::FilePath::StringType> - MTPDeviceFileSystemMap; + typedef std::pair<base::FilePath::StringType, bool> MTPDeviceInfo; + typedef std::map<std::string, MTPDeviceInfo> MTPDeviceFileSystemMap; // Map a MTP or PTP device location to a count of current uses of that // location. - typedef std::map<const base::FilePath::StringType, int> - MTPDeviceUsageMap; - + typedef std::map<AsyncDelegateKey, int> MTPDeviceUsageMap; // Get access to this class using GetInstance() method. MTPDeviceMapService();
diff --git a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc index b1cd91c5..b742eea8 100644 --- a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc +++ b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
@@ -4,11 +4,13 @@ #include "chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h" +#include <fcntl.h> #include <algorithm> #include <vector> #include "base/bind.h" #include "base/numerics/safe_conversions.h" +#include "base/posix/eintr_wrapper.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -51,13 +53,16 @@ // storage. // // |storage_name| specifies the name of the storage device. +// |read_only| specifies the mode of the storage device. // Returns NULL if the |storage_name| is no longer valid (e.g. because the // corresponding storage device is detached, etc). MTPDeviceTaskHelper* GetDeviceTaskHelperForStorage( - const std::string& storage_name) { + const std::string& storage_name, + const bool read_only) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); return MTPDeviceTaskHelperMapService::GetInstance()->GetDeviceTaskHelper( - storage_name); + storage_name, + read_only); } // Opens the storage device for communication. @@ -66,20 +71,22 @@ // MediaTransferProtocolManager. // // |storage_name| specifies the name of the storage device. +// |read_only| specifies the mode of the storage device. // |reply_callback| is called when the OpenStorage request completes. // |reply_callback| runs on the IO thread. void OpenStorageOnUIThread( const std::string& storage_name, + const bool read_only, const MTPDeviceTaskHelper::OpenStorageCallback& reply_callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); MTPDeviceTaskHelper* task_helper = - GetDeviceTaskHelperForStorage(storage_name); + GetDeviceTaskHelperForStorage(storage_name, read_only); if (!task_helper) { task_helper = MTPDeviceTaskHelperMapService::GetInstance()->CreateDeviceTaskHelper( - storage_name); + storage_name, read_only); } - task_helper->OpenStorage(storage_name, reply_callback); + task_helper->OpenStorage(storage_name, read_only, reply_callback); } // Enumerates the |dir_id| directory file entries. @@ -88,17 +95,19 @@ // MediaTransferProtocolManager. // // |storage_name| specifies the name of the storage device. +// |read_only| specifies the mode of the storage device. // |success_callback| is called when the ReadDirectory request succeeds. // |error_callback| is called when the ReadDirectory request fails. // |success_callback| and |error_callback| runs on the IO thread. void ReadDirectoryOnUIThread( const std::string& storage_name, + const bool read_only, uint32 dir_id, const MTPDeviceTaskHelper::ReadDirectorySuccessCallback& success_callback, const MTPDeviceTaskHelper::ErrorCallback& error_callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); MTPDeviceTaskHelper* task_helper = - GetDeviceTaskHelperForStorage(storage_name); + GetDeviceTaskHelperForStorage(storage_name, read_only); if (!task_helper) return; task_helper->ReadDirectory(dir_id, success_callback, error_callback); @@ -110,17 +119,19 @@ // MediaTransferProtocolManager. // // |storage_name| specifies the name of the storage device. +// |read_only| specifies the mode of the storage device. // |success_callback| is called when the GetFileInfo request succeeds. // |error_callback| is called when the GetFileInfo request fails. // |success_callback| and |error_callback| runs on the IO thread. void GetFileInfoOnUIThread( const std::string& storage_name, + const bool read_only, uint32 file_id, const MTPDeviceTaskHelper::GetFileInfoSuccessCallback& success_callback, const MTPDeviceTaskHelper::ErrorCallback& error_callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); MTPDeviceTaskHelper* task_helper = - GetDeviceTaskHelperForStorage(storage_name); + GetDeviceTaskHelperForStorage(storage_name, read_only); if (!task_helper) return; task_helper->GetFileInfo(file_id, success_callback, error_callback); @@ -132,6 +143,7 @@ // MediaTransferProtocolManager. // // |storage_name| specifies the name of the storage device. +// |read_only| specifies the mode of the storage device. // |device_file_path| specifies the media device file path. // |snapshot_file_path| specifies the platform path of the snapshot file. // |file_size| specifies the number of bytes that will be written to the @@ -141,11 +153,12 @@ // |success_callback| and |error_callback| runs on the IO thread. void WriteDataIntoSnapshotFileOnUIThread( const std::string& storage_name, + const bool read_only, const SnapshotRequestInfo& request_info, const base::File::Info& snapshot_file_info) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); MTPDeviceTaskHelper* task_helper = - GetDeviceTaskHelperForStorage(storage_name); + GetDeviceTaskHelperForStorage(storage_name, read_only); if (!task_helper) return; task_helper->WriteDataIntoSnapshotFile(request_info, snapshot_file_info); @@ -157,33 +170,80 @@ // MediaTransferProtocolManager. // // |storage_name| specifies the name of the storage device. +// |read_only| specifies the mode of the storage device. // |request| is a struct containing details about the byte read request. void ReadBytesOnUIThread( const std::string& storage_name, + const bool read_only, const MTPDeviceAsyncDelegate::ReadBytesRequest& request) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); MTPDeviceTaskHelper* task_helper = - GetDeviceTaskHelperForStorage(storage_name); + GetDeviceTaskHelperForStorage(storage_name, read_only); if (!task_helper) return; task_helper->ReadBytes(request); } +// Copies the file |source_file_descriptor| to |file_name| in |parent_id|. +// +// |storage_name| specifies the name of the storage device. +// |read_only| specifies the mode of the storage device. +// |source_file_descriptor| file descriptor of source file. +// |parent_id| object id of a target directory. +// |file_name| file name of a target file. +// |success_callback| is called when the file is copied successfully. +// |error_callback| is called when it fails to copy file. +// Since this method does not close the file descriptor, callbacks are +// responsible for closing it. +void CopyFileFromLocalOnUIThread( + const std::string& storage_name, + const bool read_only, + const int source_file_descriptor, + const uint32 parent_id, + const std::string& file_name, + const MTPDeviceTaskHelper::CopyFileFromLocalSuccessCallback& + success_callback, + const MTPDeviceTaskHelper::ErrorCallback& error_callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + MTPDeviceTaskHelper* task_helper = + GetDeviceTaskHelperForStorage(storage_name, read_only); + if (!task_helper) + return; + task_helper->CopyFileFromLocal(storage_name, source_file_descriptor, + parent_id, file_name, success_callback, + error_callback); +} + // Closes the device storage specified by the |storage_name| and destroys the // MTPDeviceTaskHelper object associated with the device storage. // // Called on the UI thread to dispatch the request to the // MediaTransferProtocolManager. void CloseStorageAndDestroyTaskHelperOnUIThread( - const std::string& storage_name) { + const std::string& storage_name, + const bool read_only) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); MTPDeviceTaskHelper* task_helper = - GetDeviceTaskHelperForStorage(storage_name); + GetDeviceTaskHelperForStorage(storage_name, read_only); if (!task_helper) return; task_helper->CloseStorage(); MTPDeviceTaskHelperMapService::GetInstance()->DestroyDeviceTaskHelper( - storage_name); + storage_name, read_only); +} + +// Opens |file_path| with |flags|. +int OpenFileDescriptor(const char* file_path, const int flags) { + DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); + + return open(file_path, flags); +} + +// Closes |file_descriptor| on file thread. +void CloseFileDescriptor(const int file_descriptor) { + DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); + + IGNORE_EINTR(close(file_descriptor)); } } // namespace @@ -310,10 +370,12 @@ } MTPDeviceDelegateImplLinux::MTPDeviceDelegateImplLinux( - const std::string& device_location) + const std::string& device_location, + const bool read_only) : init_state_(UNINITIALIZED), task_in_progress_(false), device_path_(device_location), + read_only_(read_only), root_node_(new MTPFileNode(mtpd::kRootFileId, "", // Root node has no name. NULL, // And no parent node. @@ -432,13 +494,41 @@ closure)); } +bool MTPDeviceDelegateImplLinux::IsReadOnly() { + return read_only_; +} + +void MTPDeviceDelegateImplLinux::CopyFileFromLocal( + const base::FilePath& source_file_path, + const base::FilePath& device_file_path, + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(!source_file_path.empty()); + DCHECK(!device_file_path.empty()); + + content::BrowserThread::PostTaskAndReplyWithResult( + content::BrowserThread::FILE, + FROM_HERE, + base::Bind(&OpenFileDescriptor, + source_file_path.value().c_str(), + O_RDONLY), + base::Bind(&MTPDeviceDelegateImplLinux::CopyFileFromLocalInternal, + weak_ptr_factory_.GetWeakPtr(), + device_file_path, + success_callback, + error_callback)); +} + void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); // To cancel all the pending tasks, destroy the MTPDeviceTaskHelper object. content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE, - base::Bind(&CloseStorageAndDestroyTaskHelperOnUIThread, storage_name_)); + base::Bind(&CloseStorageAndDestroyTaskHelperOnUIThread, + storage_name_, + read_only_)); delete this; } @@ -463,6 +553,7 @@ base::Closure closure = base::Bind(&GetFileInfoOnUIThread, storage_name_, + read_only_, file_id, success_callback_wrapper, error_callback_wrapper); @@ -497,6 +588,7 @@ dir_id); base::Closure closure = base::Bind(&GetFileInfoOnUIThread, storage_name_, + read_only_, dir_id, success_callback_wrapper, error_callback_wrapper); @@ -536,6 +628,7 @@ file_id); base::Closure closure = base::Bind(&GetFileInfoOnUIThread, storage_name_, + read_only_, file_id, success_callback_wrapper, error_callback_wrapper); @@ -569,7 +662,7 @@ file_id)); base::Closure closure = - base::Bind(base::Bind(&ReadBytesOnUIThread, storage_name_, request)); + base::Bind(&ReadBytesOnUIThread, storage_name_, read_only_, request); EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(), content::BrowserThread::UI, FROM_HERE, @@ -580,6 +673,49 @@ PendingRequestDone(); } +void MTPDeviceDelegateImplLinux::CopyFileFromLocalInternal( + const base::FilePath& device_file_path, + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback, + const int source_file_descriptor) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + if (source_file_descriptor < 0) { + error_callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); + PendingRequestDone(); + return; + } + + uint32 parent_id; + if (CachedPathToId(device_file_path.DirName(), &parent_id)) { + CopyFileFromLocalSuccessCallback success_callback_wrapper = + base::Bind(&MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal, + weak_ptr_factory_.GetWeakPtr(), success_callback, + source_file_descriptor); + + ErrorCallback error_callback_wrapper = base::Bind( + &MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError, + weak_ptr_factory_.GetWeakPtr(), error_callback, source_file_descriptor); + + base::Closure closure = base::Bind(&CopyFileFromLocalOnUIThread, + storage_name_, + read_only_, + source_file_descriptor, + parent_id, + device_file_path.BaseName().value(), + success_callback_wrapper, + error_callback_wrapper); + + EnsureInitAndRunTask(PendingTaskInfo( + base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure)); + } else { + HandleCopyFileFromLocalError(error_callback, source_file_descriptor, + base::File::FILE_ERROR_INVALID_OPERATION); + } + + PendingRequestDone(); +} + void MTPDeviceDelegateImplLinux::EnsureInitAndRunTask( const PendingTaskInfo& task_info) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); @@ -599,10 +735,8 @@ init_state_ = PENDING_INIT; task_in_progress_ = true; content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::Bind(&OpenStorageOnUIThread, - storage_name_, + content::BrowserThread::UI, FROM_HERE, + base::Bind(&OpenStorageOnUIThread, storage_name_, read_only_, base::Bind(&MTPDeviceDelegateImplLinux::OnInitCompleted, weak_ptr_factory_.GetWeakPtr()))); } @@ -649,6 +783,7 @@ base::Closure task_closure = base::Bind(&WriteDataIntoSnapshotFileOnUIThread, storage_name_, + read_only_, request_info, file_info); content::BrowserThread::PostTask(content::BrowserThread::UI, @@ -657,6 +792,7 @@ } void MTPDeviceDelegateImplLinux::PendingRequestDone() { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK(task_in_progress_); task_in_progress_ = false; ProcessNextPendingRequest(); @@ -703,6 +839,7 @@ base::Closure task_closure = base::Bind(&ReadDirectoryOnUIThread, storage_name_, + read_only_, dir_id, base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadDirectory, weak_ptr_factory_.GetWeakPtr(), @@ -854,6 +991,37 @@ pending_tasks_.front().path.clear(); } +void MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal( + const CopyFileFromLocalSuccessCallback& success_callback, + const int source_file_descriptor) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + const base::Closure closure = base::Bind(&CloseFileDescriptor, + source_file_descriptor); + + content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, + closure); + + success_callback.Run(); + PendingRequestDone(); +} + +void MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError( + const ErrorCallback& error_callback, + const int source_file_descriptor, + base::File::Error error) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + const base::Closure closure = base::Bind(&CloseFileDescriptor, + source_file_descriptor); + + content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, + closure); + + error_callback.Run(error); + PendingRequestDone(); +} + void MTPDeviceDelegateImplLinux::HandleDeviceFileError( const ErrorCallback& error_callback, uint32 file_id, @@ -943,7 +1111,8 @@ void CreateMTPDeviceAsyncDelegate( const std::string& device_location, + const bool read_only, const CreateMTPDeviceAsyncDelegateCallback& callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - callback.Run(new MTPDeviceDelegateImplLinux(device_location)); + callback.Run(new MTPDeviceDelegateImplLinux(device_location, read_only)); }
diff --git a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h index 0b9a7725..eba37039 100644 --- a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h +++ b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
@@ -32,6 +32,7 @@ private: friend void CreateMTPDeviceAsyncDelegate( const std::string&, + const bool read_only, const CreateMTPDeviceAsyncDelegateCallback&); enum InitializationState { @@ -66,7 +67,8 @@ // Should only be called by CreateMTPDeviceAsyncDelegate() factory call. // Defer the device initializations until the first file operation request. // Do all the initializations in EnsureInitAndRunTask() function. - explicit MTPDeviceDelegateImplLinux(const std::string& device_location); + MTPDeviceDelegateImplLinux(const std::string& device_location, + const bool read_only); // Destructed via CancelPendingTasksAndDeleteDelegate(). ~MTPDeviceDelegateImplLinux() override; @@ -90,6 +92,12 @@ int buf_len, const ReadBytesSuccessCallback& success_callback, const ErrorCallback& error_callback) override; + bool IsReadOnly() override; + void CopyFileFromLocal( + const base::FilePath& source_file_path, + const base::FilePath& device_file_path, + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback) override; void CancelPendingTasksAndDeleteDelegate() override; // The internal methods correspond to the similarly named methods above. @@ -112,6 +120,11 @@ net::IOBuffer* buf, int64 offset, int buf_len, const ReadBytesSuccessCallback& success_callback, const ErrorCallback& error_callback); + virtual void CopyFileFromLocalInternal( + const base::FilePath& device_file_path, + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback, + const int source_file_descriptor); // Ensures the device is initialized for communication. // If the device is already initialized, call RunTask(). @@ -222,6 +235,16 @@ // Called when FillFileCache() fails. void OnFillFileCacheFailed(base::File::Error error); + // Called when CopyFileFromLocal() succeeds. + void OnDidCopyFileFromLocal( + const CopyFileFromLocalSuccessCallback& success_callback, + const int source_file_descriptor); + + // Called when CopyFileFromLocal() fails. + void HandleCopyFileFromLocalError(const ErrorCallback& error_callback, + const int source_file_descriptor, + base::File::Error error); + // Handles the device file |error| while operating on |file_id|. // |error_callback| is invoked to notify the caller about the file error. void HandleDeviceFileError(const ErrorCallback& error_callback, @@ -257,6 +280,9 @@ // MTP device storage name (e.g. "usb:2,2:81282"). std::string storage_name_; + // Mode for opening storage. + const bool read_only_; + // A list of pending tasks that needs to be run when the device is // initialized or when the current task in progress is complete. std::deque<PendingTaskInfo> pending_tasks_;
diff --git a/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc b/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc index e19ce181..5fb766f 100644 --- a/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc +++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc
@@ -59,6 +59,7 @@ } void MTPDeviceTaskHelper::OpenStorage(const std::string& storage_name, + const bool read_only, const OpenStorageCallback& callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(!storage_name.empty()); @@ -68,11 +69,12 @@ base::Bind(callback, true)); return; } + + const std::string mode = + read_only ? mtpd::kReadOnlyMode : mtpd::kReadWriteMode; GetMediaTransferProtocolManager()->OpenStorage( - storage_name, mtpd::kReadOnlyMode, - base::Bind(&MTPDeviceTaskHelper::OnDidOpenStorage, - weak_ptr_factory_.GetWeakPtr(), - callback)); + storage_name, mode, base::Bind(&MTPDeviceTaskHelper::OnDidOpenStorage, + weak_ptr_factory_.GetWeakPtr(), callback)); } void MTPDeviceTaskHelper::GetFileInfo( @@ -136,6 +138,22 @@ weak_ptr_factory_.GetWeakPtr(), request)); } +void MTPDeviceTaskHelper::CopyFileFromLocal( + const std::string& storage_name, + const int source_file_descriptor, + const uint32 parent_id, + const std::string& file_name, + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + GetMediaTransferProtocolManager()->CopyFileFromLocal( + device_handle_, source_file_descriptor, parent_id, file_name, + base::Bind(&MTPDeviceTaskHelper::OnCopyFileFromLocal, + weak_ptr_factory_.GetWeakPtr(), success_callback, + error_callback)); +} + void MTPDeviceTaskHelper::CloseStorage() const { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (device_handle_.empty()) @@ -266,6 +284,22 @@ file_info, data.length())); } +void MTPDeviceTaskHelper::OnCopyFileFromLocal( + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback, + const bool error) const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (error) { + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(error_callback, base::File::FILE_ERROR_FAILED)); + return; + } + + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(success_callback)); +} + void MTPDeviceTaskHelper::HandleDeviceError( const ErrorCallback& error_callback, base::File::Error error) const {
diff --git a/chrome/browser/media_galleries/linux/mtp_device_task_helper.h b/chrome/browser/media_galleries/linux/mtp_device_task_helper.h index 31ac534..df284a12 100644 --- a/chrome/browser/media_galleries/linux/mtp_device_task_helper.h +++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper.h
@@ -36,6 +36,8 @@ typedef base::Callback<void(const storage::AsyncFileUtil::EntryList& entries, bool has_more)> ReadDirectorySuccessCallback; + typedef base::Closure CopyFileFromLocalSuccessCallback; + typedef MTPDeviceAsyncDelegate::ErrorCallback ErrorCallback; MTPDeviceTaskHelper(); @@ -48,6 +50,7 @@ // |callback| is called when the OpenStorage request completes. |callback| // runs on the IO thread. void OpenStorage(const std::string& storage_name, + const bool read_only, const OpenStorageCallback& callback); // Dispatches the GetFileInfo request to the MediaTransferProtocolManager. @@ -95,6 +98,15 @@ // called on the IO thread to notify the caller about success or failure. void ReadBytes(const MTPDeviceAsyncDelegate::ReadBytesRequest& request); + // Forwards CopyFileFromLocal request to the MediaTransferProtocolManager. + void CopyFileFromLocal( + const std::string& storage_name, + const int source_file_descriptor, + const uint32 parent_id, + const std::string& file_name, + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback); + // Dispatches the CloseStorage request to the MediaTransferProtocolManager. void CloseStorage() const; @@ -159,6 +171,13 @@ const std::string& data, bool error) const; + // Called when CopyFileFromLocal completed no matter if it succeeded or + // failed. + void OnCopyFileFromLocal( + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback, + const bool error) const; + // Called when the device is uninitialized. // // Runs |error_callback| on the IO thread to notify the caller about the
diff --git a/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.cc b/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.cc index ce923aa..dfa85e3 100644 --- a/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.cc +++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.cc
@@ -22,19 +22,25 @@ } MTPDeviceTaskHelper* MTPDeviceTaskHelperMapService::CreateDeviceTaskHelper( - const std::string& storage_name) { + const std::string& storage_name, + const bool read_only) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(!storage_name.empty()); - DCHECK(!ContainsKey(task_helper_map_, storage_name)); + const MTPDeviceTaskHelperKey key = + GetMTPDeviceTaskHelperKey(storage_name, read_only); + DCHECK(!ContainsKey(task_helper_map_, key)); MTPDeviceTaskHelper* task_helper = new MTPDeviceTaskHelper(); - task_helper_map_[storage_name] = task_helper; + task_helper_map_[key] = task_helper; return task_helper; } void MTPDeviceTaskHelperMapService::DestroyDeviceTaskHelper( - const std::string& storage_name) { + const std::string& storage_name, + const bool read_only) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - TaskHelperMap::iterator it = task_helper_map_.find(storage_name); + const MTPDeviceTaskHelperKey key = + GetMTPDeviceTaskHelperKey(storage_name, read_only); + TaskHelperMap::iterator it = task_helper_map_.find(key); if (it == task_helper_map_.end()) return; delete it->second; @@ -42,13 +48,25 @@ } MTPDeviceTaskHelper* MTPDeviceTaskHelperMapService::GetDeviceTaskHelper( - const std::string& storage_name) { + const std::string& storage_name, + const bool read_only) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(!storage_name.empty()); - TaskHelperMap::const_iterator it = task_helper_map_.find(storage_name); + const MTPDeviceTaskHelperKey key = + GetMTPDeviceTaskHelperKey(storage_name, read_only); + TaskHelperMap::const_iterator it = task_helper_map_.find(key); return (it != task_helper_map_.end()) ? it->second : NULL; } +// static +MTPDeviceTaskHelperMapService::MTPDeviceTaskHelperKey +MTPDeviceTaskHelperMapService::GetMTPDeviceTaskHelperKey( + const std::string& storage_name, + const bool read_only) { + return (read_only ? "ReadOnly" : "ReadWrite") + std::string("|") + + storage_name; +} + MTPDeviceTaskHelperMapService::MTPDeviceTaskHelperMapService() { }
diff --git a/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h b/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h index d13920c..6b02b094 100644 --- a/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h +++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h
@@ -20,25 +20,36 @@ // Creates and returns the MTPDeviceTaskHelper object for the storage device // specified by the |storage_name|. - MTPDeviceTaskHelper* CreateDeviceTaskHelper(const std::string& storage_name); + MTPDeviceTaskHelper* CreateDeviceTaskHelper(const std::string& storage_name, + const bool read_only); // Destroys the MTPDeviceTaskHelper object created by // CreateDeviceTaskHelper(). // |storage_name| specifies the name of the storage device. - void DestroyDeviceTaskHelper(const std::string& storage_name); + void DestroyDeviceTaskHelper(const std::string& storage_name, + const bool read_only); // Gets the MTPDeviceTaskHelper object associated with the device storage. // |storage_name| specifies the name of the storage device. // Return NULL if the |storage_name| is no longer valid (e.g. because the // corresponding storage device is detached, etc). - MTPDeviceTaskHelper* GetDeviceTaskHelper(const std::string& storage_name); + MTPDeviceTaskHelper* GetDeviceTaskHelper(const std::string& storage_name, + const bool read_only); private: friend struct base::DefaultLazyInstanceTraits<MTPDeviceTaskHelperMapService>; - // Key: Storage name. + // A key to be used in TaskHelperMap. + typedef std::string MTPDeviceTaskHelperKey; + + // Gets a key from |storage_name| and |read_only|. + static MTPDeviceTaskHelperKey GetMTPDeviceTaskHelperKey( + const std::string& storage_name, + const bool read_only); + + // Key: A combined value with storage_name and read_only. // Value: MTPDeviceTaskHelper object. - typedef std::map<std::string, MTPDeviceTaskHelper*> TaskHelperMap; + typedef std::map<MTPDeviceTaskHelperKey, MTPDeviceTaskHelper*> TaskHelperMap; // Get access to this class using GetInstance() method. MTPDeviceTaskHelperMapService();
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h index 0440fbd..f770834 100644 --- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h +++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h
@@ -54,6 +54,12 @@ int buf_len, const ReadBytesSuccessCallback& success_callback, const ErrorCallback& error_callback) override; + bool IsReadOnly() override; + void CopyFileFromLocal( + const base::FilePath& source_file_path, + const base::FilePath& device_file_path, + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback) override; void CancelPendingTasksAndDeleteDelegate() override; // Forward delegates for ImageCaptureDeviceListener. These are
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm index 9c54cc7..a8781bc 100644 --- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm +++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
@@ -209,6 +209,18 @@ NOTREACHED(); } +bool MTPDeviceDelegateImplMac::IsReadOnly() { + return true; +} + +void MTPDeviceDelegateImplMac::CopyFileFromLocal( + const base::FilePath& source_file_path, + const base::FilePath& device_file_path, + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback) { + NOTREACHED(); +} + void MTPDeviceDelegateImplMac::CancelPendingTasksAndDeleteDelegate() { content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, base::Bind(&MTPDeviceDelegateImplMac::CancelAndDelete, @@ -480,7 +492,11 @@ void CreateMTPDeviceAsyncDelegate( const base::FilePath::StringType& device_location, + const bool read_only, const CreateMTPDeviceAsyncDelegateCallback& cb) { + // Write operation is not supported on Mac. + DCHECK(read_only); + std::string device_name = base::FilePath(device_location).BaseName().value(); std::string device_id; storage_monitor::StorageInfo::Type type;
diff --git a/chrome/browser/media_galleries/media_file_system_registry.cc b/chrome/browser/media_galleries/media_file_system_registry.cc index a01845e6..85bd0954 100644 --- a/chrome/browser/media_galleries/media_file_system_registry.cc +++ b/chrome/browser/media_galleries/media_file_system_registry.cc
@@ -722,10 +722,11 @@ storage::FileSystemMountOption(), path); CHECK(result); - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind( - &MTPDeviceMapService::RegisterMTPFileSystem, - base::Unretained(MTPDeviceMapService::GetInstance()), - path.value(), fs_name)); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&MTPDeviceMapService::RegisterMTPFileSystem, + base::Unretained(MTPDeviceMapService::GetInstance()), + path.value(), fs_name, true /* read only */)); return result; }
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc index 21aa95e..5f1234c6 100644 --- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc +++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
@@ -315,8 +315,13 @@ void CreateMTPDeviceAsyncDelegate( const base::string16& device_location, + const bool read_only, const CreateMTPDeviceAsyncDelegateCallback& callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + // Write operation is not supported on Windows. + DCHECK(read_only); + DCHECK(!device_location.empty()); base::string16* pnp_device_id = new base::string16; base::string16* storage_object_id = new base::string16; @@ -456,6 +461,18 @@ NOTREACHED(); } +bool MTPDeviceDelegateImplWin::IsReadOnly() { + return true; +} + +void MTPDeviceDelegateImplWin::CopyFileFromLocal( + const base::FilePath& source_file_path, + const base::FilePath& device_file_path, + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback) { + NOTREACHED(); +} + void MTPDeviceDelegateImplWin::CancelPendingTasksAndDeleteDelegate() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); PortableDeviceMapService::GetInstance()->MarkPortableDeviceForDeletion(
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h index f1ca860..f0da938 100644 --- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h +++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h
@@ -110,6 +110,12 @@ int buf_len, const ReadBytesSuccessCallback& success_callback, const ErrorCallback& error_callback) override; + bool IsReadOnly() override; + void CopyFileFromLocal( + const base::FilePath& source_file_path, + const base::FilePath& device_file_path, + const CopyFileFromLocalSuccessCallback& success_callback, + const ErrorCallback& error_callback) override; virtual void CancelPendingTasksAndDeleteDelegate() override; // Ensures the device is initialized for communication by doing a
diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc index 19b3b16..7c91e9d4 100644 --- a/chrome/browser/notifications/desktop_notification_service.cc +++ b/chrome/browser/notifications/desktop_notification_service.cc
@@ -96,7 +96,7 @@ const PermissionRequestID& request_id, const GURL& requesting_origin, bool user_gesture, - const base::Callback<void(bool)>& result_callback) { + const BrowserPermissionCallback& result_callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); #if defined(ENABLE_EXTENSIONS) @@ -123,7 +123,7 @@ extensions::APIPermission::kNotifications, extension, web_contents->GetRenderViewHost())) { - result_callback.Run(true); + result_callback.Run(CONTENT_SETTING_ALLOW); return; } #endif @@ -245,8 +245,11 @@ void DesktopNotificationService::UpdateContentSetting( const GURL& requesting_origin, const GURL& embedder_origin, - bool allowed) { - if (allowed) { + ContentSetting content_setting) { + DCHECK(content_setting == CONTENT_SETTING_ALLOW || + content_setting == CONTENT_SETTING_BLOCK); + + if (content_setting == CONTENT_SETTING_ALLOW) { DesktopNotificationProfileUtil::GrantPermission( profile_, requesting_origin); } else {
diff --git a/chrome/browser/notifications/desktop_notification_service.h b/chrome/browser/notifications/desktop_notification_service.h index 0c7407f..8f1e167 100644 --- a/chrome/browser/notifications/desktop_notification_service.h +++ b/chrome/browser/notifications/desktop_notification_service.h
@@ -61,7 +61,7 @@ const PermissionRequestID& request_id, const GURL& requesting_origin, bool user_gesture, - const base::Callback<void(bool)>& result_callback); + const BrowserPermissionCallback& result_callback); // Returns true if the notifier with |notifier_id| is allowed to send // notifications. @@ -93,7 +93,7 @@ // PermissionContextBase: void UpdateContentSetting(const GURL& requesting_origin, const GURL& embedder_origin, - bool allowed) override; + ContentSetting content_setting) override; // The profile which owns this object. Profile* profile_;
diff --git a/chrome/browser/notifications/notification_ui_manager_android.cc b/chrome/browser/notifications/notification_ui_manager_android.cc index 656d2a2..62aa950 100644 --- a/chrome/browser/notifications/notification_ui_manager_android.cc +++ b/chrome/browser/notifications/notification_ui_manager_android.cc
@@ -219,6 +219,7 @@ const Notification& notification = iter->second->notification(); notification.delegate()->Close(true /** by_user **/); + RemoveProfileNotification(iter->second); return true; }
diff --git a/chrome/browser/notifications/platform_notification_service_impl.h b/chrome/browser/notifications/platform_notification_service_impl.h index 2c24843..85ef422 100644 --- a/chrome/browser/notifications/platform_notification_service_impl.h +++ b/chrome/browser/notifications/platform_notification_service_impl.h
@@ -75,7 +75,7 @@ friend struct DefaultSingletonTraits<PlatformNotificationServiceImpl>; friend class PlatformNotificationServiceBrowserTest; friend class PlatformNotificationServiceTest; - friend class gcm::PushMessagingBrowserTest; + friend class PushMessagingBrowserTest; FRIEND_TEST_ALL_PREFIXES( PlatformNotificationServiceTest, DisplayNameForOrigin); FRIEND_TEST_ALL_PREFIXES(PlatformNotificationServiceTest,
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc index e5d6c54..9f74eec7 100644 --- a/chrome/browser/password_manager/password_manager_browsertest.cc +++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -1615,3 +1615,48 @@ observer.Wait(); EXPECT_FALSE(prompt_observer->IsShowingPrompt()); } + +// Regression test for http://crbug.com/452306 +IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, + ChangingTextToPasswordFieldOnSignupForm) { + NavigateToFile("/password/signup_form.html"); + + // In this case, pretend that username_field is actually a password field + // that starts as a text field to simulate placeholder. + NavigationObserver observer(WebContents()); + scoped_ptr<PromptObserver> prompt_observer( + PromptObserver::Create(WebContents())); + std::string change_and_submit = + "document.getElementById('other_info').value = 'username';" + "document.getElementById('username_field').type = 'password';" + "document.getElementById('username_field').value = 'mypass';" + "document.getElementById('password_field').value = 'mypass';" + "document.getElementById('testform').submit();"; + ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), change_and_submit)); + observer.Wait(); + EXPECT_TRUE(prompt_observer->IsShowingPrompt()); +} + +// Regression test for http://crbug.com/451631 +IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, + SavingOnManyPasswordFieldsTest) { + // Simulate Macy's registration page, which contains the normal 2 password + // fields for confirming the new password plus 2 more fields for security + // questions and credit card. Make sure that saving works correctly for such + // sites. + NavigateToFile("/password/many_password_signup_form.html"); + + NavigationObserver observer(WebContents()); + scoped_ptr<PromptObserver> prompt_observer( + PromptObserver::Create(WebContents())); + std::string fill_and_submit = + "document.getElementById('username_field').value = 'username';" + "document.getElementById('password_field').value = 'mypass';" + "document.getElementById('confirm_field').value = 'mypass';" + "document.getElementById('security_answer').value = 'hometown';" + "document.getElementById('SSN').value = '1234';" + "document.getElementById('testform').submit();"; + ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit)); + observer.Wait(); + EXPECT_TRUE(prompt_observer->IsShowingPrompt()); +}
diff --git a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc index 5224eca8..96d9e07 100644 --- a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc +++ b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
@@ -148,6 +148,11 @@ POLICY_SCOPE_USER, new base::FundamentalValue(false), NULL); + policy_map->Set(key::kCaptivePortalAuthenticationIgnoresProxy, + POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, + new base::FundamentalValue(false), + NULL); #endif } @@ -189,6 +194,11 @@ POLICY_SCOPE_USER, new base::FundamentalValue(false), NULL); + expected->Set(key::kCaptivePortalAuthenticationIgnoresProxy, + POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, + new base::FundamentalValue(false), + NULL); #endif }
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 8735ec6..d5210e1 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -467,6 +467,9 @@ { key::kEasyUnlockAllowed, prefs::kEasyUnlockAllowed, base::Value::TYPE_BOOLEAN }, + { key::kCaptivePortalAuthenticationIgnoresProxy, + prefs::kCaptivePortalAuthenticationIgnoresProxy, + base::Value::TYPE_BOOLEAN }, #endif // defined(OS_CHROMEOS) #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index a913c1c9..73d9b85 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -55,9 +55,9 @@ #include "chrome/browser/profiles/profile_impl.h" #include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profiles_state.h" +#include "chrome/browser/push_messaging/push_messaging_service_impl.h" #include "chrome/browser/renderer_host/pepper/device_id_fetcher.h" #include "chrome/browser/search/search.h" -#include "chrome/browser/services/gcm/gcm_profile_service.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/task_manager/task_manager.h" #include "chrome/browser/ui/app_list/app_list_prefs.h" @@ -162,7 +162,6 @@ #include "chrome/browser/chromeos/extensions/echo_private_api.h" #include "chrome/browser/chromeos/file_system_provider/registry.h" #include "chrome/browser/chromeos/first_run/first_run.h" -#include "chrome/browser/chromeos/login/default_pinned_apps_field_trial.h" #include "chrome/browser/chromeos/login/saml/saml_offline_signin_limiter.h" #include "chrome/browser/chromeos/login/session/user_session_manager.h" #include "chrome/browser/chromeos/login/startup_utils.h" @@ -223,19 +222,6 @@ namespace { -enum MigratedPreferences { - NO_PREFS = 0, - DNS_PREFS = 1 << 0, - WINDOWS_PREFS = 1 << 1, -}; - -// A previous feature (see -// chrome/browser/protector/protected_prefs_watcher.cc in source -// control history) used this string as a prefix for various prefs it -// registered. We keep it here for now to clear out those old prefs in -// MigrateUserPrefs. -const char kBackupPref[] = "backup"; - #if !defined(OS_ANDROID) // The AutomaticProfileResetter service used this preference to save that the // profile reset prompt had already been shown, however, the preference has been @@ -250,8 +236,6 @@ namespace chrome { void RegisterLocalState(PrefRegistrySimple* registry) { - // Prefs in Local State. - registry->RegisterIntegerPref(prefs::kMultipleProfilePrefMigration, 0); // Please keep this list alphabetized. AppListService::RegisterPrefs(registry); @@ -328,7 +312,6 @@ chromeos::DataPromoNotification::RegisterPrefs(registry); chromeos::DeviceOAuth2TokenService::RegisterPrefs(registry); chromeos::device_settings_cache::RegisterPrefs(registry); - chromeos::default_pinned_apps_field_trial::RegisterPrefs(registry); chromeos::EnableDebuggingScreenHandler::RegisterPrefs(registry); chromeos::language_prefs::RegisterPrefs(registry); chromeos::KioskAppManager::RegisterPrefs(registry); @@ -398,7 +381,7 @@ dom_distiller::DistilledPagePrefs::RegisterProfilePrefs(registry); DownloadPrefs::RegisterProfilePrefs(registry); enhanced_bookmarks::BookmarkServerClusterService::RegisterPrefs(registry); - gcm::GCMProfileService::RegisterProfilePrefs(registry); + PushMessagingServiceImpl::RegisterProfilePrefs(registry); HostContentSettingsMap::RegisterProfilePrefs(registry); IncognitoModePrefs::RegisterProfilePrefs(registry); InstantUI::RegisterProfilePrefs(registry); @@ -528,13 +511,6 @@ #if defined(USE_ASH) ash::RegisterChromeLauncherUserPrefs(registry); #endif - - // Preferences registered only for migration (clearing or moving to a new key) - // go here. - registry->RegisterDictionaryPref( - kBackupPref, - new base::DictionaryValue(), - user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); } void RegisterUserProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { @@ -557,82 +533,47 @@ } #endif -void MigrateUserPrefs(Profile* profile) { - PrefService* prefs = profile->GetPrefs(); - - // Cleanup prefs from now-removed protector feature. - prefs->ClearPref(kBackupPref); +// This method should be periodically pruned of year+ old migrations. +void MigrateObsoleteBrowserPrefs(Profile* profile, PrefService* local_state) { +#if defined(TOOLKIT_VIEWS) + // Added 05/2014. + MigrateBrowserTabStripPrefs(local_state); +#endif #if !defined(OS_ANDROID) + // Added 08/2014. + local_state->ClearPref(kLegacyProfileResetPromptMemento); +#endif +} + +// This method should be periodically pruned of year+ old migrations. +void MigrateObsoleteProfilePrefs(Profile* profile) { + PrefService* profile_prefs = profile->GetPrefs(); + +#if defined(OS_MACOSX) && !defined(OS_IOS) + // Added 06/2014. + autofill::AutofillManager::MigrateUserPrefs(profile_prefs); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) + + // Added 07/2014. + translate::TranslatePrefs::MigrateUserPrefs(profile_prefs, + prefs::kAcceptLanguages); + +#if !defined(OS_ANDROID) + // Added 08/2014. // Migrate kNetworkPredictionEnabled to kNetworkPredictionOptions when not on // Android. On Android, platform-specific code performs preference migration. // TODO(bnc): https://crbug.com/401970 Remove migration code one year after // M38. - chrome_browser_net::MigrateNetworkPredictionUserPrefs(prefs); + chrome_browser_net::MigrateNetworkPredictionUserPrefs(profile_prefs); #endif - PromoResourceService::MigrateUserPrefs(prefs); - translate::TranslatePrefs::MigrateUserPrefs(prefs, prefs::kAcceptLanguages); - -#if defined(OS_MACOSX) && !defined(OS_IOS) - autofill::AutofillManager::MigrateUserPrefs(prefs); -#endif // defined(OS_MACOSX) && !defined(OS_IOS) - #if defined(OS_CHROMEOS) && defined(ENABLE_APP_LIST) + // Added 02/2015. MigrateGoogleNowPrefs(profile); #endif } -void MigrateBrowserPrefs(Profile* profile, PrefService* local_state) { - // Copy pref values which have been migrated to user_prefs from local_state, - // or remove them from local_state outright, if copying is not required. - int current_version = - local_state->GetInteger(prefs::kMultipleProfilePrefMigration); - PrefRegistrySimple* registry = static_cast<PrefRegistrySimple*>( - local_state->DeprecatedGetPrefRegistry()); - - if (!(current_version & DNS_PREFS)) { - registry->RegisterListPref(prefs::kDnsStartupPrefetchList); - local_state->ClearPref(prefs::kDnsStartupPrefetchList); - - registry->RegisterListPref(prefs::kDnsHostReferralList); - local_state->ClearPref(prefs::kDnsHostReferralList); - - current_version |= DNS_PREFS; - local_state->SetInteger(prefs::kMultipleProfilePrefMigration, - current_version); - } - - PrefService* user_prefs = profile->GetPrefs(); - if (!(current_version & WINDOWS_PREFS)) { - registry->RegisterDictionaryPref(prefs::kBrowserWindowPlacement); - if (local_state->HasPrefPath(prefs::kBrowserWindowPlacement)) { - const PrefService::Preference* pref = - local_state->FindPreference(prefs::kBrowserWindowPlacement); - DCHECK(pref); - user_prefs->Set(prefs::kBrowserWindowPlacement, - *(pref->GetValue())); - } - local_state->ClearPref(prefs::kBrowserWindowPlacement); - - current_version |= WINDOWS_PREFS; - local_state->SetInteger(prefs::kMultipleProfilePrefMigration, - current_version); - } - -#if !defined(OS_ANDROID) - local_state->ClearPref(kLegacyProfileResetPromptMemento); -#endif - -#if defined(OS_CHROMEOS) - chromeos::default_pinned_apps_field_trial::MigratePrefs(local_state); -#endif - -#if defined(TOOLKIT_VIEWS) - MigrateBrowserTabStripPrefs(local_state); -#endif -} - // As part of the migration from per-profile to per-partition HostZoomMaps, // we need to detect if an existing per-profile set of preferences exist, and // if so convert them to be per-partition. We migrate any per-profile zoom
diff --git a/chrome/browser/prefs/browser_prefs.h b/chrome/browser/prefs/browser_prefs.h index 9fa2829..122ebe49 100644 --- a/chrome/browser/prefs/browser_prefs.h +++ b/chrome/browser/prefs/browser_prefs.h
@@ -30,11 +30,17 @@ void RegisterLoginProfilePrefs(user_prefs::PrefRegistrySyncable* registry); #endif -// Migrates prefs from |local_state| to |profile|'s pref store. -void MigrateBrowserPrefs(Profile* profile, PrefService* local_state); +// Migrate/cleanup deprecated prefs in |local_state|. Over time, long deprecated +// prefs should be removed as new ones are added, but this call should never go +// away (even if it becomes an empty call for some time) as it should remain +// *the* place to drop deprecated browser prefs at. +void MigrateObsoleteBrowserPrefs(Profile* profile, PrefService* local_state); -// Migrates prefs in |profile|'s pref store. -void MigrateUserPrefs(Profile* profile); +// Migrate/cleanup deprecated prefs in |profile|'s pref store. Over time, long +// deprecated prefs should be removed as new ones are added, but this call +// should never go away (even if it becomes an empty call for some time) as it +// should remain *the* place to drop deprecated profile prefs at. +void MigrateObsoleteProfilePrefs(Profile* profile); // Migrates zoom level prefs in |profile|'s pref store to a per-StoragePartition // set of prefs.
diff --git a/chrome/browser/prefs/leveldb_pref_store.cc b/chrome/browser/prefs/leveldb_pref_store.cc index 86666b1..f397b08 100644 --- a/chrome/browser/prefs/leveldb_pref_store.cc +++ b/chrome/browser/prefs/leveldb_pref_store.cc
@@ -167,7 +167,7 @@ // TODO(dgrogan): Is it really necessary to check it->status() each iteration? for (it->SeekToFirst(); it->Valid() && it->status().ok(); it->Next()) { const std::string value_string = it->value().ToString(); - JSONStringValueSerializer deserializer(value_string); + JSONStringValueDeserializer deserializer(value_string); std::string error_message; int error_code; base::Value* json_value =
diff --git a/chrome/browser/prefs/pref_service_browsertest.cc b/chrome/browser/prefs/pref_service_browsertest.cc index ba72e21..47e1007 100644 --- a/chrome/browser/prefs/pref_service_browsertest.cc +++ b/chrome/browser/prefs/pref_service_browsertest.cc
@@ -52,41 +52,29 @@ class PreferenceServiceTest : public InProcessBrowserTest { public: - explicit PreferenceServiceTest(bool new_profile) : new_profile_(new_profile) { - } - bool SetUpUserDataDirectory() override { base::FilePath user_data_directory; PathService::Get(chrome::DIR_USER_DATA, &user_data_directory); - if (new_profile_) { - original_pref_file_ = ui_test_utils::GetTestFilePath( - base::FilePath().AppendASCII("profiles"). - AppendASCII("window_placement"). - AppendASCII("Default"), - base::FilePath().Append(chrome::kPreferencesFilename)); - tmp_pref_file_ = - user_data_directory.AppendASCII(TestingProfile::kTestUserProfileDir); - CHECK(base::CreateDirectory(tmp_pref_file_)); - tmp_pref_file_ = tmp_pref_file_.Append(chrome::kPreferencesFilename); - } else { - original_pref_file_ = ui_test_utils::GetTestFilePath( - base::FilePath().AppendASCII("profiles"). - AppendASCII("window_placement"), - base::FilePath().Append(chrome::kLocalStateFilename)); - tmp_pref_file_ = user_data_directory.Append(chrome::kLocalStateFilename); - } + original_pref_file_ = ui_test_utils::GetTestFilePath( + base::FilePath() + .AppendASCII("profiles") + .AppendASCII("window_placement") + .AppendASCII("Default"), + base::FilePath().Append(chrome::kPreferencesFilename)); + tmp_pref_file_ = + user_data_directory.AppendASCII(TestingProfile::kTestUserProfileDir); + EXPECT_TRUE(base::CreateDirectory(tmp_pref_file_)); + tmp_pref_file_ = tmp_pref_file_.Append(chrome::kPreferencesFilename); - CHECK(base::PathExists(original_pref_file_)); - // Copy only the Preferences file if |new_profile_|, or Local State if not, - // and the rest will be automatically created. - CHECK(base::CopyFile(original_pref_file_, tmp_pref_file_)); + EXPECT_TRUE(base::PathExists(original_pref_file_)); + EXPECT_TRUE(base::CopyFile(original_pref_file_, tmp_pref_file_)); #if defined(OS_WIN) // Make the copy writable. On POSIX we assume the umask allows files // we create to be writable. - CHECK(::SetFileAttributesW(tmp_pref_file_.value().c_str(), - FILE_ATTRIBUTE_NORMAL)); + EXPECT_TRUE(::SetFileAttributesW(tmp_pref_file_.value().c_str(), + FILE_ATTRIBUTE_NORMAL)); #endif return true; } @@ -94,9 +82,6 @@ protected: base::FilePath original_pref_file_; base::FilePath tmp_pref_file_; - - private: - bool new_profile_; }; #if defined(OS_WIN) || defined(OS_MACOSX) @@ -106,13 +91,7 @@ // might be able to make this work on buildbots. // TODO(port): revisit this. -class PreservedWindowPlacementIsLoaded : public PreferenceServiceTest { - public: - PreservedWindowPlacementIsLoaded() : PreferenceServiceTest(true) { - } -}; - -IN_PROC_BROWSER_TEST_F(PreservedWindowPlacementIsLoaded, Test) { +IN_PROC_BROWSER_TEST_F(PreferenceServiceTest, Test) { #if defined(OS_WIN) && defined(USE_ASH) // Disable this test in Metro+Ash for now (http://crbug.com/262796). if (base::CommandLine::ForCurrentProcess()->HasSwitch( @@ -122,7 +101,7 @@ // The window should open with the new reference profile, with window // placement values stored in the user data directory. - JSONFileValueSerializer deserializer(original_pref_file_); + JSONFileValueDeserializer deserializer(original_pref_file_); scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, NULL)); ASSERT_TRUE(root.get()); @@ -164,69 +143,3 @@ EXPECT_EQ(is_maximized, is_window_maximized); } #endif - -#if defined(OS_WIN) || defined(OS_MACOSX) - -class PreservedWindowPlacementIsMigrated : public PreferenceServiceTest { - public: - PreservedWindowPlacementIsMigrated() : PreferenceServiceTest(false) { - } -}; - -IN_PROC_BROWSER_TEST_F(PreservedWindowPlacementIsMigrated, Test) { -#if defined(OS_WIN) && defined(USE_ASH) - // Disable this test in Metro+Ash for now (http://crbug.com/262796). - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshBrowserTests)) - return; -#endif - - // The window should open with the old reference profile, with window - // placement values stored in Local State. - - JSONFileValueSerializer deserializer(original_pref_file_); - scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, NULL)); - - ASSERT_TRUE(root.get()); - ASSERT_TRUE(root->IsType(base::Value::TYPE_DICTIONARY)); - - // Retrieve the screen rect for the launched window - gfx::Rect bounds = browser()->window()->GetRestoredBounds(); - - // Values from old reference profile in Local State should have been - // correctly migrated to the user's Preferences -- if so, the window - // should be set to values taken from the user's Local State. - base::DictionaryValue* root_dict = - static_cast<base::DictionaryValue*>(root.get()); - - // Retrieve the expected rect values from User Preferences, where they - // should have been migrated from Local State. - int bottom = 0; - std::string kBrowserWindowPlacement(prefs::kBrowserWindowPlacement); - EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + ".bottom", - &bottom)); - EXPECT_EQ(bottom, bounds.y() + bounds.height()); - - int top = 0; - EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + ".top", - &top)); - EXPECT_EQ(top, bounds.y()); - - int left = 0; - EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + ".left", - &left)); - EXPECT_EQ(left, bounds.x()); - - int right = 0; - EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + ".right", - &right)); - EXPECT_EQ(right, bounds.x() + bounds.width()); - - // Find if launched window is maximized. - bool is_window_maximized = browser()->window()->IsMaximized(); - bool is_maximized = false; - EXPECT_TRUE(root_dict->GetBoolean(kBrowserWindowPlacement + ".maximized", - &is_maximized)); - EXPECT_EQ(is_maximized, is_window_maximized); -} -#endif
diff --git a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc index 5a8e5ce..3608606 100644 --- a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc +++ b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
@@ -85,12 +85,12 @@ scoped_ptr<base::DictionaryValue> ReadPrefsDictionary( const base::FilePath& pref_file) { - JSONFileValueSerializer serializer(pref_file); - int error_code = JSONFileValueSerializer::JSON_NO_ERROR; + JSONFileValueDeserializer deserializer(pref_file); + int error_code = JSONFileValueDeserializer::JSON_NO_ERROR; std::string error_str; scoped_ptr<base::Value> prefs( - serializer.Deserialize(&error_code, &error_str)); - if (!prefs || error_code != JSONFileValueSerializer::JSON_NO_ERROR) { + deserializer.Deserialize(&error_code, &error_str)); + if (!prefs || error_code != JSONFileValueDeserializer::JSON_NO_ERROR) { ADD_FAILURE() << "Error #" << error_code << ": " << error_str; return scoped_ptr<base::DictionaryValue>(); }
diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc index 63a0c48..439dfb2 100644 --- a/chrome/browser/process_singleton_win.cc +++ b/chrome/browser/process_singleton_win.cc
@@ -11,6 +11,7 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "base/process/kill.h" +#include "base/process/process.h" #include "base/process/process_info.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" @@ -266,6 +267,7 @@ remote_window_ = NULL; return PROCESS_NONE; } + base::Process process = base::Process::Open(process_id); // The window is hung. Scan for every window to find a visible one. bool visible_window = false; @@ -285,7 +287,7 @@ } // Time to take action. Kill the browser process. - base::KillProcessById(process_id, content::RESULT_CODE_HUNG, true); + base::KillProcess(process.Handle(), content::RESULT_CODE_HUNG, true); remote_window_ = NULL; return PROCESS_NONE; }
diff --git a/chrome/browser/profile_resetter/brandcoded_default_settings.cc b/chrome/browser/profile_resetter/brandcoded_default_settings.cc index 7d7f2cc..20145fb 100644 --- a/chrome/browser/profile_resetter/brandcoded_default_settings.cc +++ b/chrome/browser/profile_resetter/brandcoded_default_settings.cc
@@ -16,7 +16,7 @@ BrandcodedDefaultSettings::BrandcodedDefaultSettings(const std::string& prefs) { if (!prefs.empty()) { - JSONStringValueSerializer json(prefs); + JSONStringValueDeserializer json(prefs); std::string error; scoped_ptr<base::Value> root(json.Deserialize(NULL, &error)); if (!root.get()) {
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc index 7baa510af..3804d1d 100644 --- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc +++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -960,7 +960,7 @@ for (int field_mask = 0; field_mask <= ResettableSettingsSnapshot::ALL_FIELDS; ++field_mask) { std::string report = SerializeSettingsReport(nonorganic_snap, field_mask); - JSONStringValueSerializer json(report); + JSONStringValueDeserializer json(report); std::string error; scoped_ptr<base::Value> root(json.Deserialize(NULL, &error)); ASSERT_TRUE(root) << error;
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc index e998faf..d78b314 100644 --- a/chrome/browser/profiles/off_the_record_profile_impl.cc +++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -80,6 +80,12 @@ #include "extensions/common/extension.h" #endif +#if defined(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/content_settings/content_settings_supervised_provider.h" +#include "chrome/browser/supervised_user/supervised_user_settings_service.h" +#include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h" +#endif + using content::BrowserThread; using content::DownloadManagerDelegate; using content::HostZoomMap; @@ -392,6 +398,15 @@ host_content_settings_map_.get()); } #endif +#if defined(ENABLE_SUPERVISED_USERS) + SupervisedUserSettingsService* supervised_service = + SupervisedUserSettingsServiceFactory::GetForProfile(this); + scoped_ptr<content_settings::SupervisedProvider> supervised_provider( + new content_settings::SupervisedProvider(supervised_service)); + host_content_settings_map_->RegisterProvider( + HostContentSettingsMap::SUPERVISED_PROVIDER, + supervised_provider.Pass()); +#endif } return host_content_settings_map_.get(); }
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index 9b7389f..aa365dd 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc
@@ -60,10 +60,10 @@ #include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_metrics.h" +#include "chrome/browser/push_messaging/push_messaging_service_factory.h" +#include "chrome/browser/push_messaging/push_messaging_service_impl.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/services/gcm/gcm_profile_service.h" -#include "chrome/browser/services/gcm/gcm_profile_service_factory.h" -#include "chrome/browser/services/gcm/push_messaging_service_impl.h" #include "chrome/browser/sessions/session_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/signin/signin_ui_util.h" @@ -143,6 +143,7 @@ #endif #if defined(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/content_settings/content_settings_supervised_provider.h" #include "chrome/browser/supervised_user/supervised_user_constants.h" #include "chrome/browser/supervised_user/supervised_user_settings_service.h" #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h" @@ -475,7 +476,7 @@ BrowserContextDependencyManager::GetInstance()-> RegisterProfilePrefsForServices(this, pref_registry_.get()); - SupervisedUserSettingsService* supervised_user_settings = NULL; + SupervisedUserSettingsService* supervised_user_settings = nullptr; #if defined(ENABLE_SUPERVISED_USERS) supervised_user_settings = SupervisedUserSettingsServiceFactory::GetForProfile(this); @@ -691,7 +692,7 @@ model->AddObserver(new BookmarkModelLoadedObserver(this)); #endif - gcm::PushMessagingServiceImpl::InitializeForProfile(this); + PushMessagingServiceImpl::InitializeForProfile(this); #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) && !defined(OS_IOS) signin_ui_util::InitializePrefsForProfile(this); @@ -851,11 +852,10 @@ return; } - // TODO(mirandac): remove migration code after 6 months (crbug.com/69995). + // Migrate obsolete prefs. if (g_browser_process->local_state()) - chrome::MigrateBrowserPrefs(this, g_browser_process->local_state()); - // TODO(ivankr): remove cleanup code eventually (crbug.com/165672). - chrome::MigrateUserPrefs(this); + chrome::MigrateObsoleteBrowserPrefs(this, g_browser_process->local_state()); + chrome::MigrateObsoleteProfilePrefs(this); // |kSessionExitType| was added after |kSessionExitedCleanly|. If the pref // value is empty fallback to checking for |kSessionExitedCleanly|. @@ -1041,6 +1041,15 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!host_content_settings_map_.get()) { host_content_settings_map_ = new HostContentSettingsMap(GetPrefs(), false); +#if defined(ENABLE_SUPERVISED_USERS) + SupervisedUserSettingsService* supervised_user_settings = + SupervisedUserSettingsServiceFactory::GetForProfile(this); + scoped_ptr<content_settings::SupervisedProvider> supervised_provider( + new content_settings::SupervisedProvider(supervised_user_settings)); + host_content_settings_map_->RegisterProvider( + HostContentSettingsMap::SUPERVISED_PROVIDER, + supervised_provider.Pass()); +#endif } return host_content_settings_map_.get(); } @@ -1067,8 +1076,7 @@ } content::PushMessagingService* ProfileImpl::GetPushMessagingService() { - return gcm::GCMProfileServiceFactory::GetForProfile( - this)->push_messaging_service(); + return PushMessagingServiceFactory::GetForProfile(this); } content::SSLHostStateDelegate* ProfileImpl::GetSSLHostStateDelegate() {
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index 36ee8e3d..7d3f1fb 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc
@@ -558,8 +558,8 @@ Profile* ProfileManager::GetProfileByPath(const base::FilePath& path) const { TRACE_EVENT0("browser", "ProfileManager::GetProfileByPath"); ProfileInfo* profile_info = GetProfileInfoByPath(path); - return profile_info && profile_info->created ? profile_info->profile.get() - : nullptr; + return (profile_info && profile_info->created) ? profile_info->profile.get() + : nullptr; } // static @@ -650,7 +650,6 @@ service->CancelDownloads(); } - PrefService* local_state = g_browser_process->local_state(); ProfileInfoCache& cache = GetProfileInfoCache(); // If we're deleting the last (non-legacy-supervised) profile, then create a @@ -682,51 +681,42 @@ new_path = GenerateNextProfileDirectoryPath(); CreateProfileAsync(new_path, - callback, + base::Bind(&ProfileManager::OnNewActiveProfileLoaded, + base::Unretained(this), + profile_dir, + new_path, + callback), new_profile_name, new_avatar_url, std::string()); ProfileMetrics::LogProfileAddNewUser( ProfileMetrics::ADD_NEW_USER_LAST_DELETED); + return; } - // Update the last used profile pref before closing browser windows. This - // way the correct last used profile is set for any notification observers. +#if defined(OS_MACOSX) + // On the Mac, the browser process is not killed when all browser windows are + // closed, so just in case we are deleting the active profile, and no other + // profile has been loaded, we must pre-load a next one. const std::string last_used_profile = - local_state->GetString(prefs::kProfileLastUsed); + g_browser_process->local_state()->GetString(prefs::kProfileLastUsed); if (last_used_profile == profile_dir.BaseName().MaybeAsASCII() || last_used_profile == GetGuestProfilePath().BaseName().MaybeAsASCII()) { - const std::string last_non_supervised_profile = - last_non_supervised_profile_path.BaseName().MaybeAsASCII(); - if (last_non_supervised_profile.empty()) { - DCHECK(!new_path.empty()); - local_state->SetString(prefs::kProfileLastUsed, - new_path.BaseName().MaybeAsASCII()); - } else { - // On the Mac, the browser process is not killed when all browser windows - // are closed, so just in case we are deleting the active profile, and no - // other profile has been loaded, we must pre-load a next one. -#if defined(OS_MACOSX) - CreateProfileAsync(last_non_supervised_profile_path, - base::Bind(&ProfileManager::OnNewActiveProfileLoaded, - base::Unretained(this), - profile_dir, - last_non_supervised_profile_path, - callback), - base::string16(), - base::string16(), - std::string()); - return; -#else - // For OS_MACOSX the pref is updated in the callback to make sure that - // it isn't used before the profile is actually loaded. - local_state->SetString(prefs::kProfileLastUsed, - last_non_supervised_profile); -#endif - } + CreateProfileAsync(last_non_supervised_profile_path, + base::Bind(&ProfileManager::OnNewActiveProfileLoaded, + base::Unretained(this), + profile_dir, + last_non_supervised_profile_path, + callback), + base::string16(), + base::string16(), + std::string()); + return; } - FinishDeletingProfile(profile_dir); +#endif // defined(OS_MACOSX) + + FinishDeletingProfile(profile_dir, last_non_supervised_profile_path); } // static @@ -1160,7 +1150,15 @@ return profile; } -void ProfileManager::FinishDeletingProfile(const base::FilePath& profile_dir) { +void ProfileManager::FinishDeletingProfile( + const base::FilePath& profile_dir, + const base::FilePath& new_active_profile_dir) { + // Update the last used profile pref before closing browser windows. This + // way the correct last used profile is set for any notification observers. + g_browser_process->local_state()->SetString( + prefs::kProfileLastUsed, + new_active_profile_dir.BaseName().MaybeAsASCII()); + ProfileInfoCache& cache = GetProfileInfoCache(); // TODO(sail): Due to bug 88586 we don't delete the profile instance. Once we // start deleting the profile instance we need to close background apps too. @@ -1372,10 +1370,9 @@ } #endif // !defined(OS_ANDROID) && !defined(OS_IOS) -#if defined(OS_MACOSX) void ProfileManager::OnNewActiveProfileLoaded( const base::FilePath& profile_to_delete_path, - const base::FilePath& last_non_supervised_profile_path, + const base::FilePath& new_active_profile_path, const CreateCallback& original_callback, Profile* loaded_profile, Profile::CreateStatus status) { @@ -1383,22 +1380,21 @@ status != Profile::CREATE_STATUS_REMOTE_FAIL); // Only run the code if the profile initialization has finished completely. - if (status == Profile::CREATE_STATUS_INITIALIZED) { - if (IsProfileMarkedForDeletion(last_non_supervised_profile_path)) { - // If the profile we tried to load as the next active profile has been - // deleted, then retry deleting this profile to redo the logic to load - // the next available profile. - ScheduleProfileForDeletion(profile_to_delete_path, original_callback); - } else { - // Update the local state as promised in the ScheduleProfileForDeletion. - g_browser_process->local_state()->SetString( - prefs::kProfileLastUsed, - last_non_supervised_profile_path.BaseName().MaybeAsASCII()); - FinishDeletingProfile(profile_to_delete_path); - } + if (status != Profile::CREATE_STATUS_INITIALIZED) + return; + + if (IsProfileMarkedForDeletion(new_active_profile_path)) { + // If the profile we tried to load as the next active profile has been + // deleted, then retry deleting this profile to redo the logic to load + // the next available profile. + ScheduleProfileForDeletion(profile_to_delete_path, original_callback); + return; } + + FinishDeletingProfile(profile_to_delete_path, new_active_profile_path); + if (!original_callback.is_null()) + original_callback.Run(loaded_profile, status); } -#endif ProfileManagerWithoutInit::ProfileManagerWithoutInit( const base::FilePath& user_data_dir) : ProfileManager(user_data_dir) {
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h index ff28e3d1..9436a459e 100644 --- a/chrome/browser/profiles/profile_manager.h +++ b/chrome/browser/profiles/profile_manager.h
@@ -265,8 +265,10 @@ // creation and adds it to the set managed by this ProfileManager. Profile* CreateAndInitializeProfile(const base::FilePath& profile_dir); - // Schedules the profile at the given path to be deleted on shutdown. - void FinishDeletingProfile(const base::FilePath& profile_dir); + // Schedules the profile at the given path to be deleted on shutdown, + // and marks the new profile as active. + void FinishDeletingProfile(const base::FilePath& profile_dir, + const base::FilePath& new_active_profile_dir); // Registers profile with given info. Returns pointer to created ProfileInfo // entry. @@ -317,7 +319,6 @@ }; #endif // !defined(OS_ANDROID) && !defined(OS_IOS) -#if defined(OS_MACOSX) // If the |loaded_profile| has been loaded successfully (according to // |status|) and isn't already scheduled for deletion, then finishes adding // |profile_to_delete_dir| to the queue of profiles to be deleted, and updates @@ -329,7 +330,6 @@ const CreateCallback& original_callback, Profile* loaded_profile, Profile::CreateStatus status); -#endif content::NotificationRegistrar registrar_;
diff --git a/chrome/browser/profiles/profile_manager_browsertest.cc b/chrome/browser/profiles/profile_manager_browsertest.cc index 820eb18..43df0d4b 100644 --- a/chrome/browser/profiles/profile_manager_browsertest.cc +++ b/chrome/browser/profiles/profile_manager_browsertest.cc
@@ -40,10 +40,11 @@ // An observer that returns back to test code after a new profile is // initialized. -void OnUnblockOnProfileCreation(Profile* profile, +void OnUnblockOnProfileCreation(base::RunLoop* run_loop, + Profile* profile, Profile::CreateStatus status) { if (status == Profile::CREATE_STATUS_INITIALIZED) - base::MessageLoop::current()->Quit(); + run_loop->Quit(); } void ProfileCreationComplete(Profile* profile, Profile::CreateStatus status) { @@ -91,26 +92,26 @@ // The class serves to retrieve passwords from PasswordStore asynchronously. It // used by ProfileManagerBrowserTest.DeletePasswords on some platforms. -class PasswordStoreConsumerVerifier : - public password_manager::PasswordStoreConsumer { +class PasswordStoreConsumerVerifier + : public password_manager::PasswordStoreConsumer { public: - PasswordStoreConsumerVerifier() : called_(false) {} - void OnGetPasswordStoreResults( ScopedVector<autofill::PasswordForm> results) override { - EXPECT_FALSE(called_); - called_ = true; password_entries_.swap(results); + run_loop_.Quit(); } - bool IsCalled() const { return called_; } + void Wait() { + run_loop_.Run(); + } const std::vector<autofill::PasswordForm*>& GetPasswords() const { return password_entries_.get(); } + private: + base::RunLoop run_loop_; ScopedVector<autofill::PasswordForm> password_entries_; - bool called_; }; static base::FilePath GetFirstNonSigninProfile(const ProfileInfoCache& cache) { @@ -160,20 +161,23 @@ // Delete singleton profile. base::FilePath singleton_profile_path = cache.GetPathOfProfileAtIndex(0); EXPECT_FALSE(singleton_profile_path.empty()); - profile_manager->ScheduleProfileForDeletion(singleton_profile_path, - ProfileManager::CreateCallback()); + base::RunLoop run_loop; + profile_manager->ScheduleProfileForDeletion( + singleton_profile_path, + base::Bind(&OnUnblockOnProfileCreation, &run_loop)); - // Spin things till profile is actually deleted. - content::RunAllPendingInMessageLoop(); + // Run the message loop until the profile is actually deleted (as indicated + // by the callback above being called). + run_loop.Run(); // Make sure a new profile was created automatically. EXPECT_EQ(cache.GetNumberOfProfiles(), 1U); base::FilePath new_profile_path = cache.GetPathOfProfileAtIndex(0); - EXPECT_NE(new_profile_path, singleton_profile_path); + EXPECT_NE(new_profile_path.value(), singleton_profile_path.value()); // Make sure that last used profile preference is set correctly. Profile* last_used = ProfileManager::GetLastUsedProfile(); - EXPECT_EQ(new_profile_path, last_used->GetPath()); + EXPECT_EQ(new_profile_path.value(), last_used->GetPath().value()); // Make sure the last used profile was set correctly before the notification // was sent. @@ -191,14 +195,14 @@ // Create an additional profile. base::FilePath new_path = profile_manager->GenerateNextProfileDirectoryPath(); - profile_manager->CreateProfileAsync(new_path, - base::Bind(&OnUnblockOnProfileCreation), - base::string16(), base::string16(), - std::string()); + base::RunLoop run_loop; + profile_manager->CreateProfileAsync( + new_path, base::Bind(&OnUnblockOnProfileCreation, &run_loop), + base::string16(), base::string16(), std::string()); - // Spin to allow profile creation to take place, loop is terminated - // by OnUnblockOnProfileCreation when the profile is created. - content::RunMessageLoop(); + // Run the message loop to allow profile creation to take place; the loop is + // terminated by OnUnblockOnProfileCreation when the profile is created. + run_loop.Run(); ASSERT_EQ(cache.GetNumberOfProfiles(), 2U); @@ -306,14 +310,14 @@ // Create an additional profile. base::FilePath path_profile2 = profile_manager->GenerateNextProfileDirectoryPath(); - profile_manager->CreateProfileAsync(path_profile2, - base::Bind(&OnUnblockOnProfileCreation), - base::string16(), base::string16(), - std::string()); + base::RunLoop run_loop; + profile_manager->CreateProfileAsync( + path_profile2, base::Bind(&OnUnblockOnProfileCreation, &run_loop), + base::string16(), base::string16(), std::string()); - // Spin to allow profile creation to take place, loop is terminated - // by OnUnblockOnProfileCreation when the profile is created. - content::RunMessageLoop(); + // Run the message loop to allow profile creation to take place; the loop is + // terminated by OnUnblockOnProfileCreation when the profile is created. + run_loop.Run(); chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop(); BrowserList* browser_list = BrowserList::GetInstance(desktop_type); @@ -445,27 +449,18 @@ password_store->AddLogin(form); PasswordStoreConsumerVerifier verify_add; password_store->GetAutofillableLogins(&verify_add); + verify_add.Wait(); + EXPECT_EQ(1u, verify_add.GetPasswords().size()); ProfileManager* profile_manager = g_browser_process->profile_manager(); - profile_manager->ScheduleProfileForDeletion(profile->GetPath(), - ProfileManager::CreateCallback()); - content::RunAllPendingInMessageLoop(); - PasswordStoreConsumerVerifier verify_delete; - password_store->GetAutofillableLogins(&verify_delete); - - // Run the password background thread. base::RunLoop run_loop; - base::Closure task = base::Bind( - base::IgnoreResult(&content::BrowserThread::PostTask), - content::BrowserThread::UI, - FROM_HERE, - run_loop.QuitClosure()); - EXPECT_TRUE(password_store->ScheduleTask(task)); + profile_manager->ScheduleProfileForDeletion( + profile->GetPath(), base::Bind(&OnUnblockOnProfileCreation, &run_loop)); run_loop.Run(); - EXPECT_TRUE(verify_add.IsCalled()); - EXPECT_EQ(1u, verify_add.GetPasswords().size()); - EXPECT_TRUE(verify_delete.IsCalled()); + PasswordStoreConsumerVerifier verify_delete; + password_store->GetAutofillableLogins(&verify_delete); + verify_delete.Wait(); EXPECT_EQ(0u, verify_delete.GetPasswords().size()); } #endif // !defined(OS_WIN) && !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
diff --git a/chrome/browser/push_messaging/OWNERS b/chrome/browser/push_messaging/OWNERS new file mode 100644 index 0000000..7783e23f --- /dev/null +++ b/chrome/browser/push_messaging/OWNERS
@@ -0,0 +1,3 @@ +johnme@chromium.org +mvanouwerkerk@chromium.org +peter@chromium.org
diff --git a/chrome/browser/push_messaging/push_messaging_application_id.cc b/chrome/browser/push_messaging/push_messaging_application_id.cc new file mode 100644 index 0000000..c6b30e7 --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_application_id.cc
@@ -0,0 +1,168 @@ +// 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/push_messaging/push_messaging_application_id.h" + +#include "base/guid.h" +#include "base/logging.h" +#include "base/prefs/pref_service.h" +#include "base/prefs/scoped_user_pref_update.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "base/values.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/pref_names.h" +#include "components/pref_registry/pref_registry_syncable.h" + +namespace { +const char kSeparator = '#'; // Ok as only the origin of the url is used. +} // namespace + +const char kPushMessagingApplicationIdPrefix[] = "wp:"; + +// static +void PushMessagingApplicationId::RegisterProfilePrefs( + user_prefs::PrefRegistrySyncable* registry) { + registry->RegisterDictionaryPref( + prefs::kPushMessagingApplicationIdMap, + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); +} + +// static +PushMessagingApplicationId PushMessagingApplicationId::Generate( + const GURL& origin, int64 service_worker_registration_id) +{ + // TODO(johnme): Does GenerateGUID produce good enough random numbers? + std::string guid = base::GenerateGUID(); + CHECK(!guid.empty()); + std::string app_id_guid = + kPushMessagingApplicationIdPrefix + guid; + + PushMessagingApplicationId application_id(app_id_guid, origin, + service_worker_registration_id); + DCHECK(application_id.IsValid()); + return application_id; +} + +// static +PushMessagingApplicationId PushMessagingApplicationId::Get( + Profile* profile, const std::string& app_id_guid) { + // Workaround crbug.com/461867 in GCM where it converts subtypes to lowercase. + // TODO(johnme): Remove this when obsolete + const size_t prefix_len = strlen(kPushMessagingApplicationIdPrefix); + if (app_id_guid.size() < prefix_len) + return PushMessagingApplicationId(); + std::string uppercase_app_id = + app_id_guid.substr(0, prefix_len) + + StringToUpperASCII(app_id_guid.substr(prefix_len, std::string::npos)); + + const base::DictionaryValue* map = + profile->GetPrefs()->GetDictionary(prefs::kPushMessagingApplicationIdMap); + + std::string origin_and_sw_id; + if (!map->GetStringWithoutPathExpansion(uppercase_app_id, &origin_and_sw_id)) + return PushMessagingApplicationId(); + + std::vector<std::string> parts; + base::SplitString(origin_and_sw_id, kSeparator, &parts); + if (parts.size() != 2) + return PushMessagingApplicationId(); + + GURL origin = GURL(parts[0]); + + int64 service_worker_registration_id; + if (!base::StringToInt64(parts[1], &service_worker_registration_id)) + return PushMessagingApplicationId(); + + PushMessagingApplicationId application_id(uppercase_app_id, origin, + service_worker_registration_id); + DCHECK(application_id.IsValid()); + return application_id; +} + +// static +PushMessagingApplicationId PushMessagingApplicationId::Get( + Profile* profile, const GURL& origin, int64 service_worker_registration_id) +{ + base::StringValue origin_and_sw_id = base::StringValue(origin.spec() + + kSeparator + base::Int64ToString(service_worker_registration_id)); + + const base::DictionaryValue* map = + profile->GetPrefs()->GetDictionary(prefs::kPushMessagingApplicationIdMap); + for (auto it = base::DictionaryValue::Iterator(*map); !it.IsAtEnd(); + it.Advance()) { + if (it.value().Equals(&origin_and_sw_id)) + return Get(profile, it.key()); + } + return PushMessagingApplicationId(); +} + +// static +std::vector<PushMessagingApplicationId> PushMessagingApplicationId::GetAll( + Profile* profile) { + std::vector<PushMessagingApplicationId> result; + + const base::DictionaryValue* map = + profile->GetPrefs()->GetDictionary(prefs::kPushMessagingApplicationIdMap); + for (auto it = base::DictionaryValue::Iterator(*map); !it.IsAtEnd(); + it.Advance()) { + result.push_back(Get(profile, it.key())); + } + + return result; +} + +void PushMessagingApplicationId::PersistToDisk(Profile* profile) const { + DCHECK(IsValid()); + + DictionaryPrefUpdate update(profile->GetPrefs(), + prefs::kPushMessagingApplicationIdMap); + base::DictionaryValue* map = update.Get(); + + // Delete any stale entry with the same origin and Service Worker + // registration id (hence we ensure there is a 1:1 not 1:many mapping). + PushMessagingApplicationId old = Get(profile, origin_, + service_worker_registration_id_); + if (old.IsValid()) + map->RemoveWithoutPathExpansion(old.app_id_guid_, nullptr); + + std::string origin_and_sw_id = origin_.spec() + kSeparator + + base::Int64ToString(service_worker_registration_id_); + map->SetStringWithoutPathExpansion(app_id_guid_, origin_and_sw_id); +} + +void PushMessagingApplicationId::DeleteFromDisk(Profile* profile) const { + DCHECK(IsValid()); + + DictionaryPrefUpdate update(profile->GetPrefs(), + prefs::kPushMessagingApplicationIdMap); + base::DictionaryValue* map = update.Get(); + map->RemoveWithoutPathExpansion(app_id_guid_, nullptr); +} + +PushMessagingApplicationId::PushMessagingApplicationId() + : origin_(GURL::EmptyGURL()), + service_worker_registration_id_(-1) { +} + +PushMessagingApplicationId::PushMessagingApplicationId( + const std::string& app_id_guid, + const GURL& origin, + int64 service_worker_registration_id) + : app_id_guid_(app_id_guid), + origin_(origin), + service_worker_registration_id_(service_worker_registration_id) { +} + +PushMessagingApplicationId::~PushMessagingApplicationId() { +} + +bool PushMessagingApplicationId::IsValid() const { + const size_t prefix_len = strlen(kPushMessagingApplicationIdPrefix); + return origin_.is_valid() && origin_.GetOrigin() == origin_ + && service_worker_registration_id_ >= 0 + && !app_id_guid_.compare(0, prefix_len, kPushMessagingApplicationIdPrefix) + && base::IsValidGUID(app_id_guid_.substr(prefix_len, std::string::npos)); +}
diff --git a/chrome/browser/push_messaging/push_messaging_application_id.h b/chrome/browser/push_messaging/push_messaging_application_id.h new file mode 100644 index 0000000..dea7a59 --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_application_id.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 CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_APPLICATION_ID_H_ +#define CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_APPLICATION_ID_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "url/gurl.h" + +class Profile; + +namespace user_prefs { +class PrefRegistrySyncable; +} + +// The prefix used for all push messaging application ids. +extern const char kPushMessagingApplicationIdPrefix[]; + +// Type used to identify a web app from a Push API perspective. +// These can be persisted to disk, in a 1:1 mapping between app_id_guid and +// pair<origin, service_worker_registration_id>. +class PushMessagingApplicationId { + public: + // Register profile-specific prefs. + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); + + // Generates a new application id with random app_id_guid. + static PushMessagingApplicationId Generate( + const GURL& origin, + int64 service_worker_registration_id); + + // Looks up an application id by app_id_guid. Will be invalid if not found. + static PushMessagingApplicationId Get(Profile* profile, + const std::string& app_id_guid); + + // Looks up an application id by origin & service worker registration id. + // Will be invalid if not found. + static PushMessagingApplicationId Get(Profile* profile, + const GURL& origin, + int64 service_worker_registration_id); + + // Returns all the PushMessagingApplicationId currently registered for the + // given |profile|. + static std::vector<PushMessagingApplicationId> GetAll(Profile* profile); + + ~PushMessagingApplicationId(); + + // Persist this application id to disk. + void PersistToDisk(Profile* profile) const; + + // Delete this application id from disk. + void DeleteFromDisk(Profile* profile) const; // TODO: Does const make sense? + + bool IsValid() const; + + const std::string& app_id_guid() const { return app_id_guid_; } + const GURL& origin() const { return origin_; } + int64 service_worker_registration_id() const { + return service_worker_registration_id_; + } + + private: + friend class PushMessagingApplicationIdTest; + + // Constructs an invalid app id. + PushMessagingApplicationId(); + // Constructs a valid app id. + PushMessagingApplicationId(const std::string& app_id_guid, + const GURL& origin, + int64 service_worker_registration_id); + + std::string app_id_guid_; + GURL origin_; + int64 service_worker_registration_id_; +}; + +#endif // CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_APPLICATION_ID_H_
diff --git a/chrome/browser/push_messaging/push_messaging_application_id_unittest.cc b/chrome/browser/push_messaging/push_messaging_application_id_unittest.cc new file mode 100644 index 0000000..54f1ab76 --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_application_id_unittest.cc
@@ -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. + +#include "chrome/browser/push_messaging/push_messaging_application_id.h" +#include "testing/gtest/include/gtest/gtest.h" + +class PushMessagingApplicationIdTest : public testing::Test { + protected: + PushMessagingApplicationId GenerateId( + const GURL& origin, + int64 service_worker_registration_id) { + // To bypass DCHECK in PushMessagingApplicationId::Generate, we just use it + // to generate app_id_guid, and then use private constructor. + std::string app_id_guid = PushMessagingApplicationId::Generate( + GURL("https://www.example.com/"), 1).app_id_guid(); + return PushMessagingApplicationId(app_id_guid, origin, + service_worker_registration_id); + } +}; + +TEST_F(PushMessagingApplicationIdTest, ConstructorValidity) { + EXPECT_TRUE(GenerateId(GURL("https://www.example.com/"), 1).IsValid()); + EXPECT_TRUE(GenerateId(GURL("https://www.example.com"), 1).IsValid()); + EXPECT_FALSE(GenerateId(GURL(""), 1).IsValid()); + EXPECT_FALSE(GenerateId(GURL("foo"), 1).IsValid()); + EXPECT_FALSE(GenerateId(GURL("https://www.example.com/foo"), 1).IsValid()); + EXPECT_FALSE(GenerateId(GURL("https://www.example.com/#foo"), 1).IsValid()); + EXPECT_FALSE(GenerateId(GURL("https://www.example.com/"), -1).IsValid()); +} + +TEST_F(PushMessagingApplicationIdTest, UniqueGuids) { + EXPECT_NE(PushMessagingApplicationId::Generate( + GURL("https://www.example.com/"), 1).app_id_guid(), + PushMessagingApplicationId::Generate( + GURL("https://www.example.com/"), 1).app_id_guid()); +}
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc new file mode 100644 index 0000000..7ab3987 --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -0,0 +1,1011 @@ +// 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 <map> +#include <string> + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/infobars/infobar_service.h" +#include "chrome/browser/notifications/notification_test_util.h" +#include "chrome/browser/notifications/platform_notification_service_impl.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/push_messaging/push_messaging_application_id.h" +#include "chrome/browser/push_messaging/push_messaging_constants.h" +#include "chrome/browser/push_messaging/push_messaging_service_factory.h" +#include "chrome/browser/push_messaging/push_messaging_service_impl.h" +#include "chrome/browser/services/gcm/fake_gcm_profile_service.h" +#include "chrome/browser/services/gcm/gcm_profile_service_factory.h" +#include "chrome/browser/ui/browser.h" +#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.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" +#include "components/infobars/core/infobar_manager.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/browser_test_utils.h" +#include "ui/base/window_open_disposition.h" + +#if defined(OS_ANDROID) +#include "base/android/build_info.h" +#endif + +namespace { +// Responds to a confirm infobar by accepting or cancelling it. Responds to at +// most one infobar. +class InfoBarResponder : public infobars::InfoBarManager::Observer { + public: + InfoBarResponder(Browser* browser, bool accept) + : infobar_service_(InfoBarService::FromWebContents( + browser->tab_strip_model()->GetActiveWebContents())), + accept_(accept), + has_observed_(false) { + infobar_service_->AddObserver(this); + } + + ~InfoBarResponder() override { infobar_service_->RemoveObserver(this); } + + // infobars::InfoBarManager::Observer + void OnInfoBarAdded(infobars::InfoBar* infobar) override { + if (has_observed_) + return; + has_observed_ = true; + ConfirmInfoBarDelegate* delegate = + infobar->delegate()->AsConfirmInfoBarDelegate(); + DCHECK(delegate); + + // Respond to the infobar asynchronously, like a person. + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind( + &InfoBarResponder::Respond, base::Unretained(this), delegate)); + } + + private: + void Respond(ConfirmInfoBarDelegate* delegate) { + if (accept_) { + delegate->Accept(); + } else { + delegate->Cancel(); + } + } + + InfoBarService* infobar_service_; + 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), waiting_(false) {} + + void Run(const std::string& app_id) { + app_id_ = app_id; + done_ = true; + if (waiting_) + base::MessageLoop::current()->Quit(); + } + + void WaitUntilSatisfied() { + if (done_) + return; + + waiting_ = true; + while (!done_) + content::RunMessageLoop(); + } + + const std::string& app_id() { + return app_id_; + } + + private: + bool done_; + bool waiting_; + std::string app_id_; +}; + +// Class to instantiate on the stack that is meant to be used with +// StubNotificationUIManager::SetNotificationAddedCallback. Mind that Run() +// might be invoked prior to WaitUntilSatisfied() being called. +class NotificationAddedCallback { + public: + NotificationAddedCallback() : done_(false), waiting_(false) {} + + void Run() { + done_ = true; + if (waiting_) + base::MessageLoop::current()->Quit(); + } + + void WaitUntilSatisfied() { + if (done_) + return; + + waiting_ = true; + while (!done_) + content::RunMessageLoop(); + } + + private: + bool done_; + bool waiting_; +}; + +// The Push API depends on Web Notifications, which is only available on Android +// Jelly Bean and later. +bool IsPushSupported() { +#if defined(OS_ANDROID) + if (base::android::BuildInfo::GetInstance()->sdk_int() < + base::android::SDK_VERSION_JELLY_BEAN) { + DVLOG(0) << "The Push API is only supported in Android 4.1 and later."; + return false; + } +#endif + return true; +} + +} // namespace + +class PushMessagingBrowserTest : public InProcessBrowserTest { + public: + PushMessagingBrowserTest() : gcm_service_(nullptr) {} + ~PushMessagingBrowserTest() override {} + + // InProcessBrowserTest: + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitch(switches::kEnablePushMessagePayload); + command_line->AppendSwitch(switches::kEnablePushMessagingHasPermission); + + InProcessBrowserTest::SetUpCommandLine(command_line); + } + + // InProcessBrowserTest: + void SetUp() override { + https_server_.reset(new net::SpawnedTestServer( + net::SpawnedTestServer::TYPE_HTTPS, + net::BaseTestServer::SSLOptions( + net::BaseTestServer::SSLOptions::CERT_OK), + base::FilePath(FILE_PATH_LITERAL("chrome/test/data/")))); + ASSERT_TRUE(https_server_->Start()); + +#if defined(ENABLE_NOTIFICATIONS) + notification_manager_.reset(new StubNotificationUIManager); + notification_service()->SetNotificationUIManagerForTesting( + notification_manager()); +#endif + + InProcessBrowserTest::SetUp(); + } + + // InProcessBrowserTest: + void SetUpOnMainThread() override { + gcm_service_ = static_cast<gcm::FakeGCMProfileService*>( + gcm::GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse( + browser()->profile(), &gcm::FakeGCMProfileService::Build)); + gcm_service_->set_collect(true); + push_service_ = + PushMessagingServiceFactory::GetForProfile(browser()->profile()); + + LoadTestPage(); + + InProcessBrowserTest::SetUpOnMainThread(); + } + + // InProcessBrowserTest: + void TearDown() override { +#if defined(ENABLE_NOTIFICATIONS) + notification_service()->SetNotificationUIManagerForTesting(nullptr); +#endif + + InProcessBrowserTest::TearDown(); + } + + void LoadTestPage(const std::string& path) { + ui_test_utils::NavigateToURL(browser(), https_server_->GetURL(path)); + } + + void LoadTestPage() { + LoadTestPage(GetTestURL()); + } + + bool RunScript(const std::string& script, std::string* result) { + return RunScript(script, result, nullptr); + } + + bool RunScript(const std::string& script, std::string* result, + content::WebContents* web_contents) { + if (!web_contents) + web_contents = browser()->tab_strip_model()->GetActiveWebContents(); + return content::ExecuteScriptAndExtractString(web_contents->GetMainFrame(), + script, + result); + } + + void TryToRegisterSuccessfully( + const std::string& expected_push_registration_id); + + PushMessagingApplicationId GetServiceWorkerAppId( + int64 service_worker_registration_id); + + net::SpawnedTestServer* https_server() const { return https_server_.get(); } + + gcm::FakeGCMProfileService* gcm_service() const { return gcm_service_; } + +#if defined(ENABLE_NOTIFICATIONS) + StubNotificationUIManager* notification_manager() const { + return notification_manager_.get(); + } + + PlatformNotificationServiceImpl* notification_service() const { + return PlatformNotificationServiceImpl::GetInstance(); + } +#endif + + PushMessagingServiceImpl* push_service() const { return push_service_; } + + protected: + virtual std::string GetTestURL() { + return "files/push_messaging/test.html"; + } + + private: + scoped_ptr<net::SpawnedTestServer> https_server_; + gcm::FakeGCMProfileService* gcm_service_; + PushMessagingServiceImpl* push_service_; + scoped_ptr<StubNotificationUIManager> notification_manager_; + + DISALLOW_COPY_AND_ASSIGN(PushMessagingBrowserTest); +}; + +class PushMessagingBadManifestBrowserTest : public PushMessagingBrowserTest { + std::string GetTestURL() override { + return "files/push_messaging/test_bad_manifest.html"; + } +}; + +IN_PROC_BROWSER_TEST_F(PushMessagingBadManifestBrowserTest, + RegisterFailsNotVisibleMessages) { + if (!IsPushSupported()) + return; + + std::string script_result; + + ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); + ASSERT_EQ("ok - service worker registered", script_result); + ASSERT_TRUE(RunScript("registerPush()", &script_result)); + EXPECT_EQ("AbortError - Registration failed - permission denied", + script_result); +} + +void PushMessagingBrowserTest::TryToRegisterSuccessfully( + const std::string& expected_push_registration_id) { + std::string script_result; + + EXPECT_TRUE(RunScript("registerServiceWorker()", &script_result)); + EXPECT_EQ("ok - service worker registered", script_result); + + InfoBarResponder accepting_responder(browser(), true); + EXPECT_TRUE(RunScript("requestNotificationPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); + + EXPECT_TRUE(RunScript("registerPush()", &script_result)); + EXPECT_EQ(std::string(kPushMessagingEndpoint) + " - " + + expected_push_registration_id, script_result); +} + +PushMessagingApplicationId PushMessagingBrowserTest::GetServiceWorkerAppId( + int64 service_worker_registration_id) { + GURL origin = https_server()->GetURL(std::string()).GetOrigin(); + PushMessagingApplicationId application_id = PushMessagingApplicationId::Get( + browser()->profile(), origin, service_worker_registration_id); + EXPECT_TRUE(application_id.IsValid()); + return application_id; +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + RegisterSuccessNotificationsGranted) { + if (!IsPushSupported()) + return; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); + EXPECT_EQ(app_id.app_id_guid(), gcm_service()->last_registered_app_id()); + EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + RegisterSuccessNotificationsPrompt) { + if (!IsPushSupported()) + return; + + 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("registerPush()", &script_result)); + EXPECT_EQ(std::string(kPushMessagingEndpoint) + " - 1-0", script_result); + + PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); + EXPECT_EQ(app_id.app_id_guid(), gcm_service()->last_registered_app_id()); + EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + RegisterFailureNotificationsBlocked) { + if (!IsPushSupported()) + return; + + 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)); + ASSERT_EQ("permission status - denied", script_result); + + ASSERT_TRUE(RunScript("registerPush()", &script_result)); + EXPECT_EQ("AbortError - Registration failed - permission denied", + script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, RegisterFailureNoManifest) { + if (!IsPushSupported()) + return; + + 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("removeManifest()", &script_result)); + ASSERT_EQ("manifest removed", script_result); + + ASSERT_TRUE(RunScript("registerPush()", &script_result)); + EXPECT_EQ("AbortError - Registration failed - no sender id provided", + script_result); +} + +// TODO(johnme): Test registering from a worker - see https://crbug.com/437298. + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, RegisterPersisted) { + if (!IsPushSupported()) + return; + + std::string script_result; + + // First, test that Service Worker registration IDs are assigned in order of + // registering the Service Workers, and the (fake) push registration ids are + // assigned in order of push registration (even when these orders are + // different). + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + PushMessagingApplicationId app_id_sw0 = GetServiceWorkerAppId(0LL); + EXPECT_EQ(app_id_sw0.app_id_guid(), gcm_service()->last_registered_app_id()); + + LoadTestPage("files/push_messaging/subscope1/test.html"); + ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); + ASSERT_EQ("ok - service worker registered", script_result); + + LoadTestPage("files/push_messaging/subscope2/test.html"); + ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); + ASSERT_EQ("ok - service worker registered", script_result); + + // Note that we need to reload the page after registering, otherwise + // navigator.serviceWorker.ready is going to be resolved with the parent + // Service Worker which still controls the page. + LoadTestPage("files/push_messaging/subscope2/test.html"); + TryToRegisterSuccessfully("1-1" /* expected_push_registration_id */); + PushMessagingApplicationId app_id_sw2 = GetServiceWorkerAppId(2LL); + EXPECT_EQ(app_id_sw2.app_id_guid(), gcm_service()->last_registered_app_id()); + + LoadTestPage("files/push_messaging/subscope1/test.html"); + TryToRegisterSuccessfully("1-2" /* expected_push_registration_id */); + PushMessagingApplicationId app_id_sw1 = GetServiceWorkerAppId(1LL); + EXPECT_EQ(app_id_sw1.app_id_guid(), gcm_service()->last_registered_app_id()); + + // Now test that the Service Worker registration IDs and push registration IDs + // generated above were persisted to SW storage, by checking that they are + // unchanged despite requesting them in a different order. + // TODO(johnme): Ideally we would restart the browser at this point to check + // they were persisted to disk, but that's not currently possible since the + // test server uses random port numbers for each test (even PRE_Foo and Foo), + // so we wouldn't be able to load the test pages with the same origin. + + LoadTestPage("files/push_messaging/subscope1/test.html"); + TryToRegisterSuccessfully("1-2" /* expected_push_registration_id */); + EXPECT_EQ(app_id_sw1.app_id_guid(), gcm_service()->last_registered_app_id()); + + LoadTestPage("files/push_messaging/subscope2/test.html"); + TryToRegisterSuccessfully("1-1" /* expected_push_registration_id */); + EXPECT_EQ(app_id_sw1.app_id_guid(), gcm_service()->last_registered_app_id()); + + LoadTestPage(); + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + EXPECT_EQ(app_id_sw1.app_id_guid(), gcm_service()->last_registered_app_id()); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventSuccess) { + if (!IsPushSupported()) + return; + + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); + EXPECT_EQ(app_id.app_id_guid(), 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); + + gcm::GCMClient::IncomingMessage message; + message.sender_id = "1234567890"; + message.data["data"] = "testdata"; + push_service()->OnMessage(app_id.app_id_guid(), message); + ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result)); + EXPECT_EQ("testdata", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventNoServiceWorker) { + if (!IsPushSupported()) + return; + + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); + EXPECT_EQ(app_id.app_id_guid(), 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))); + + gcm::GCMClient::IncomingMessage message; + message.sender_id = "1234567890"; + message.data["data"] = "testdata"; + push_service()->OnMessage(app_id.app_id_guid(), message); + + callback.WaitUntilSatisfied(); + EXPECT_EQ(app_id.app_id_guid(), callback.app_id()); + + // No push data should have been received. + ASSERT_TRUE(RunScript("resultQueue.popImmediately()", &script_result)); + EXPECT_EQ("null", script_result); +} + +#if defined(ENABLE_NOTIFICATIONS) +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + PushEventEnforcesUserVisibleNotification) { + if (!IsPushSupported()) + return; + + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); + EXPECT_EQ(app_id.app_id_guid(), 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); + + notification_manager()->CancelAll(); + ASSERT_EQ(0u, notification_manager()->GetNotificationCount()); + + // We'll need to specify the web_contents in which to eval script, since we're + // going to run script in a background tab. + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + // If the site is visible in an active tab, we should not force a notification + // to be shown. Try it twice, since we allow one mistake per 10 push events. + gcm::GCMClient::IncomingMessage message; + message.sender_id = "1234567890"; + for (int n = 0; n < 2; n++) { + message.data["data"] = "testdata"; + push_service()->OnMessage(app_id.app_id_guid(), message); + ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result)); + EXPECT_EQ("testdata", script_result); + EXPECT_EQ(0u, notification_manager()->GetNotificationCount()); + } + + // Open a blank foreground tab so site is no longer visible. + ui_test_utils::NavigateToURLWithDisposition( + browser(), GURL("about:blank"), NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB); + + // If the Service Worker push event handler does not show a notification, we + // should show a forced one, but only on the 2nd occurrence since we allow one + // mistake per 10 push events. + message.data["data"] = "testdata"; + push_service()->OnMessage(app_id.app_id_guid(), message); + ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents)); + EXPECT_EQ("testdata", script_result); + EXPECT_EQ(0u, notification_manager()->GetNotificationCount()); + message.data["data"] = "testdata"; + push_service()->OnMessage(app_id.app_id_guid(), message); + ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents)); + EXPECT_EQ("testdata", script_result); + EXPECT_EQ(1u, notification_manager()->GetNotificationCount()); + EXPECT_EQ(base::ASCIIToUTF16(kPushMessagingForcedNotificationTag), + notification_manager()->GetNotificationAt(0).replace_id()); + + // Currently, this notification will stick around until the user or webapp + // explicitly dismisses it (though we may change this later). + message.data["data"] = "shownotification"; + push_service()->OnMessage(app_id.app_id_guid(), message); + ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents)); + EXPECT_EQ("shownotification", script_result); + EXPECT_EQ(2u, notification_manager()->GetNotificationCount()); + + notification_manager()->CancelAll(); + EXPECT_EQ(0u, notification_manager()->GetNotificationCount()); + + // However if the Service Worker push event handler shows a notification, we + // should not show a forced one. + message.data["data"] = "shownotification"; + for (int n = 0; n < 9; n++) { + push_service()->OnMessage(app_id.app_id_guid(), message); + ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents)); + EXPECT_EQ("shownotification", script_result); + EXPECT_EQ(1u, notification_manager()->GetNotificationCount()); + EXPECT_EQ(base::ASCIIToUTF16("push_test_tag"), + notification_manager()->GetNotificationAt(0).replace_id()); + notification_manager()->CancelAll(); + } + + // Now that 10 push messages in a row have shown notifications, we should + // allow the next one to mistakenly not show a notification. + message.data["data"] = "testdata"; + push_service()->OnMessage(app_id.app_id_guid(), message); + ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents)); + EXPECT_EQ("testdata", script_result); + EXPECT_EQ(0u, notification_manager()->GetNotificationCount()); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + PushEventNotificationWithoutEventWaitUntil) { + if (!IsPushSupported()) + return; + + std::string script_result; + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); + EXPECT_EQ(app_id.app_id_guid(), 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); + + NotificationAddedCallback callback; + notification_manager()->SetNotificationAddedCallback( + base::Bind(&NotificationAddedCallback::Run, base::Unretained(&callback))); + + gcm::GCMClient::IncomingMessage message; + message.sender_id = "1234567890"; + message.data["data"] = "shownotification-without-waituntil"; + push_service()->OnMessage(app_id.app_id_guid(), message); + ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents)); + EXPECT_EQ("immediate:shownotification-without-waituntil", script_result); + + callback.WaitUntilSatisfied(); + + ASSERT_EQ(1u, notification_manager()->GetNotificationCount()); + EXPECT_EQ(base::ASCIIToUTF16("push_test_tag"), + notification_manager()->GetNotificationAt(0).replace_id()); + + // Verify that the renderer process hasn't crashed. + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); +} +#endif + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, HasPermissionSaysDefault) { + if (!IsPushSupported()) + return; + + 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) { + if (!IsPushSupported()) + return; + + 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-0", script_result); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, HasPermissionSaysDenied) { + if (!IsPushSupported()) + return; + + 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); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, UnregisterSuccess) { + if (!IsPushSupported()) + return; + + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + gcm_service()->AddExpectedUnregisterResponse(gcm::GCMClient::SUCCESS); + + ASSERT_TRUE(RunScript("unregister()", &script_result)); + EXPECT_EQ("unregister result: true", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, UnregisterNetworkError) { + if (!IsPushSupported()) + return; + + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + gcm_service()->AddExpectedUnregisterResponse(gcm::GCMClient::NETWORK_ERROR); + + ASSERT_TRUE(RunScript("unregister()", &script_result)); + EXPECT_EQ("unregister error: NetworkError: " + "Unregistration failed - could not connect to push server", + script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, UnregisterAbortError) { + if (!IsPushSupported()) + return; + + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + gcm_service()->AddExpectedUnregisterResponse(gcm::GCMClient::UNKNOWN_ERROR); + + ASSERT_TRUE(RunScript("unregister()", &script_result)); + EXPECT_EQ("unregister error: " + "AbortError: Unregistration failed - push service error", + script_result); +} + +#if defined(OS_ANDROID) +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushUnavailableOnAndroidICS) { + // This test should only run on Android ICS to confirm that the Push API + // is not available on that version of Android. + if (IsPushSupported()) + return; + + std::string script_result; + ASSERT_TRUE(RunScript("window.PushManager", &script_result)); + EXPECT_EQ("undefined", script_result); +} +#endif + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + GlobalResetPushPermissionUnregisters) { + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("true - registered", script_result); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); + + browser()->profile()->GetHostContentSettingsMap()-> + ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - default", script_result); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("false - not registered", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + LocalResetPushPermissionUnregisters) { + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("true - registered", script_result); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); + + GURL origin = https_server()->GetURL(std::string()).GetOrigin(); + browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( + ContentSettingsPattern::FromURLNoWildcard(origin), + ContentSettingsPattern::FromURLNoWildcard(origin), + CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, + std::string(), + CONTENT_SETTING_DEFAULT); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - default", script_result); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("false - not registered", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + DenyPushPermissionUnregisters) { + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("true - registered", script_result); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); + + GURL origin = https_server()->GetURL(std::string()).GetOrigin(); + browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( + ContentSettingsPattern::FromURLNoWildcard(origin), + ContentSettingsPattern::FromURLNoWildcard(origin), + CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, + std::string(), + CONTENT_SETTING_BLOCK); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - denied", script_result); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("false - not registered", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + GlobalResetNotificationsPermissionUnregisters) { + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("true - registered", script_result); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); + + browser()->profile()->GetHostContentSettingsMap()-> + ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_NOTIFICATIONS); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - default", script_result); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("false - not registered", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + LocalResetNotificationsPermissionUnregisters) { + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("true - registered", script_result); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); + + GURL origin = https_server()->GetURL(std::string()).GetOrigin(); + browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( + ContentSettingsPattern::FromURLNoWildcard(origin), + ContentSettingsPattern::Wildcard(), + CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + std::string(), + CONTENT_SETTING_DEFAULT); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - default", script_result); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("false - not registered", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + DenyNotificationsPermissionUnregisters) { + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("true - registered", script_result); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); + + GURL origin = https_server()->GetURL(std::string()).GetOrigin(); + browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( + ContentSettingsPattern::FromURLNoWildcard(origin), + ContentSettingsPattern::Wildcard(), + CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + std::string(), + CONTENT_SETTING_BLOCK); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - denied", script_result); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("false - not registered", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + GrantAlreadyGrantedPermissionDoesNotUnregister) { + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("true - registered", script_result); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); + + GURL origin = https_server()->GetURL(std::string()).GetOrigin(); + browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( + ContentSettingsPattern::FromURLNoWildcard(origin), + ContentSettingsPattern::Wildcard(), + CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + std::string(), + CONTENT_SETTING_ALLOW); + browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( + ContentSettingsPattern::FromURLNoWildcard(origin), + ContentSettingsPattern::FromURLNoWildcard(origin), + CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, + std::string(), + CONTENT_SETTING_ALLOW); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("true - registered", script_result); +} + +// This test is testing some non-trivial content settings rules and make sure +// that they are respected with regards to automatic unregistration. In other +// words, it checks that the push service does not end up unregistering origins +// that have push permission with some non-common rules. +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, + AutomaticUnregistrationFollowsContentSettingRules) { + std::string script_result; + + TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("true - registered", script_result); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); + + GURL origin = https_server()->GetURL(std::string()).GetOrigin(); + browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( + ContentSettingsPattern::Wildcard(), + ContentSettingsPattern::Wildcard(), + CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + std::string(), + CONTENT_SETTING_ALLOW); + browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( + ContentSettingsPattern::FromString("https://*"), + ContentSettingsPattern::FromString("https://*"), + CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, + std::string(), + CONTENT_SETTING_ALLOW); + browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( + ContentSettingsPattern::FromURLNoWildcard(origin), + ContentSettingsPattern::Wildcard(), + CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + std::string(), + CONTENT_SETTING_DEFAULT); + browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( + ContentSettingsPattern::FromURLNoWildcard(origin), + ContentSettingsPattern::FromURLNoWildcard(origin), + CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, + std::string(), + CONTENT_SETTING_DEFAULT); + + // The two first rules should give |origin| the permission to use Push even + // if the rules it used to have have been reset. + // The Push service should not unsubcribe |origin| because at no point it was + // left without permission to use Push. + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); + + ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); + EXPECT_EQ("true - registered", script_result); +}
diff --git a/chrome/browser/push_messaging/push_messaging_constants.cc b/chrome/browser/push_messaging/push_messaging_constants.cc new file mode 100644 index 0000000..57e603d --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_constants.cc
@@ -0,0 +1,10 @@ +// 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/push_messaging/push_messaging_constants.h" + +const char kPushMessagingEndpoint[] = "https://android.googleapis.com/gcm/send"; + +const char kPushMessagingForcedNotificationTag[] = + "user_visible_auto_notification";
diff --git a/chrome/browser/push_messaging/push_messaging_constants.h b/chrome/browser/push_messaging/push_messaging_constants.h new file mode 100644 index 0000000..6ab91c5 --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_constants.h
@@ -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. + +#ifndef CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_CONSTANTS_H_ +#define CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_CONSTANTS_H_ + +extern const char kPushMessagingEndpoint[]; + +// The tag of the notification that will be automatically shown if a webapp +// receives a push message then fails to show a notification. +extern const char kPushMessagingForcedNotificationTag[]; + +#endif // CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_CONSTANTS_H_
diff --git a/chrome/browser/push_messaging/push_messaging_permission_context.cc b/chrome/browser/push_messaging/push_messaging_permission_context.cc new file mode 100644 index 0000000..885589e1 --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_permission_context.cc
@@ -0,0 +1,138 @@ +// 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/push_messaging/push_messaging_permission_context.h" + +#include "chrome/browser/content_settings/permission_context_uma_util.h" +#include "chrome/browser/notifications/desktop_notification_service.h" +#include "chrome/browser/notifications/desktop_notification_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/content_settings/core/common/permission_request_id.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_delegate.h" + +const ContentSettingsType kPushSettingType = + CONTENT_SETTINGS_TYPE_PUSH_MESSAGING; + +PushMessagingPermissionContext::PushMessagingPermissionContext(Profile* profile) + : PermissionContextBase(profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING), + profile_(profile), + weak_factory_ui_thread_(this) { +} + +PushMessagingPermissionContext::~PushMessagingPermissionContext() { +} + +ContentSetting PushMessagingPermissionContext::GetPermissionStatus( + const GURL& requesting_origin, + const GURL& embedding_origin) const { +#if defined(ENABLE_NOTIFICATIONS) + if (requesting_origin != embedding_origin) + return CONTENT_SETTING_BLOCK; + + ContentSetting push_content_setting = + profile_->GetHostContentSettingsMap()->GetContentSetting( + requesting_origin, embedding_origin, kPushSettingType, std::string()); + + DesktopNotificationService* notification_service = + DesktopNotificationServiceFactory::GetForProfile(profile_); + DCHECK(notification_service); + + ContentSetting notifications_permission = + notification_service->GetPermissionStatus(requesting_origin, + embedding_origin); + + if (notifications_permission == CONTENT_SETTING_BLOCK || + push_content_setting == CONTENT_SETTING_BLOCK) { + return CONTENT_SETTING_BLOCK; + } + if (notifications_permission == CONTENT_SETTING_ASK || + push_content_setting == CONTENT_SETTING_ASK) { + return CONTENT_SETTING_ASK; + } + DCHECK_EQ(CONTENT_SETTING_ALLOW, notifications_permission); + DCHECK_EQ(CONTENT_SETTING_ALLOW, push_content_setting); + return CONTENT_SETTING_ALLOW; +#else + return CONTENT_SETTING_BLOCK; +#endif +} + +void PushMessagingPermissionContext::CancelPermissionRequest( + content::WebContents* web_contents, const PermissionRequestID& id) { + // TODO(peter): consider implementing this method. + NOTIMPLEMENTED() << "CancelPermission not implemented for push messaging"; +} + +// 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. +// This is done to avoid double prompting for notifications and push. +void PushMessagingPermissionContext::DecidePermission( + content::WebContents* web_contents, + const PermissionRequestID& id, + const GURL& requesting_origin, + const GURL& embedding_origin, + bool user_gesture, + const BrowserPermissionCallback& callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +#if defined(ENABLE_NOTIFICATIONS) + if (requesting_origin != embedding_origin) { + NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, + false /* persist */, CONTENT_SETTING_BLOCK); + return; + } + DesktopNotificationService* notification_service = + DesktopNotificationServiceFactory::GetForProfile(profile_); + DCHECK(notification_service); + + notification_service->RequestPermission( + web_contents, id, requesting_origin, user_gesture, + base::Bind(&PushMessagingPermissionContext::DecidePushPermission, + weak_factory_ui_thread_.GetWeakPtr(), id, requesting_origin, + embedding_origin, callback)); +#else + NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, + false /* persist */, CONTENT_SETTING_BLOCK); +#endif +} + +void PushMessagingPermissionContext::DecidePushPermission( + const PermissionRequestID& id, + const GURL& requesting_origin, + const GURL& embedding_origin, + const BrowserPermissionCallback& callback, + ContentSetting notification_content_setting) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + ContentSetting push_content_setting = + profile_->GetHostContentSettingsMap() + ->GetContentSettingAndMaybeUpdateLastUsage( + requesting_origin, embedding_origin, kPushSettingType, + std::string()); + + if (push_content_setting == CONTENT_SETTING_BLOCK) { + DVLOG(1) << "Push permission was explicitly blocked."; + PermissionContextUmaUtil::PermissionDenied(kPushSettingType, + requesting_origin); + NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, + true /* persist */, CONTENT_SETTING_BLOCK); + return; + } + + if (notification_content_setting != CONTENT_SETTING_ALLOW) { + DVLOG(1) << "Notification permission has not been granted."; + NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, + false /* persist */, notification_content_setting); + return; + } + + PermissionContextUmaUtil::PermissionGranted(kPushSettingType, + requesting_origin); + NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, + true /* persist */, CONTENT_SETTING_ALLOW); +}
diff --git a/chrome/browser/push_messaging/push_messaging_permission_context.h b/chrome/browser/push_messaging/push_messaging_permission_context.h new file mode 100644 index 0000000..f978fea --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_permission_context.h
@@ -0,0 +1,59 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_PERMISSION_CONTEXT_H_ +#define CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_PERMISSION_CONTEXT_H_ + +#include "chrome/browser/content_settings/permission_context_base.h" + +#include "components/content_settings/core/common/content_settings_types.h" + +class PermissionRequestID; +class Profile; + +// Permission context for push messages. +class PushMessagingPermissionContext : public PermissionContextBase { + public: + explicit PushMessagingPermissionContext(Profile* profile); + ~PushMessagingPermissionContext() override; + + // PermissionContextBase: + ContentSetting GetPermissionStatus( + const GURL& requesting_origin, + const GURL& embedding_origin) const override; + + void CancelPermissionRequest(content::WebContents* web_contents, + const PermissionRequestID& id) override; + + protected: + // PermissionContextBase: + void DecidePermission(content::WebContents* web_contents, + const PermissionRequestID& id, + const GURL& requesting_origin, + const GURL& embedding_origin, + bool user_gesture, + const BrowserPermissionCallback& callback) override; + + private: + FRIEND_TEST_ALL_PREFIXES(PushMessagingPermissionContextTest, + DecidePushPermission); + + // Used to decide the permission for push, once the permission for + // Notification has been granted/denied. + void DecidePushPermission(const PermissionRequestID& id, + const GURL& requesting_origin, + const GURL& embedding_origin, + const BrowserPermissionCallback& callback, + ContentSetting notifications_content_setting); + + Profile* profile_; + + // Must be the last member, to ensure that it will be + // destroyed first, which will invalidate weak pointers + base::WeakPtrFactory<PushMessagingPermissionContext> weak_factory_ui_thread_; + + DISALLOW_COPY_AND_ASSIGN(PushMessagingPermissionContext); +}; + +#endif // CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_PERMISSION_CONTEXT_H_
diff --git a/chrome/browser/push_messaging/push_messaging_permission_context_factory.cc b/chrome/browser/push_messaging/push_messaging_permission_context_factory.cc new file mode 100644 index 0000000..ad2855a --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_permission_context_factory.cc
@@ -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. + +#include "chrome/browser/push_messaging/push_messaging_permission_context_factory.h" + +#include "chrome/browser/profiles/incognito_helpers.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/push_messaging/push_messaging_permission_context.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" + +// static +PushMessagingPermissionContext* +PushMessagingPermissionContextFactory::GetForProfile( + Profile* profile) { + return static_cast<PushMessagingPermissionContext*>( + GetInstance()->GetServiceForBrowserContext(profile, true)); +} + +// static +PushMessagingPermissionContextFactory* +PushMessagingPermissionContextFactory::GetInstance() { + return Singleton<PushMessagingPermissionContextFactory>::get(); +} + +PushMessagingPermissionContextFactory::PushMessagingPermissionContextFactory() + : BrowserContextKeyedServiceFactory( + "GCMPermissionContext", + BrowserContextDependencyManager::GetInstance()) { +} + +PushMessagingPermissionContextFactory +::~PushMessagingPermissionContextFactory() { +} + +KeyedService* PushMessagingPermissionContextFactory::BuildServiceInstanceFor( + content::BrowserContext* profile) const { + return new PushMessagingPermissionContext(static_cast<Profile*>(profile)); +} + +content::BrowserContext* +PushMessagingPermissionContextFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextOwnInstanceInIncognito(context); +}
diff --git a/chrome/browser/push_messaging/push_messaging_permission_context_factory.h b/chrome/browser/push_messaging/push_messaging_permission_context_factory.h new file mode 100644 index 0000000..84e4bc1 --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_permission_context_factory.h
@@ -0,0 +1,36 @@ +// 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_PUSH_MESSAGING_PUSH_MESSAGING_PERMISSION_CONTEXT_FACTORY_H_ +#define CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_PERMISSION_CONTEXT_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class Profile; + +class PushMessagingPermissionContext; + +class PushMessagingPermissionContextFactory + : public BrowserContextKeyedServiceFactory { + public: + static PushMessagingPermissionContext* GetForProfile(Profile* profile); + static PushMessagingPermissionContextFactory* GetInstance(); + + private: + friend struct DefaultSingletonTraits<PushMessagingPermissionContextFactory>; + + PushMessagingPermissionContextFactory(); + ~PushMessagingPermissionContextFactory() override; + + // BrowserContextKeyedBaseFactory methods: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* profile) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; + + DISALLOW_COPY_AND_ASSIGN(PushMessagingPermissionContextFactory); +}; + +#endif // CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_PERMISSION_CONTEXT_FACTORY_H_
diff --git a/chrome/browser/push_messaging/push_messaging_permission_context_unittest.cc b/chrome/browser/push_messaging/push_messaging_permission_context_unittest.cc new file mode 100644 index 0000000..57e9372 --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_permission_context_unittest.cc
@@ -0,0 +1,162 @@ +// 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/push_messaging/push_messaging_permission_context.h" +#include "chrome/test/base/testing_profile.h" +#include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/content_settings/core/common/content_settings.h" +#include "components/content_settings/core/common/content_settings_types.h" +#include "components/content_settings/core/common/permission_request_id.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" + +const char kOriginA[] = "https://origina.org"; +const char kOriginB[] = "https://originb.org"; + +class TestPushMessagingPermissionContext + : public PushMessagingPermissionContext { + public: + explicit TestPushMessagingPermissionContext(Profile* profile) + : PushMessagingPermissionContext(profile), + was_persisted_(false), + permission_granted_(false) {} + + bool was_persisted() const { return was_persisted_; } + bool was_granted() const { return permission_granted_; } + + private: + // PushMessagingPermissionContext: + void NotifyPermissionSet(const PermissionRequestID& id, + const GURL& requesting_origin, + const GURL& embedder_origin, + const BrowserPermissionCallback& callback, + bool persist, + ContentSetting content_setting) override { + was_persisted_ = persist; + permission_granted_ = content_setting == CONTENT_SETTING_ALLOW; + } + + bool was_persisted_; + bool permission_granted_; +}; + +class PushMessagingPermissionContextTest : public testing::Test { + public: + PushMessagingPermissionContextTest() {} + + protected: + void SetContentSetting(Profile* profile, + ContentSettingsType setting, + ContentSetting value) { + ContentSettingsPattern pattern = + ContentSettingsPattern::FromString(kOriginA); + HostContentSettingsMap* host_content_settings_map = + profile->GetHostContentSettingsMap(); + host_content_settings_map->SetContentSetting(pattern, pattern, setting, + std::string(), value); + } + + content::TestBrowserThreadBundle thread_bundle_; +}; + +TEST_F(PushMessagingPermissionContextTest, HasPermissionPrompt) { + TestingProfile profile; + PushMessagingPermissionContext context(&profile); + EXPECT_EQ(CONTENT_SETTING_ASK, + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); + + // Just granting notifications should still prompt + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + CONTENT_SETTING_ALLOW); + + EXPECT_EQ(CONTENT_SETTING_ASK, + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); + + // Just granting push should still prompt + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + CONTENT_SETTING_ASK); + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, + CONTENT_SETTING_ALLOW); + + EXPECT_EQ(CONTENT_SETTING_ASK, + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); +} + +TEST_F(PushMessagingPermissionContextTest, HasPermissionDenySettingsMismatch) { + TestingProfile profile; + PushMessagingPermissionContext context(&profile); + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + CONTENT_SETTING_BLOCK); + EXPECT_EQ(CONTENT_SETTING_BLOCK, + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + CONTENT_SETTING_ASK); + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, + CONTENT_SETTING_BLOCK); + EXPECT_EQ(CONTENT_SETTING_BLOCK, + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + CONTENT_SETTING_ALLOW); + EXPECT_EQ(CONTENT_SETTING_BLOCK, + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); + + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + CONTENT_SETTING_ASK); + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, + CONTENT_SETTING_BLOCK); + EXPECT_EQ(CONTENT_SETTING_BLOCK, + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); +} + +TEST_F(PushMessagingPermissionContextTest, HasPermissionDenyDifferentOrigins) { + TestingProfile profile; + PushMessagingPermissionContext context(&profile); + EXPECT_EQ(CONTENT_SETTING_BLOCK, + context.GetPermissionStatus(GURL(kOriginB), GURL(kOriginA))); +} + +TEST_F(PushMessagingPermissionContextTest, HasPermissionAccept) { + TestingProfile profile; + PushMessagingPermissionContext context(&profile); + + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + CONTENT_SETTING_ALLOW); + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, + CONTENT_SETTING_ALLOW); + EXPECT_EQ(CONTENT_SETTING_ALLOW, + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); +} + +TEST_F(PushMessagingPermissionContextTest, DecidePushPermission) { + TestingProfile profile; + TestPushMessagingPermissionContext context(&profile); + PermissionRequestID request_id(-1, -1, -1, GURL(kOriginA)); + BrowserPermissionCallback callback; + + context.DecidePushPermission(request_id, GURL(kOriginA), GURL(kOriginA), + callback, CONTENT_SETTING_DEFAULT); + EXPECT_FALSE(context.was_persisted()); + EXPECT_FALSE(context.was_granted()); + + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, + CONTENT_SETTING_ALLOW); + context.DecidePushPermission(request_id, GURL(kOriginA), GURL(kOriginA), + callback, CONTENT_SETTING_ALLOW); + EXPECT_TRUE(context.was_persisted()); + EXPECT_TRUE(context.was_granted()); + + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, + CONTENT_SETTING_BLOCK); + context.DecidePushPermission(request_id, GURL(kOriginA), GURL(kOriginA), + callback, CONTENT_SETTING_ALLOW); + EXPECT_TRUE(context.was_persisted()); + EXPECT_FALSE(context.was_granted()); + + SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, + CONTENT_SETTING_ASK); + context.DecidePushPermission(request_id, GURL(kOriginA), GURL(kOriginA), + callback, CONTENT_SETTING_ALLOW); + EXPECT_TRUE(context.was_persisted()); + EXPECT_TRUE(context.was_granted()); +}
diff --git a/chrome/browser/push_messaging/push_messaging_service_factory.cc b/chrome/browser/push_messaging/push_messaging_service_factory.cc new file mode 100644 index 0000000..1ed640c --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_service_factory.cc
@@ -0,0 +1,51 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/push_messaging/push_messaging_service_factory.h" + +#include "chrome/browser/profiles/incognito_helpers.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/push_messaging/push_messaging_service_impl.h" +#include "chrome/browser/services/gcm/fake_gcm_profile_service.h" +#include "chrome/browser/services/gcm/gcm_profile_service_factory.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" + +// static +PushMessagingServiceImpl* PushMessagingServiceFactory::GetForProfile( + content::BrowserContext* profile) { + // The Push API is not currently supported in incognito mode. + // See https://crbug.com/401439. + if (profile->IsOffTheRecord()) + return NULL; + + return static_cast<PushMessagingServiceImpl*>( + GetInstance()->GetServiceForBrowserContext(profile, true)); +} + +// static +PushMessagingServiceFactory* PushMessagingServiceFactory::GetInstance() { + return Singleton<PushMessagingServiceFactory>::get(); +} + +PushMessagingServiceFactory::PushMessagingServiceFactory() + : BrowserContextKeyedServiceFactory( + "PushMessagingProfileService", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(gcm::GCMProfileServiceFactory::GetInstance()); +} + +PushMessagingServiceFactory::~PushMessagingServiceFactory() { +} + +KeyedService* PushMessagingServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + Profile* profile = Profile::FromBrowserContext(context); + CHECK(!profile->IsOffTheRecord()); + return new PushMessagingServiceImpl(profile); +} + +content::BrowserContext* PushMessagingServiceFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextOwnInstanceInIncognito(context); +}
diff --git a/chrome/browser/push_messaging/push_messaging_service_factory.h b/chrome/browser/push_messaging/push_messaging_service_factory.h new file mode 100644 index 0000000..b15b11d --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_service_factory.h
@@ -0,0 +1,35 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_SERVICE_FACTORY_H_ +#define CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_SERVICE_FACTORY_H_ + +#include "base/compiler_specific.h" +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class PushMessagingServiceImpl; + +class PushMessagingServiceFactory : public BrowserContextKeyedServiceFactory { + public: + static PushMessagingServiceImpl* GetForProfile( + content::BrowserContext* profile); + static PushMessagingServiceFactory* GetInstance(); + + private: + friend struct DefaultSingletonTraits<PushMessagingServiceFactory>; + + PushMessagingServiceFactory(); + ~PushMessagingServiceFactory() override; + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* profile) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; + + DISALLOW_COPY_AND_ASSIGN(PushMessagingServiceFactory); +}; + +#endif // CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_SERVICE_FACTORY_H_
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.cc b/chrome/browser/push_messaging/push_messaging_service_impl.cc new file mode 100644 index 0000000..59a8216 --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
@@ -0,0 +1,769 @@ +// 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/push_messaging/push_messaging_service_impl.h" + +#include <bitset> +#include <vector> + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/metrics/histogram.h" +#include "base/prefs/pref_service.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/notifications/notification_ui_manager.h" +#include "chrome/browser/notifications/platform_notification_service_impl.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/push_messaging/push_messaging_application_id.h" +#include "chrome/browser/push_messaging/push_messaging_constants.h" +#include "chrome/browser/push_messaging/push_messaging_permission_context.h" +#include "chrome/browser/push_messaging/push_messaging_permission_context_factory.h" +#include "chrome/browser/push_messaging/push_messaging_service_factory.h" +#include "chrome/browser/services/gcm/gcm_profile_service.h" +#include "chrome/browser/services/gcm/gcm_profile_service_factory.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" +#include "chrome/grit/generated_resources.h" +#include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/content_settings/core/common/permission_request_id.h" +#include "components/gcm_driver/gcm_driver.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/service_worker_context.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/child_process_host.h" +#include "content/public/common/content_switches.h" +#include "content/public/common/platform_notification_data.h" +#include "content/public/common/push_messaging_status.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/l10n/l10n_util.h" + +#if defined(OS_ANDROID) +#include "chrome/browser/ui/android/tab_model/tab_model.h" +#include "chrome/browser/ui/android/tab_model/tab_model_list.h" +#else +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_iterator.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#endif + +namespace { +const int kMaxRegistrations = 1000000; + +void RecordDeliveryStatus(content::PushDeliveryStatus status) { + UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus", + status, + content::PUSH_DELIVERY_STATUS_LAST + 1); +} + +void RecordUserVisibleStatus(content::PushUserVisibleStatus status) { + UMA_HISTOGRAM_ENUMERATION("PushMessaging.UserVisibleStatus", + status, + content::PUSH_USER_VISIBLE_STATUS_LAST + 1); +} + +blink::WebPushPermissionStatus ToPushPermission(ContentSetting setting) { + switch (setting) { + case CONTENT_SETTING_ALLOW: + return blink::WebPushPermissionStatusGranted; + case CONTENT_SETTING_BLOCK: + return blink::WebPushPermissionStatusDenied; + case CONTENT_SETTING_ASK: + return blink::WebPushPermissionStatusDefault; + default: + NOTREACHED(); + return blink::WebPushPermissionStatusDenied; + } +} + +} // namespace + +// static +void PushMessagingServiceImpl::RegisterProfilePrefs( + user_prefs::PrefRegistrySyncable* registry) { + registry->RegisterIntegerPref( + prefs::kPushMessagingRegistrationCount, + 0, + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); + PushMessagingApplicationId::RegisterProfilePrefs(registry); +} + +// static +void PushMessagingServiceImpl::InitializeForProfile(Profile* profile) { + // TODO(johnme): Consider whether push should be enabled in incognito. + if (!profile || profile->IsOffTheRecord()) + return; + + // TODO(johnme): If push becomes enabled in incognito (and this still uses a + // pref), be careful that this pref is read from the right profile, as prefs + // defined in a regular profile are visible in the corresponding incognito + // profile unless overridden. + // TODO(johnme): Make sure this pref doesn't get out of sync after crashes. + int count = profile->GetPrefs()->GetInteger( + prefs::kPushMessagingRegistrationCount); + if (count <= 0) + return; + + PushMessagingServiceImpl* push_service = + PushMessagingServiceFactory::GetForProfile(profile); + push_service->IncreasePushRegistrationCount(count, false /* is_pending */); +} + +PushMessagingServiceImpl::PushMessagingServiceImpl(Profile* profile) + : profile_(profile), + push_registration_count_(0), + pending_push_registration_count_(0), + weak_factory_(this) { + // In some tests, we might end up with |profile_| being null at this point. + // When that is the case |profile_| will be set in SetProfileForTesting(), at + // which point the service will start to observe HostContentSettingsMap. + if (profile_) + profile_->GetHostContentSettingsMap()->AddObserver(this); +} + +PushMessagingServiceImpl::~PushMessagingServiceImpl() { + profile_->GetHostContentSettingsMap()->RemoveObserver(this); +} + +void PushMessagingServiceImpl::IncreasePushRegistrationCount(int add, + bool is_pending) { + DCHECK(add > 0); + if (push_registration_count_ + pending_push_registration_count_ == 0) { + GetGCMDriver()->AddAppHandler(kPushMessagingApplicationIdPrefix, this); + } + if (is_pending) { + pending_push_registration_count_ += add; + } else { + push_registration_count_ += add; + profile_->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount, + push_registration_count_); + } +} + +void PushMessagingServiceImpl::DecreasePushRegistrationCount(int subtract, + bool was_pending) { + DCHECK(subtract > 0); + if (was_pending) { + pending_push_registration_count_ -= subtract; + DCHECK(pending_push_registration_count_ >= 0); + } else { + push_registration_count_ -= subtract; + DCHECK(push_registration_count_ >= 0); + profile_->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount, + push_registration_count_); + } + if (push_registration_count_ + pending_push_registration_count_ == 0) { + GetGCMDriver()->RemoveAppHandler(kPushMessagingApplicationIdPrefix); + } +} + +bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const { + return PushMessagingApplicationId::Get(profile_, app_id).IsValid(); +} + +void PushMessagingServiceImpl::ShutdownHandler() { + // Shutdown() should come before and it removes us from the list of app + // handlers of gcm::GCMDriver so this shouldn't ever been called. + NOTREACHED(); +} + +// OnMessage methods ----------------------------------------------------------- + +void PushMessagingServiceImpl::OnMessage( + const std::string& app_id, + const gcm::GCMClient::IncomingMessage& message) { + PushMessagingApplicationId application_id = + PushMessagingApplicationId::Get(profile_, app_id); + // Drop message and unregister if app id was unknown (maybe recently deleted). + if (!application_id.IsValid()) { + DeliverMessageCallback(app_id, GURL::EmptyGURL(), -1, message, + content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID); + return; + } + // Drop message and unregister if |origin| has lost push permission. + if (!HasPermission(application_id.origin())) { + DeliverMessageCallback(app_id, application_id.origin(), + application_id.service_worker_registration_id(), + message, + content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED); + return; + } + + // The Push API only exposes a single string of data in the push event fired + // on the Service Worker. When developers send messages using GCM to the Push + // API and want to include a message payload, they must pass a single key- + // value pair, where the key is "data" and the value is the string they want + // to be passed to their Service Worker. For example, they could send the + // following JSON using the HTTPS GCM API: + // { + // "registration_ids": ["FOO", "BAR"], + // "data": { + // "data": "BAZ", + // }, + // "delay_while_idle": true, + // } + // TODO(johnme): Make sure this is clearly documented for developers. + std::string data; + // TODO(peter): Message payloads are disabled pending mandatory encryption. + // https://crbug.com/449184 + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnablePushMessagePayload)) { + gcm::GCMClient::MessageData::const_iterator it = message.data.find("data"); + if (it != message.data.end()) + data = it->second; + } + + content::BrowserContext::DeliverPushMessage( + profile_, + application_id.origin(), + application_id.service_worker_registration_id(), + data, + base::Bind(&PushMessagingServiceImpl::DeliverMessageCallback, + weak_factory_.GetWeakPtr(), + application_id.app_id_guid(), application_id.origin(), + application_id.service_worker_registration_id(), message)); +} + +void PushMessagingServiceImpl::DeliverMessageCallback( + const std::string& app_id_guid, + const GURL& requesting_origin, + int64 service_worker_registration_id, + const gcm::GCMClient::IncomingMessage& message, + content::PushDeliveryStatus status) { + // TODO(mvanouwerkerk): Show a warning in the developer console of the + // Service Worker corresponding to app_id (and/or on an internals page). + // TODO(mvanouwerkerk): Is there a way to recover from failure? + switch (status) { + // Call RequireUserVisibleUX if the message was delivered to the Service + // Worker JS, even if the website's event handler failed (to prevent sites + // deliberately failing in order to avoid having to show notifications). + case content::PUSH_DELIVERY_STATUS_SUCCESS: + case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED: + RequireUserVisibleUX(requesting_origin, service_worker_registration_id); + break; + case content::PUSH_DELIVERY_STATUS_INVALID_MESSAGE: + case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR: + break; + case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID: + case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED: + case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER: + Unregister(app_id_guid, message.sender_id, true /* retry_on_failure */, + UnregisterCallback()); + break; + } + RecordDeliveryStatus(status); +} + +void PushMessagingServiceImpl::RequireUserVisibleUX( + const GURL& requesting_origin, int64 service_worker_registration_id) { +#if defined(ENABLE_NOTIFICATIONS) + // TODO(johnme): Relax this heuristic slightly. + PlatformNotificationServiceImpl* notification_service = + PlatformNotificationServiceImpl::GetInstance(); + // Can't use g_browser_process->notification_ui_manager(), since the test uses + // PlatformNotificationServiceImpl::SetNotificationUIManagerForTesting. + // TODO(peter): Remove the need to use both APIs here once Notification.get() + // is supported. + int notification_count = notification_service->GetNotificationUIManager()-> + GetAllIdsByProfileAndSourceOrigin(profile_, requesting_origin).size(); + // TODO(johnme): Hiding an existing notification should also count as a useful + // user-visible action done in response to a push message - but make sure that + // sending two messages in rapid succession which show then hide a + // notification doesn't count. + bool notification_shown = notification_count > 0; + + bool notification_needed = true; + // Sites with a currently visible tab don't need to show notifications. +#if defined(OS_ANDROID) + for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) { + Profile* profile = (*it)->GetProfile(); + content::WebContents* active_web_contents = + (*it)->GetActiveWebContents(); +#else + for (chrome::BrowserIterator it; !it.done(); it.Next()) { + Profile* profile = it->profile(); + content::WebContents* active_web_contents = + it->tab_strip_model()->GetActiveWebContents(); +#endif + if (!active_web_contents || !active_web_contents->GetMainFrame()) + continue; + + // Don't leak information from other profiles. + if (profile != profile_) + continue; + + // Ignore minimized windows etc. + switch (active_web_contents->GetMainFrame()->GetVisibilityState()) { + case blink::WebPageVisibilityStateHidden: + case blink::WebPageVisibilityStatePrerender: + continue; + case blink::WebPageVisibilityStateVisible: + break; + } + + // Use the visible URL since that's the one the user is aware of (and it + // doesn't matter whether the page loaded successfully). + const GURL& active_url = active_web_contents->GetVisibleURL(); + if (requesting_origin == active_url.GetOrigin()) { + notification_needed = false; + break; + } +#if defined(OS_ANDROID) + } +#else + } +#endif + + // Don't track push messages that didn't show a notification but were exempt + // from needing to do so. + if (notification_shown || notification_needed) { + content::ServiceWorkerContext* service_worker_context = + content::BrowserContext::GetStoragePartitionForSite( + profile_, requesting_origin)->GetServiceWorkerContext(); + + PushMessagingService::GetNotificationsShownByLastFewPushes( + service_worker_context, service_worker_registration_id, + base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShown, + weak_factory_.GetWeakPtr(), + requesting_origin, service_worker_registration_id, + notification_shown, notification_needed)); + } else { + RecordUserVisibleStatus( + content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN); + } +#endif // defined(ENABLE_NOTIFICATIONS) +} + +static void IgnoreResult(bool unused) { +} + +void PushMessagingServiceImpl::DidGetNotificationsShown( + const GURL& requesting_origin, int64 service_worker_registration_id, + bool notification_shown, bool notification_needed, + const std::string& data, bool success, bool not_found) { + content::ServiceWorkerContext* service_worker_context = + content::BrowserContext::GetStoragePartitionForSite( + profile_, requesting_origin)->GetServiceWorkerContext(); + + // We remember whether the last (up to) 10 pushes showed notifications. + const size_t MISSED_NOTIFICATIONS_LENGTH = 10; + // data is a string like "0001000", where '0' means shown, and '1' means + // needed but not shown. We manipulate it in bitset form. + std::bitset<MISSED_NOTIFICATIONS_LENGTH> missed_notifications(data); + + bool needed_but_not_shown = notification_needed && !notification_shown; + + // New entries go at the end, and old ones are shifted off the beginning once + // the history length is exceeded. + missed_notifications <<= 1; + missed_notifications[0] = needed_but_not_shown; + std::string updated_data(missed_notifications. + to_string<char, std::string::traits_type, std::string::allocator_type>()); + PushMessagingService::SetNotificationsShownByLastFewPushes( + service_worker_context, service_worker_registration_id, + requesting_origin, updated_data, + base::Bind(&IgnoreResult)); // This is a heuristic; ignore failure. + + if (notification_shown) { + RecordUserVisibleStatus( + notification_needed + ? content::PUSH_USER_VISIBLE_STATUS_REQUIRED_AND_SHOWN + : content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_BUT_SHOWN); + return; + } + if (needed_but_not_shown) { + if (missed_notifications.count() <= 1) { + RecordUserVisibleStatus( + content::PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_USED_GRACE); + return; + } + RecordUserVisibleStatus( + content:: + PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED); + // The site failed to show a notification when one was needed, and they have + // already failed once in the previous 10 push messages, so we will show a + // generic notification. See https://crbug.com/437277. + // TODO(johnme): The generic notification should probably automatically + // close itself when the next push message arrives? + content::PlatformNotificationData notification_data; + // TODO(johnme): Switch to FormatOriginForDisplay from crbug.com/402698 + notification_data.title = base::UTF8ToUTF16(requesting_origin.host()); + notification_data.direction = + content::PlatformNotificationData::NotificationDirectionLeftToRight; + notification_data.body = + l10n_util::GetStringUTF16(IDS_PUSH_MESSAGING_GENERIC_NOTIFICATION_BODY); + notification_data.tag = + base::ASCIIToUTF16(kPushMessagingForcedNotificationTag); + notification_data.icon = GURL(); // TODO(johnme): Better icon? + PlatformNotificationServiceImpl* notification_service = + PlatformNotificationServiceImpl::GetInstance(); + notification_service->DisplayPersistentNotification( + profile_, + service_worker_registration_id, + requesting_origin, + SkBitmap() /* icon */, + notification_data); + } +} + +// Other gcm::GCMAppHandler methods ------------------------------------------- + +void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) { + // TODO(mvanouwerkerk): Fire push error event on the Service Worker + // corresponding to app_id. +} + +void PushMessagingServiceImpl::OnSendError( + const std::string& app_id, + const gcm::GCMClient::SendErrorDetails& send_error_details) { + NOTREACHED() << "The Push API shouldn't have sent messages upstream"; +} + +void PushMessagingServiceImpl::OnSendAcknowledged( + const std::string& app_id, + const std::string& message_id) { + NOTREACHED() << "The Push API shouldn't have sent messages upstream"; +} + +// GetPushEndpoint method ------------------------------------------------------ + +GURL PushMessagingServiceImpl::GetPushEndpoint() { + return GURL(std::string(kPushMessagingEndpoint)); +} + +// Register and GetPermissionStatus methods ------------------------------------ + +void PushMessagingServiceImpl::RegisterFromDocument( + const GURL& requesting_origin, + int64 service_worker_registration_id, + const std::string& sender_id, + int renderer_id, + int render_frame_id, + bool user_visible_only, + const content::PushMessagingService::RegisterCallback& callback) { + PushMessagingApplicationId application_id = + PushMessagingApplicationId::Generate(requesting_origin, + service_worker_registration_id); + DCHECK(application_id.IsValid()); + + if (push_registration_count_ + pending_push_registration_count_ + >= kMaxRegistrations) { + RegisterEnd(callback, + std::string(), + content::PUSH_REGISTRATION_STATUS_LIMIT_REACHED); + return; + } + + content::RenderFrameHost* render_frame_host = + content::RenderFrameHost::FromID(renderer_id, render_frame_id); + if (!render_frame_host) + return; + + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(render_frame_host); + if (!web_contents) + return; + + // TODO(miguelg) need to send this over IPC when bubble support is + // implemented. + int bridge_id = -1; + + const PermissionRequestID id( + renderer_id, web_contents->GetRoutingID(), bridge_id, GURL()); + + PushMessagingPermissionContext* permission_context = + PushMessagingPermissionContextFactory::GetForProfile(profile_); + + if (permission_context == NULL || !user_visible_only) { + RegisterEnd(callback, + std::string(), + content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); + return; + } + + // TODO(miguelg): Consider the value of |user_visible_only| when making + // the permission request. + // TODO(mlamouri): Move requesting Push permission over to using Mojo, and + // re-introduce the ability of |user_gesture| when bubbles require this. + // https://crbug.com/423770. + permission_context->RequestPermission( + web_contents, id, requesting_origin, true /* user_gesture */, + base::Bind(&PushMessagingServiceImpl::DidRequestPermission, + 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) { + PushMessagingApplicationId application_id = + PushMessagingApplicationId::Generate(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; + } + + 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; + } + + IncreasePushRegistrationCount(1, true /* is_pending */); + std::vector<std::string> sender_ids(1, sender_id); + GetGCMDriver()->Register( + application_id.app_id_guid(), sender_ids, + base::Bind(&PushMessagingServiceImpl::DidRegister, + weak_factory_.GetWeakPtr(), + application_id, register_callback)); +} + +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) { + callback.Run(registration_id, status); +} + +void PushMessagingServiceImpl::DidRegister( + const PushMessagingApplicationId& application_id, + const content::PushMessagingService::RegisterCallback& callback, + const std::string& registration_id, + gcm::GCMClient::Result result) { + content::PushRegistrationStatus status = + content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR; + switch (result) { + case gcm::GCMClient::SUCCESS: + status = content::PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE; + application_id.PersistToDisk(profile_); + IncreasePushRegistrationCount(1, false /* is_pending */); + break; + case gcm::GCMClient::INVALID_PARAMETER: + case gcm::GCMClient::GCM_DISABLED: + case gcm::GCMClient::ASYNC_OPERATION_PENDING: + case gcm::GCMClient::SERVER_ERROR: + case gcm::GCMClient::UNKNOWN_ERROR: + status = content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR; + break; + case gcm::GCMClient::NETWORK_ERROR: + case gcm::GCMClient::TTL_EXCEEDED: + status = content::PUSH_REGISTRATION_STATUS_NETWORK_ERROR; + break; + } + RegisterEnd(callback, registration_id, status); + DecreasePushRegistrationCount(1, true /* was_pending */); +} + +void PushMessagingServiceImpl::DidRequestPermission( + const PushMessagingApplicationId& application_id, + const std::string& sender_id, + const content::PushMessagingService::RegisterCallback& register_callback, + ContentSetting content_setting) { + if (content_setting != CONTENT_SETTING_ALLOW) { + RegisterEnd(register_callback, + std::string(), + content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); + return; + } + + IncreasePushRegistrationCount(1, true /* is_pending */); + std::vector<std::string> sender_ids(1, sender_id); + GetGCMDriver()->Register( + application_id.app_id_guid(), + sender_ids, + base::Bind(&PushMessagingServiceImpl::DidRegister, + weak_factory_.GetWeakPtr(), + application_id, register_callback)); +} + +// Unregister methods ---------------------------------------------------------- + +void PushMessagingServiceImpl::Unregister( + const GURL& requesting_origin, + int64 service_worker_registration_id, + const std::string& sender_id, + bool retry_on_failure, + const content::PushMessagingService::UnregisterCallback& callback) { + PushMessagingApplicationId application_id = PushMessagingApplicationId::Get( + profile_, requesting_origin, service_worker_registration_id); + if (!application_id.IsValid()) { + if (!callback.is_null()) { + callback.Run( + content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED); + } + return; + } + + Unregister(application_id.app_id_guid(), sender_id, retry_on_failure, + callback); +} + +void PushMessagingServiceImpl::Unregister( + const std::string& app_id_guid, + const std::string& sender_id, + bool retry_on_failure, + const content::PushMessagingService::UnregisterCallback& callback) { + if (retry_on_failure) { + // Delete the mapping for this app id, to guarantee that no messages get + // delivered in future (even if unregistration fails). + // TODO(johnme): Instead of deleting these app ids, store them elsewhere, + // and retry unregistration if it fails due to network errors. + PushMessagingApplicationId application_id = + PushMessagingApplicationId::Get(profile_, app_id_guid); + if (application_id.IsValid()) + application_id.DeleteFromDisk(profile_); + } + + const auto& unregister_callback = + base::Bind(&PushMessagingServiceImpl::DidUnregister, + weak_factory_.GetWeakPtr(), + app_id_guid, retry_on_failure, callback); +#if defined(OS_ANDROID) + // On Android the backend is different, and requires the original sender_id. + GetGCMDriver()->UnregisterWithSenderId(app_id_guid, sender_id, + unregister_callback); +#else + GetGCMDriver()->Unregister(app_id_guid, unregister_callback); +#endif +} + +void PushMessagingServiceImpl::DidUnregister( + const std::string& app_id_guid, + bool retry_on_failure, + const content::PushMessagingService::UnregisterCallback& callback, + gcm::GCMClient::Result result) { + if (result == gcm::GCMClient::SUCCESS) { + PushMessagingApplicationId application_id = + PushMessagingApplicationId::Get(profile_, app_id_guid); + if (!application_id.IsValid()) { + if (!callback.is_null()) { + callback.Run( + content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED); + } + return; + } + + application_id.DeleteFromDisk(profile_); + DecreasePushRegistrationCount(1, false /* was_pending */); + } + + // Internal calls pass a null callback. + if (!callback.is_null()) { + switch (result) { + case gcm::GCMClient::SUCCESS: + callback.Run(content::PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED); + break; + case gcm::GCMClient::INVALID_PARAMETER: + case gcm::GCMClient::GCM_DISABLED: + case gcm::GCMClient::ASYNC_OPERATION_PENDING: + case gcm::GCMClient::SERVER_ERROR: + case gcm::GCMClient::UNKNOWN_ERROR: + callback.Run(content::PUSH_UNREGISTRATION_STATUS_SERVICE_ERROR); + break; + case gcm::GCMClient::NETWORK_ERROR: + case gcm::GCMClient::TTL_EXCEEDED: + callback.Run( + retry_on_failure + ? content:: + PUSH_UNREGISTRATION_STATUS_PENDING_WILL_RETRY_NETWORK_ERROR + : content::PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR); + break; + } + } +} + +// OnContentSettingChanged methods --------------------------------------------- + +void PushMessagingServiceImpl::OnContentSettingChanged( + const ContentSettingsPattern& primary_pattern, + const ContentSettingsPattern& secondary_pattern, + ContentSettingsType content_type, + std::string resource_identifier) { + if (content_type != CONTENT_SETTINGS_TYPE_PUSH_MESSAGING && + content_type != CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { + return; + } + + for (const auto& id : PushMessagingApplicationId::GetAll(profile_)) { + // If |primary_pattern| is not valid, we should always check for a + // permission change because it can happen for example when the entire + // Push or Notifications permissions are cleared. + // Otherwise, the permission should be checked if the pattern matches the + // origin. + if (primary_pattern.IsValid() && !primary_pattern.Matches(id.origin())) + continue; + + if (HasPermission(id.origin())) + continue; + + PushMessagingService::GetSenderId( + profile_, id.origin(), id.service_worker_registration_id(), + base::Bind( + &PushMessagingServiceImpl::UnregisterBecausePermissionRevoked, + weak_factory_.GetWeakPtr(), id)); + } +} + +void PushMessagingServiceImpl::UnregisterBecausePermissionRevoked( + const PushMessagingApplicationId& id, + const std::string& sender_id, bool success, bool not_found) { + // Unregister the PushMessagingApplicationId with the push service. + Unregister(id.app_id_guid(), sender_id, true /* retry_on_failure */, + UnregisterCallback()); + + // Clear the associated service worker push registration id. + PushMessagingService::ClearPushRegistrationID( + profile_, id.origin(), id.service_worker_registration_id()); +} + +// KeyedService methods ------------------------------------------------------- + +void PushMessagingServiceImpl::Shutdown() { + GetGCMDriver()->RemoveAppHandler(kPushMessagingApplicationIdPrefix); +} + +// Helper methods -------------------------------------------------------------- + +bool PushMessagingServiceImpl::HasPermission(const GURL& origin) { + PushMessagingPermissionContext* permission_context = + PushMessagingPermissionContextFactory::GetForProfile(profile_); + DCHECK(permission_context); + + return permission_context->GetPermissionStatus(origin, origin) == + CONTENT_SETTING_ALLOW; +} + +gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const { + gcm::GCMProfileService* gcm_profile_service = + gcm::GCMProfileServiceFactory::GetForProfile(profile_); + CHECK(gcm_profile_service); + CHECK(gcm_profile_service->driver()); + return gcm_profile_service->driver(); +}
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.h b/chrome/browser/push_messaging/push_messaging_service_impl.h new file mode 100644 index 0000000..ed06b08 --- /dev/null +++ b/chrome/browser/push_messaging/push_messaging_service_impl.h
@@ -0,0 +1,173 @@ +// 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_PUSH_MESSAGING_PUSH_MESSAGING_SERVICE_IMPL_H_ +#define CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_SERVICE_IMPL_H_ + +#include "base/compiler_specific.h" +#include "base/memory/weak_ptr.h" +#include "components/content_settings/core/browser/content_settings_observer.h" +#include "components/content_settings/core/common/content_settings.h" +#include "components/gcm_driver/gcm_app_handler.h" +#include "components/gcm_driver/gcm_client.h" +#include "components/keyed_service/core/keyed_service.h" +#include "content/public/browser/push_messaging_service.h" +#include "content/public/common/push_messaging_status.h" +#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h" + +class Profile; +class PushMessagingApplicationId; + +namespace user_prefs { +class PrefRegistrySyncable; +} + +namespace gcm { +class GCMDriver; +class GCMProfileService; +} + +class PushMessagingServiceImpl : public content::PushMessagingService, + public gcm::GCMAppHandler, + public content_settings::Observer, + public KeyedService { + public: + // Register profile-specific prefs for GCM. + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); + + // If any Service Workers are using push, starts GCM and adds an app handler. + static void InitializeForProfile(Profile* profile); + + explicit PushMessagingServiceImpl(Profile* profile); + ~PushMessagingServiceImpl() override; + + // gcm::GCMAppHandler implementation. + void ShutdownHandler() override; + void OnMessage(const std::string& app_id, + const gcm::GCMClient::IncomingMessage& message) override; + void OnMessagesDeleted(const std::string& app_id) override; + void OnSendError( + const std::string& app_id, + const gcm::GCMClient::SendErrorDetails& send_error_details) override; + void OnSendAcknowledged(const std::string& app_id, + const std::string& message_id) override; + bool CanHandle(const std::string& app_id) const override; + + // content::PushMessagingService implementation: + GURL GetPushEndpoint() 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_visible_only, + 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; + void Unregister( + const GURL& requesting_origin, + int64 service_worker_registration_id, + const std::string& sender_id, + bool retry_on_failure, + const content::PushMessagingService::UnregisterCallback&) override; + blink::WebPushPermissionStatus GetPermissionStatus( + const GURL& requesting_origin, + const GURL& embedding_origin) override; + + // content_settings::Observer implementation. + void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern, + const ContentSettingsPattern& secondary_pattern, + ContentSettingsType content_type, + std::string resource_identifier) override; + + // KeyedService implementation. + void Shutdown() override; + + private: + // A registration is pending until it has succeeded or failed. + void IncreasePushRegistrationCount(int add, bool is_pending); + void DecreasePushRegistrationCount(int subtract, bool was_pending); + + // OnMessage methods --------------------------------------------------------- + + void DeliverMessageCallback(const std::string& app_id_guid, + const GURL& requesting_origin, + int64 service_worker_registration_id, + const gcm::GCMClient::IncomingMessage& message, + content::PushDeliveryStatus status); + + // Developers are required to display a Web Notification in response to an + // incoming push message in order to clarify to the user that something has + // happened in the background. When they forget to do so, display a default + // notification on their behalf. + void RequireUserVisibleUX(const GURL& requesting_origin, + int64 service_worker_registration_id); + void DidGetNotificationsShown( + const GURL& requesting_origin, + int64 service_worker_registration_id, + bool notification_shown, + bool notification_needed, + const std::string& data, + bool success, + bool not_found); + + // Register methods ---------------------------------------------------------- + + void RegisterEnd( + const content::PushMessagingService::RegisterCallback& callback, + const std::string& registration_id, + content::PushRegistrationStatus status); + + void DidRegister( + const PushMessagingApplicationId& application_id, + const content::PushMessagingService::RegisterCallback& callback, + const std::string& registration_id, + gcm::GCMClient::Result result); + + void DidRequestPermission( + const PushMessagingApplicationId& application_id, + const std::string& sender_id, + const content::PushMessagingService::RegisterCallback& callback, + ContentSetting content_setting); + + // Unregister methods -------------------------------------------------------- + + void Unregister(const std::string& app_id_guid, + const std::string& sender_id, + bool retry_on_failure, + const content::PushMessagingService::UnregisterCallback&); + + void DidUnregister(const std::string& app_id_guid, + bool retry_on_failure, + const content::PushMessagingService::UnregisterCallback&, + gcm::GCMClient::Result result); + + // OnContentSettingChanged methods ------------------------------------------- + + void UnregisterBecausePermissionRevoked(const PushMessagingApplicationId& id, + const std::string& sender_id, + bool success, bool not_found); + + // Helper methods ------------------------------------------------------------ + + // Checks if a given origin is allowed to use Push. + bool HasPermission(const GURL& origin); + + gcm::GCMDriver* GetGCMDriver() const; + + Profile* profile_; + + int push_registration_count_; + int pending_push_registration_count_; + + base::WeakPtrFactory<PushMessagingServiceImpl> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(PushMessagingServiceImpl); +}; + +#endif // CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_SERVICE_IMPL_H_
diff --git a/chrome/browser/resources/app_list/start_page.js b/chrome/browser/resources/app_list/start_page.js index c46b0ce..5138dba7 100644 --- a/chrome/browser/resources/app_list/start_page.js +++ b/chrome/browser/resources/app_list/start_page.js
@@ -6,13 +6,9 @@ * @fileoverview App launcher start page implementation. */ -<include src="speech_manager.js"> - cr.define('appList.startPage', function() { 'use strict'; - var speechManager = null; - // The element containing the current Google Doodle. var doodle = null; @@ -24,7 +20,6 @@ * Initialize the page. */ function initialize() { - speechManager = new speech.SpeechManager(); chrome.send('initialize'); } @@ -34,7 +29,6 @@ * @param {boolean} enabled Whether the plugin is enabled or not. */ function setHotwordEnabled(enabled) { - speechManager.setHotwordEnabled(enabled); } /** @@ -42,7 +36,6 @@ * @param {string} arch The architecture. */ function setNaclArch(arch) { - speechManager.setNaclArch(arch); } /** @@ -51,8 +44,6 @@ * @param {boolean} hotwordEnabled Whether the hotword is enabled or not. */ function onAppListShown(hotwordEnabled, legacySpeechEnabled) { - if (legacySpeechEnabled) - speechManager.onShown(hotwordEnabled); chrome.send('appListShown', [this.doodle != null]); } @@ -135,7 +126,6 @@ * Invoked when the app-list bubble is hidden. */ function onAppListHidden() { - speechManager.onHidden(); } /** @@ -143,7 +133,6 @@ * state. */ function toggleSpeechRecognition() { - speechManager.toggleSpeechRecognition(); } return {
diff --git a/chrome/browser/resources/chromeos/login/new/oobe.html b/chrome/browser/resources/chromeos/login/new/oobe.html deleted file mode 100644 index 46c3e05..0000000 --- a/chrome/browser/resources/chromeos/login/new/oobe.html +++ /dev/null
@@ -1,9 +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. --> - -<!doctype html> -<head> -<script src="chrome://oobe/oobe.js"></script> -</head> -Hello, world!
diff --git a/chrome/browser/resources/chromeos/login/new/oobe.js b/chrome/browser/resources/chromeos/login/new/oobe.js deleted file mode 100644 index cc5952c..0000000 --- a/chrome/browser/resources/chromeos/login/new/oobe.js +++ /dev/null
@@ -1,7 +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. - -window.addEventListener('load', function() { - console.log('Hello, world!'); -});
diff --git a/chrome/browser/resources/extensions/extension_list.js b/chrome/browser/resources/extensions/extension_list.js index c185b29b..16b1132 100644 --- a/chrome/browser/resources/extensions/extension_list.js +++ b/chrome/browser/resources/extensions/extension_list.js
@@ -384,8 +384,7 @@ // The 'allow file:// access' checkbox. row.setupColumn('.file-access-control input', 'localUrls', 'click', function(e) { - chrome.send('extensionSettingsAllowFileAccess', - [extension.id, String(e.target.checked)]); + chrome.developerPrivate.allowFileAccess(extension.id, e.target.checked); }); // The 'Options' button or link, depending on its behaviour. @@ -467,6 +466,17 @@ function() { // TODO(devlin): What should we do if the uninstall fails? this.uninstallIsShowing_ = false; + + if (trash.classList.contains('mouse-clicked')) + trash.blur(); + + if (chrome.runtime.lastError) { + // The uninstall failed (e.g. a cancel). Allow the trash to close. + trash.classList.remove('open'); + } else { + // Leave the trash open if the uninstall succeded. Otherwise it can + // half-close right before it's removed when the DOM is modified. + } }.bind(this)); }.bind(this)); row.querySelector('.enable-controls').appendChild(trash); @@ -900,13 +910,6 @@ }, }; - ExtensionList.uninstallCancel = function() { - var trash = document.querySelector('.trash.open'); - if (trash.classList.contains('mouse-clicked')) - trash.blur(); - trash.classList.remove('open'); - }; - return { ExtensionList: ExtensionList };
diff --git a/chrome/browser/resources/extensions/extension_loader.js b/chrome/browser/resources/extensions/extension_loader.js index e089c6f2..95def83d 100644 --- a/chrome/browser/resources/extensions/extension_loader.js +++ b/chrome/browser/resources/extensions/extension_loader.js
@@ -186,11 +186,25 @@ ExtensionLoader.prototype = { /** + * Whether or not we are currently loading an unpacked extension. + * @private {boolean} + */ + isLoading_: false, + + /** * Begin the sequence of loading an unpacked extension. If an error is * encountered, this object will get notified via notifyFailed(). */ loadUnpacked: function() { - chrome.send('extensionLoaderLoadUnpacked'); + if (this.isLoading_) // Only one running load at a time. + return; + this.isLoading_ = true; + chrome.developerPrivate.loadUnpacked({failQuietly: true}, function() { + // Check lastError to avoid the log, but don't do anything with it - + // error-handling is done on the C++ side. + var lastError = chrome.runtime.lastError; + this.isLoading_ = false; + }.bind(this)); }, /**
diff --git a/chrome/browser/resources/extensions/extensions.js b/chrome/browser/resources/extensions/extensions.js index 20b486f6..6500f07c 100644 --- a/chrome/browser/resources/extensions/extensions.js +++ b/chrome/browser/resources/extensions/extensions.js
@@ -343,28 +343,6 @@ ExtensionList.decorate($('extension-settings-list')); }; - // Indicate that warning |message| has occured for pack of |crx_path| and - // |pem_path| files. Ask if user wants override the warning. Send - // |overrideFlags| to repeated 'pack' call to accomplish the override. - ExtensionSettings.askToOverrideWarning = - function(message, crx_path, pem_path, overrideFlags) { - var closeAlert = function() { - ExtensionSettings.showOverlay(null); - }; - - alertOverlay.setValues( - loadTimeData.getString('packExtensionWarningTitle'), - message, - loadTimeData.getString('packExtensionProceedAnyway'), - loadTimeData.getString('cancel'), - function() { - chrome.send('pack', [crx_path, pem_path, overrideFlags]); - closeAlert(); - }, - closeAlert); - ExtensionSettings.showOverlay($('alertOverlay')); - }; - /** * Returns the current overlay or null if one does not exist. * @return {Element} The overlay element.
diff --git a/chrome/browser/resources/extensions/pack_extension_overlay.js b/chrome/browser/resources/extensions/pack_extension_overlay.js index 186f841..03e6180 100644 --- a/chrome/browser/resources/extensions/pack_extension_overlay.js +++ b/chrome/browser/resources/extensions/pack_extension_overlay.js
@@ -48,24 +48,26 @@ handleCommit_: function(e) { var extensionPath = $('extension-root-dir').value; var privateKeyPath = $('extension-private-key').value; - chrome.send('pack', [extensionPath, privateKeyPath, 0]); + chrome.developerPrivate.packDirectory( + extensionPath, privateKeyPath, 0, this.onPackResponse_.bind(this)); }, /** * Utility function which asks the C++ to show a platform-specific file - * select dialog, and fire |callback| with the |filePath| that resulted. - * |selectType| can be either 'file' or 'folder'. |operation| can be 'load' - * or 'pem' which are signals to the C++ to do some operation-specific - * configuration. + * select dialog, and set the value property of |node| to the selected path. + * @param {chrome.developerPrivate.SelectType} selectType + * The type of selection to use. + * @param {chrome.developerPrivate.FileType} fileType + * The type of file to select. + * @param {HTMLInputElement} node The node to set the value of. * @private */ - showFileDialog_: function(selectType, operation, callback) { - window.handleFilePathSelected = function(filePath) { - callback(filePath); - window.handleFilePathSelected = function() {}; - }; - - chrome.send('packExtensionSelectFilePath', [selectType, operation]); + showFileDialog_: function(selectType, fileType, node) { + chrome.developerPrivate.choosePath(selectType, fileType, function(path) { + // Last error is set if the user canceled the dialog. + if (!chrome.runtime.lastError && path) + node.value = path; + }); }, /** @@ -74,9 +76,10 @@ * @private */ handleBrowseExtensionDir_: function(e) { - this.showFileDialog_('folder', 'load', function(filePath) { - $('extension-root-dir').value = filePath; - }); + this.showFileDialog_( + chrome.developerPrivate.SelectType.FOLDER, + chrome.developerPrivate.FileType.LOAD, + /** @type {HTMLInputElement} */ ($('extension-root-dir'))); }, /** @@ -85,44 +88,76 @@ * @private */ handleBrowsePrivateKey_: function(e) { - this.showFileDialog_('file', 'pem', function(filePath) { - $('extension-private-key').value = filePath; - }); + this.showFileDialog_( + chrome.developerPrivate.SelectType.FILE, + chrome.developerPrivate.FileType.PEM, + /** @type {HTMLInputElement} */ ($('extension-private-key'))); }, - }; - /** - * Wrap up the pack process by showing the success |message| and closing - * the overlay. - * @param {string} message The message to show to the user. - */ - PackExtensionOverlay.showSuccessMessage = function(message) { - alertOverlay.setValues( - loadTimeData.getString('packExtensionOverlay'), - message, - loadTimeData.getString('ok'), - '', - function() { - extensions.ExtensionSettings.showOverlay(null); - }); - extensions.ExtensionSettings.showOverlay($('alertOverlay')); - }; + /** + * Handles a response from a packDirectory call. + * @param {PackDirectoryResponse} response The response of the pack call. + * @private + */ + onPackResponse_: function(response) { + /** @type {string} */ + var alertTitle; + /** @type {string} */ + var alertOk; + /** @type {string} */ + var alertCancel; + /** @type {function()} */ + var alertOkCallback; + /** @type {function()} */ + var alertCancelCallback; - /** - * Post an alert overlay showing |message|, and upon acknowledgement, close - * the alert overlay and return to showing the PackExtensionOverlay. - * @param {string} message The error message. - */ - PackExtensionOverlay.showError = function(message) { - alertOverlay.setValues( - loadTimeData.getString('packExtensionErrorTitle'), - message, - loadTimeData.getString('ok'), - '', - function() { - extensions.ExtensionSettings.showOverlay($('pack-extension-overlay')); - }); - extensions.ExtensionSettings.showOverlay($('alertOverlay')); + var closeAlert = function() { + extensions.ExtensionSettings.showOverlay(null); + }; + + switch (response.status) { + case chrome.developerPrivate.PackStatus.SUCCESS: + alertTitle = loadTimeData.getString('packExtensionOverlay'); + alertOk = loadTimeData.getString('ok'); + alertOkCallback = closeAlert; + // No 'Cancel' option. + break; + case chrome.developerPrivate.PackStatus.WARNING: + alertTitle = loadTimeData.getString('packExtensionWarningTitle'); + alertOk = loadTimeData.getString('packExtensionProceedAnyway'); + alertCancel = loadTimeData.getString('cancel'); + alertOkCallback = function() { + chrome.developerPrivate.packDirectory( + response.item_path, + response.pem_path, + response.override_flags, + this.onPackResponse_.bind(this)); + closeAlert(); + }.bind(this); + alertCancelCallback = closeAlert; + break; + case chrome.developerPrivate.PackStatus.ERROR: + alertTitle = loadTimeData.getString('packExtensionErrorTitle'); + alertOk = loadTimeData.getString('ok'); + alertOkCallback = function() { + extensions.ExtensionSettings.showOverlay( + $('pack-extension-overlay')); + }; + // No 'Cancel' option. + break; + default: + assertNotReached(); + return; + } + + alertOverlay.setValues(alertTitle, + response.message, + alertOk, + alertCancel, + alertOkCallback, + alertCancelCallback); + extensions.ExtensionSettings.showOverlay($('alertOverlay')); + }, }; // Export
diff --git a/chrome/browser/resources/feedback/js/event_handler.js b/chrome/browser/resources/feedback/js/event_handler.js index 636fdf17..5e662dd0 100644 --- a/chrome/browser/resources/feedback/js/event_handler.js +++ b/chrome/browser/resources/feedback/js/event_handler.js
@@ -52,6 +52,10 @@ '0F42756099D914A026DADFA182871C015735DD95', // Hangouts Extension '1B7734733E207CCE5C33BFAA544CA89634BF881F', // GLS nightly 'E2ACA3D943A3C96310523BCDFD8C3AF68387E6B7', // GLS stable + '11B478CEC461C766A2DC1E5BEEB7970AE06DC9C2', // http://crbug.com/463552 + '0EFB879311E9EFBB7C45251F89EC655711B1F6ED', // http://crbug.com/463552 + '9193D3A51E2FE33B496CDA53EA330423166E7F02', // http://crbug.com/463552 + 'F9119B8B18C7C82B51E7BC6FF816B694F2EC3E89', // http://crbug.com/463552 ];
diff --git a/chrome/browser/resources/history/history.js b/chrome/browser/resources/history/history.js index 85542c1..f76d339 100644 --- a/chrome/browser/resources/history/history.js +++ b/chrome/browser/resources/history/history.js
@@ -710,8 +710,8 @@ }); } - chrome.send('removeVisits', toBeRemoved); this.deleteCompleteCallback_ = callback; + chrome.send('removeVisits', toBeRemoved); }; /** @return {boolean} Whether the model is currently deleting a visit. */
diff --git a/chrome/browser/resources/history/other_devices.js b/chrome/browser/resources/history/other_devices.js index f0ebe80..5a3b21d 100644 --- a/chrome/browser/resources/history/other_devices.js +++ b/chrome/browser/resources/history/other_devices.js
@@ -513,9 +513,9 @@ continue; var grid = new cr.ui.FocusGrid(); - for (var i = 0; i < rows.length; ++i) { - DevicesViewFocusRow.decorate(rows[i], devices[i]); - grid.addRow(rows[i]); + for (var j = 0; j < rows.length; ++j) { + DevicesViewFocusRow.decorate(rows[j], devices[i]); + grid.addRow(rows[j]); } this.focusGrids_.push(grid); }
diff --git a/chrome/browser/resources/md_settings/md_settings.html b/chrome/browser/resources/md_settings/md_settings.html index c3b5842..7e33367 100644 --- a/chrome/browser/resources/md_settings/md_settings.html +++ b/chrome/browser/resources/md_settings/md_settings.html
@@ -8,6 +8,7 @@ <link rel="import" href="chrome://resources/polymer/core-menu/core-menu.html"> <link rel="import" href="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.html"> <link rel="import" href="chrome://resources/cr_elements/cr_collapse/cr_collapse.html"> + <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html"> <link rel="import" href="chrome://resources/cr_elements/cr_toggle_button/cr_toggle_button.html"> <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html"> <link rel="import" href="chrome://resources/cr_elements/cr_dropdown_menu/cr_dropdown_menu.html"> @@ -39,7 +40,7 @@ </cr-dropdown-menu> </section> <section> - <h2>cr-collapse</h2> + <h3>cr-collapse</h3> <paper-button id="manage-button" raised onclick="toggleCollapse();"> Toggle Collapse </paper-button> @@ -52,6 +53,10 @@ <cr-button>Flat button</cr-button> <cr-button raised>Raised Button</cr-button> </section> + <section> + <h3>cr-input</h3> + <cr-input label="Enter Something!"></cr-input> + </section> </div> <script> var collapse = document.getElementById('collapse');
diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html index 7c800e5e..1d47e66c 100644 --- a/chrome/browser/resources/options/browser_options.html +++ b/chrome/browser/resources/options/browser_options.html
@@ -21,6 +21,14 @@ <span i18n-content="useSharedProxies"></span> </label> </div> + <div id="captive-portal-bypass-proxy-div" class="checkbox" hidden> + <label> + <input id="enable-captive-portal-bypass-proxy" + pref="proxy.captive_portal_ignores_proxy" + metric="Options_CaptivePortalBypassProxy" type="checkbox"> + <span i18n-content="captivePortalBypassProxy"></span> + </label> + </div> <div id="network-menus"></div> </div> </section> @@ -306,11 +314,6 @@ </div> </div> <div class="checkbox settings-row"> - <label> - <input id="use-24hour-clock" pref="settings.clock.use_24hour_clock" - metric="Options_Use24HourClockCheckbox" type="checkbox"> - <span i18n-content="use24HourClock"></span> - </label> <div id="resolve-timezone-by-geolocation-selection" hidden> <label> <input id="resolve-timezone-by-geolocation" @@ -319,9 +322,12 @@ <span i18n-content="resolveTimezoneByGeoLocation"></span> </label> </div> + <label> + <input id="use-24hour-clock" pref="settings.clock.use_24hour_clock" + metric="Options_Use24HourClockCheckbox" type="checkbox"> + <span i18n-content="use24HourClock"></span> + </label> </div> - <div id="time-synced-explanation" class="settings-row" - i18n-content="timeSyncedExplanation"></div> <div id="set-time" class="settings-row" hidden> <button id="set-time-button" i18n-content="setTimeButton"></button>
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js index 3efebf9f..b22e5ba 100644 --- a/chrome/browser/resources/options/browser_options.js +++ b/chrome/browser/resources/options/browser_options.js
@@ -206,6 +206,9 @@ } options.network.NetworkList.refreshNetworkData( loadTimeData.getValue('networkData')); + if (loadTimeData.getBoolean('enableCaptivePortalBypassProxyOption')) { + $('captive-portal-bypass-proxy-div').hidden = false; + } } // On Startup section. @@ -407,6 +410,8 @@ if (loadTimeData.getBoolean('enableTimeZoneTrackingOption')) { $('resolve-timezone-by-geolocation-selection').hidden = false; this.setSystemTimezoneManaged_(false); + $('timezone-value-select').disabled = loadTimeData.getBoolean( + 'resolveTimezoneByGeolocationInitialValue'); } } @@ -2113,7 +2118,6 @@ */ setCanSetTime_: function(canSetTime) { // If the time has been network-synced, it cannot be set manually. - $('time-synced-explanation').hidden = canSetTime; $('set-time').hidden = !canSetTime; }, @@ -2192,6 +2196,7 @@ 'setMetricsReportingSettingVisibility', 'setProfilesInfo', 'setSpokenFeedbackCheckboxState', + 'setSystemTimezoneManaged', 'setThemesResetButtonEnabled', 'setVirtualKeyboardCheckboxState', 'setupPageZoomSelector',
diff --git a/chrome/browser/resources/print_preview/native_layer.js b/chrome/browser/resources/print_preview/native_layer.js index b148a1b8..1aebc71 100644 --- a/chrome/browser/resources/print_preview/native_layer.js +++ b/chrome/browser/resources/print_preview/native_layer.js
@@ -265,6 +265,7 @@ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF, 'printWithCloudPrint': destination != null && !destination.isLocal, 'printWithPrivet': destination != null && destination.isPrivet, + 'printWithExtension': destination != null && destination.isExtension, 'deviceName': destination == null ? 'foo' : destination.id, 'generateDraftData': documentInfo.isModifiable, 'fitToPageEnabled': printTicketStore.fitToPage.getValue(),
diff --git a/chrome/browser/resources/security_warnings/images/1x/brokenssl_red.png b/chrome/browser/resources/security_warnings/images/1x/brokenssl_red.png index 433b026..ddaabb1 100644 --- a/chrome/browser/resources/security_warnings/images/1x/brokenssl_red.png +++ b/chrome/browser/resources/security_warnings/images/1x/brokenssl_red.png Binary files differ
diff --git a/chrome/browser/resources/security_warnings/interstitial_v2.css b/chrome/browser/resources/security_warnings/interstitial_v2.css index a847191..920b644 100644 --- a/chrome/browser/resources/security_warnings/interstitial_v2.css +++ b/chrome/browser/resources/security_warnings/interstitial_v2.css
@@ -31,9 +31,8 @@ cursor: pointer; float: right; font-size: .875em; - height: 36px; - margin: -6px 0 0; - padding: 8px 24px; + margin: 0; + padding: 10px 24px; transition: box-shadow 200ms cubic-bezier(0.4, 0, 0.2, 1); } @@ -51,13 +50,14 @@ } #debugging { + display: inline; overflow: auto; } .debugging-content { line-height: 1em; margin-bottom: 0; - margin-top: 0; + margin-top: 1em; } .debugging-title { @@ -77,8 +77,8 @@ background: inherit; border: 0; float: none; - margin: -6px 0 0; - padding: 0; + margin: 0; + padding: 10px 0; text-decoration: underline; } @@ -86,16 +86,17 @@ box-shadow: inherit; } -#error-code { - color: black; - font-size: .825em; - opacity: .35; +.error-code { + color: #777; + display: inline; + font-size: .86667em; + margin-top: 15px; + opacity: .5; text-transform: uppercase; } #error-debugging-info { font-size: 0.8em; - overflow: auto; } h1 { @@ -141,6 +142,10 @@ width: 100%; } +#main-message > p { + display: inline; +} + #malware-opt-in { font-size: .875em; margin-top: 39px; @@ -178,18 +183,16 @@ box-shadow: 0 2px 3px rgba(0, 0, 0, .5); } +.safe-browsing .error-code { + display: none; +} + .safe-browsing .icon { background-image: -webkit-image-set( url(images/1x/stop_sign.png) 1x, url(images/2x/stop_sign.png) 2x); } -.secondary-button { - -webkit-margin-end: 16px; - background: #d9d9d9; - color: #696969; -} - .small-link { color: #696969; font-size: .875em; @@ -239,7 +242,7 @@ content: ''; height: 4px; left: 2px; - opacity: 0.3; + opacity: 0; position: absolute; top: 3px; transform: rotate(-45deg); @@ -254,9 +257,17 @@ .interstitial-wrapper { padding: 0 10%; } + + #error-debugging-info { + overflow: auto; + } } @media (max-height: 600px) { + .error-code { + margin-top: 10px; + } + .interstitial-wrapper { margin-top: 13%; } @@ -358,6 +369,10 @@ width: 100%; } + .error-code { + margin-top: 0; + } + #details { box-sizing: border-box; height: auto;
diff --git a/chrome/browser/resources/security_warnings/interstitial_v2.html b/chrome/browser/resources/security_warnings/interstitial_v2.html index e285441..b06fe1f 100644 --- a/chrome/browser/resources/security_warnings/interstitial_v2.html +++ b/chrome/browser/resources/security_warnings/interstitial_v2.html
@@ -20,6 +20,10 @@ <div id="main-message"> <h1 i18n-content="heading"></h1> <p i18n-values=".innerHTML:primaryParagraph"></p> + <div id="debugging"> + <div id="error-code" class="error-code"></div> + <div id="error-debugging-info" class="hidden"></div> + </div> </div> <div id="malware-opt-in" class="hidden"> <div class="styled-checkbox"> @@ -39,10 +43,6 @@ <div id="details" class="hidden"> <p i18n-values=".innerHTML:explanationParagraph"></p> <p i18n-values=".innerHTML:finalParagraph" id="final-paragraph"></p> - <div id="debugging"> - <p id="error-code"></p> - <div id="error-debugging-info" class="hidden"></div> - </div> </div> </div> </body>
diff --git a/chrome/browser/resources/security_warnings/interstitial_v2_mobile.js b/chrome/browser/resources/security_warnings/interstitial_v2_mobile.js index af0a21d..c482d6f 100644 --- a/chrome/browser/resources/security_warnings/interstitial_v2_mobile.js +++ b/chrome/browser/resources/security_warnings/interstitial_v2_mobile.js
@@ -15,6 +15,7 @@ '(orientation: portrait), (max-width: 736px) and ' + '(max-height: 420px) and (orientation: landscape)'; var detailsHidden = helpOuterBox.classList.contains('hidden'); + var runnerContainer = document.querySelector('.runner-container'); // Check for change in nav status. if (mobileNav != window.matchMedia(mediaQuery).matches) { @@ -24,10 +25,16 @@ if (mobileNav) { mainContent.classList.toggle('hidden', !detailsHidden); helpOuterBox.classList.toggle('hidden', detailsHidden); + if (runnerContainer) { + runnerContainer.classList.toggle('hidden', !detailsHidden); + } } else if (!detailsHidden) { // Non mobile nav with visible details. mainContent.classList.remove('hidden'); helpOuterBox.classList.remove('hidden'); + if (runnerContainer) { + runnerContainer.classList.remove('hidden'); + } } } }
diff --git a/chrome/browser/resources/whispernet_proxy/js/nacl.js b/chrome/browser/resources/whispernet_proxy/js/nacl.js index 06f566c..da8e48ca 100644 --- a/chrome/browser/resources/whispernet_proxy/js/nacl.js +++ b/chrome/browser/resources/whispernet_proxy/js/nacl.js
@@ -20,7 +20,7 @@ /** * Method to send generic byte data to the whispernet wrapper. - * @param {string} data Raw data to send to the whispernet wrapper. + * @param {Object} data Raw data to send to the whispernet wrapper. */ NaclBridge.prototype.send = function(data) { if (this.isEnabled_) {
diff --git a/chrome/browser/resources/whispernet_proxy/js/wrapper.js b/chrome/browser/resources/whispernet_proxy/js/wrapper.js index 8203b9a..29b57f7f 100644 --- a/chrome/browser/resources/whispernet_proxy/js/wrapper.js +++ b/chrome/browser/resources/whispernet_proxy/js/wrapper.js
@@ -14,7 +14,7 @@ var bstr = ''; for (var i = 0; i < bytes.length; ++i) bstr += String.fromCharCode(bytes[i]); - return btoa(bstr).replace('=', ''); + return btoa(bstr).replace(/=/g, ''); } /**
diff --git a/chrome/browser/resources/whispernet_proxy/whispernet_proxy.nmf.png b/chrome/browser/resources/whispernet_proxy/whispernet_proxy.nmf.png index 1fed28b..91e5dd8 100644 --- a/chrome/browser/resources/whispernet_proxy/whispernet_proxy.nmf.png +++ b/chrome/browser/resources/whispernet_proxy/whispernet_proxy.nmf.png
@@ -1,7 +1,7 @@ { "program": { "portable": { - "pnacl-translate": { "url": "whispernet_proxy_pnacl.pexe.png?v00006" } + "pnacl-translate": { "url": "whispernet_proxy_pnacl.pexe.png?v00007" } } } }
diff --git a/chrome/browser/resources/whispernet_proxy/whispernet_proxy_pnacl.pexe.png b/chrome/browser/resources/whispernet_proxy/whispernet_proxy_pnacl.pexe.png index e199b554..ba942829 100644 --- a/chrome/browser/resources/whispernet_proxy/whispernet_proxy_pnacl.pexe.png +++ b/chrome/browser/resources/whispernet_proxy/whispernet_proxy_pnacl.pexe.png Binary files differ
diff --git a/chrome/browser/safe_browsing/binary_feature_extractor.h b/chrome/browser/safe_browsing/binary_feature_extractor.h index fc657361..4d98a164 100644 --- a/chrome/browser/safe_browsing/binary_feature_extractor.h +++ b/chrome/browser/safe_browsing/binary_feature_extractor.h
@@ -23,6 +23,12 @@ class BinaryFeatureExtractor : public base::RefCountedThreadSafe<BinaryFeatureExtractor> { public: + // The type and defined values for a bitfield that controls aspects of image + // header extraction. + typedef uint32_t ExtractHeadersOption; + static const ExtractHeadersOption kDefaultOptions = 0; + static const ExtractHeadersOption kOmitExports = 1U << 0; + BinaryFeatureExtractor(); // Fills in the DownloadRequest_SignatureInfo for the given file path. @@ -32,8 +38,11 @@ ClientDownloadRequest_SignatureInfo* signature_info); // Populates |image_headers| with the PE image headers of |file_path|. - virtual void ExtractImageHeaders( + // |options| is a bitfield controlling aspects of extraction. Returns true if + // |image_headers| is populated with any information. + virtual bool ExtractImageHeaders( const base::FilePath& file_path, + ExtractHeadersOption options, ClientDownloadRequest_ImageHeaders* image_headers); // Populates |digests.sha256| with the SHA256 digest of |file_path|.
diff --git a/chrome/browser/safe_browsing/binary_feature_extractor_posix.cc b/chrome/browser/safe_browsing/binary_feature_extractor_posix.cc index a7da722..1c395c8 100644 --- a/chrome/browser/safe_browsing/binary_feature_extractor_posix.cc +++ b/chrome/browser/safe_browsing/binary_feature_extractor_posix.cc
@@ -17,8 +17,11 @@ const base::FilePath& file_path, ClientDownloadRequest_SignatureInfo* signature_info) {} -void BinaryFeatureExtractor::ExtractImageHeaders( +bool BinaryFeatureExtractor::ExtractImageHeaders( const base::FilePath& file_path, - ClientDownloadRequest_ImageHeaders* image_headers) {} + ExtractHeadersOption options, + ClientDownloadRequest_ImageHeaders* image_headers) { + return false; +} } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/binary_feature_extractor_win.cc b/chrome/browser/safe_browsing/binary_feature_extractor_win.cc index 12d5a71e..48b5c5ad 100644 --- a/chrome/browser/safe_browsing/binary_feature_extractor_win.cc +++ b/chrome/browser/safe_browsing/binary_feature_extractor_win.cc
@@ -90,17 +90,18 @@ } } -void BinaryFeatureExtractor::ExtractImageHeaders( +bool BinaryFeatureExtractor::ExtractImageHeaders( const base::FilePath& file_path, + ExtractHeadersOption options, ClientDownloadRequest_ImageHeaders* image_headers) { // Map the file into memory. base::MemoryMappedFile file; if (!file.Initialize(file_path)) - return; + return false; PeImageReader pe_image; if (!pe_image.Initialize(file.data(), file.length())) - return; + return false; // Copy the headers. ClientDownloadRequest_PEImageHeaders* pe_headers = @@ -123,10 +124,12 @@ pe_headers->add_section_header(pe_image.GetSectionHeaderAt(i), sizeof(IMAGE_SECTION_HEADER)); } - size_t export_size = 0; - const uint8_t* export_section = pe_image.GetExportSection(&export_size); - if (export_section) - pe_headers->set_export_section_data(export_section, export_size); + if (!(options & kOmitExports)) { + size_t export_size = 0; + const uint8_t* export_section = pe_image.GetExportSection(&export_size); + if (export_section) + pe_headers->set_export_section_data(export_section, export_size); + } size_t number_of_debug_entries = pe_image.GetNumberOfDebugEntries(); for (size_t i = 0; i != number_of_debug_entries; ++i) { const uint8_t* raw_data = NULL; @@ -142,6 +145,8 @@ debug_data->set_raw_data(raw_data, raw_data_size); } } + + return true; } } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/binary_feature_extractor_win_unittest.cc b/chrome/browser/safe_browsing/binary_feature_extractor_win_unittest.cc index ae149ad1..4e00b19 100644 --- a/chrome/browser/safe_browsing/binary_feature_extractor_win_unittest.cc +++ b/chrome/browser/safe_browsing/binary_feature_extractor_win_unittest.cc
@@ -107,27 +107,30 @@ TEST_F(BinaryFeatureExtractorWinTest, ExtractImageHeadersNoFile) { // Test extracting headers from a file that doesn't exist. ClientDownloadRequest_ImageHeaders image_headers; - binary_feature_extractor_->ExtractImageHeaders( + ASSERT_FALSE(binary_feature_extractor_->ExtractImageHeaders( testdata_path_.AppendASCII("this_file_does_not_exist"), - &image_headers); + BinaryFeatureExtractor::kDefaultOptions, + &image_headers)); EXPECT_FALSE(image_headers.has_pe_headers()); } TEST_F(BinaryFeatureExtractorWinTest, ExtractImageHeadersNonImage) { // Test extracting headers from something that is not a PE image. ClientDownloadRequest_ImageHeaders image_headers; - binary_feature_extractor_->ExtractImageHeaders( + ASSERT_FALSE(binary_feature_extractor_->ExtractImageHeaders( testdata_path_.AppendASCII("simple_exe.cc"), - &image_headers); + BinaryFeatureExtractor::kDefaultOptions, + &image_headers)); EXPECT_FALSE(image_headers.has_pe_headers()); } TEST_F(BinaryFeatureExtractorWinTest, ExtractImageHeaders) { // Test extracting headers from something that is a PE image. ClientDownloadRequest_ImageHeaders image_headers; - binary_feature_extractor_->ExtractImageHeaders( + ASSERT_TRUE(binary_feature_extractor_->ExtractImageHeaders( testdata_path_.AppendASCII("unsigned.exe"), - &image_headers); + BinaryFeatureExtractor::kDefaultOptions, + &image_headers)); EXPECT_TRUE(image_headers.has_pe_headers()); const ClientDownloadRequest_PEImageHeaders& pe_headers = image_headers.pe_headers(); @@ -143,9 +146,10 @@ TEST_F(BinaryFeatureExtractorWinTest, ExtractImageHeadersWithDebugData) { // Test extracting headers from something that is a PE image with debug data. ClientDownloadRequest_ImageHeaders image_headers; - binary_feature_extractor_->ExtractImageHeaders( + ASSERT_TRUE(binary_feature_extractor_->ExtractImageHeaders( testdata_path_.DirName().AppendASCII("module_with_exports_x86.dll"), - &image_headers); + BinaryFeatureExtractor::kDefaultOptions, + &image_headers)); EXPECT_TRUE(image_headers.has_pe_headers()); const ClientDownloadRequest_PEImageHeaders& pe_headers = image_headers.pe_headers(); @@ -158,4 +162,23 @@ EXPECT_EQ(1U, pe_headers.debug_data_size()); } +TEST_F(BinaryFeatureExtractorWinTest, ExtractImageHeadersWithoutExports) { + // Test extracting headers from something that is a PE image with debug data. + ClientDownloadRequest_ImageHeaders image_headers; + ASSERT_TRUE(binary_feature_extractor_->ExtractImageHeaders( + testdata_path_.DirName().AppendASCII("module_with_exports_x86.dll"), + BinaryFeatureExtractor::kOmitExports, + &image_headers)); + EXPECT_TRUE(image_headers.has_pe_headers()); + const ClientDownloadRequest_PEImageHeaders& pe_headers = + image_headers.pe_headers(); + EXPECT_TRUE(pe_headers.has_dos_header()); + EXPECT_TRUE(pe_headers.has_file_header()); + EXPECT_TRUE(pe_headers.has_optional_headers32()); + EXPECT_FALSE(pe_headers.has_optional_headers64()); + EXPECT_NE(0, pe_headers.section_header_size()); + EXPECT_FALSE(pe_headers.has_export_section_data()); + EXPECT_EQ(1U, pe_headers.debug_data_size()); +} + } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc index 7269a4f..e6148934 100644 --- a/chrome/browser/safe_browsing/download_protection_service.cc +++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -555,7 +555,13 @@ base::TimeTicks::Now() - start_time); start_time = base::TimeTicks::Now(); - binary_feature_extractor_->ExtractImageHeaders(file_path, &image_headers_); + image_headers_.reset(new ClientDownloadRequest_ImageHeaders()); + if (!binary_feature_extractor_->ExtractImageHeaders( + file_path, + BinaryFeatureExtractor::kDefaultOptions, + image_headers_.get())) { + image_headers_.reset(); + } UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractImageHeadersTime", base::TimeTicks::Now() - start_time); @@ -761,7 +767,8 @@ item_->GetTargetFilePath().BaseName().AsUTF8Unsafe()); request.set_download_type(type_); request.mutable_signature()->CopyFrom(signature_info_); - request.mutable_image_headers()->CopyFrom(image_headers_); + if (image_headers_) + request.set_allocated_image_headers(image_headers_.release()); if (!request.SerializeToString(&client_download_request_data_)) { FinishRequest(UNKNOWN, REASON_INVALID_REQUEST_PROTO); return; @@ -910,7 +917,7 @@ bool zipped_executable_; ClientDownloadRequest_SignatureInfo signature_info_; - ClientDownloadRequest_ImageHeaders image_headers_; + scoped_ptr<ClientDownloadRequest_ImageHeaders> image_headers_; CheckDownloadCallback callback_; // Will be NULL if the request has been canceled. DownloadProtectionService* service_;
diff --git a/chrome/browser/safe_browsing/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection_service_unittest.cc index 628211f..237af0a 100644 --- a/chrome/browser/safe_browsing/download_protection_service_unittest.cc +++ b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
@@ -111,7 +111,8 @@ MockBinaryFeatureExtractor() {} MOCK_METHOD2(CheckSignature, void(const base::FilePath&, ClientDownloadRequest_SignatureInfo*)); - MOCK_METHOD2(ExtractImageHeaders, void(const base::FilePath&, + MOCK_METHOD3(ExtractImageHeaders, bool(const base::FilePath&, + ExtractHeadersOption, ClientDownloadRequest_ImageHeaders*)); protected: @@ -156,7 +157,8 @@ } ACTION_P(SetDosHeaderContents, contents) { - arg1->mutable_pe_headers()->set_dos_header(contents); + arg2->mutable_pe_headers()->set_dos_header(contents); + return true; } ACTION_P(TrustSignature, certificate_file) { @@ -215,6 +217,8 @@ sb_service_ = new StrictMock<FakeSafeBrowsingService>(); sb_service_->Initialize(); binary_feature_extractor_ = new StrictMock<MockBinaryFeatureExtractor>(); + ON_CALL(*binary_feature_extractor_, ExtractImageHeaders(_, _, _)) + .WillByDefault(Return(true)); download_service_ = sb_service_->download_protection_service(); download_service_->binary_feature_extractor_ = binary_feature_extractor_; download_service_->SetEnabled(true); @@ -496,8 +500,9 @@ EXPECT_CALL(item, GetRemoteAddress()).WillRepeatedly(Return("")); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(a_tmp, _)) .Times(4); - EXPECT_CALL(*binary_feature_extractor_.get(), ExtractImageHeaders(a_tmp, _)) - .Times(4); + EXPECT_CALL(*binary_feature_extractor_.get(), + ExtractImageHeaders( + a_tmp, BinaryFeatureExtractor::kDefaultOptions, _)).Times(4); // We should not get whilelist checks for other URLs than specified below. EXPECT_CALL(*sb_service_->mock_database_manager(), @@ -620,7 +625,9 @@ MatchDownloadWhitelistUrl(_)) .WillRepeatedly(Return(false)); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(a_tmp, _)); - EXPECT_CALL(*binary_feature_extractor_.get(), ExtractImageHeaders(a_tmp, _)); + EXPECT_CALL( + *binary_feature_extractor_.get(), + ExtractImageHeaders(a_tmp, BinaryFeatureExtractor::kDefaultOptions, _)); download_service_->CheckClientDownload( &item, @@ -665,8 +672,9 @@ .WillRepeatedly(Return(false)); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(a_tmp, _)) .Times(6); - EXPECT_CALL(*binary_feature_extractor_.get(), ExtractImageHeaders(a_tmp, _)) - .Times(6); + EXPECT_CALL(*binary_feature_extractor_.get(), + ExtractImageHeaders( + a_tmp, BinaryFeatureExtractor::kDefaultOptions, _)).Times(6); download_service_->CheckClientDownload( &item, @@ -853,8 +861,9 @@ .WillRepeatedly(Return(false)); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(a_tmp, _)) .Times(1); - EXPECT_CALL(*binary_feature_extractor_.get(), ExtractImageHeaders(a_tmp, _)) - .Times(1); + EXPECT_CALL(*binary_feature_extractor_.get(), + ExtractImageHeaders( + a_tmp, BinaryFeatureExtractor::kDefaultOptions, _)).Times(1); download_service_->CheckClientDownload( &item, @@ -909,8 +918,9 @@ MatchDownloadWhitelistUrl(_)).WillRepeatedly(Return(false)); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(a_tmp, _)) .Times(1); - EXPECT_CALL(*binary_feature_extractor_.get(), ExtractImageHeaders(a_tmp, _)) - .Times(1); + EXPECT_CALL(*binary_feature_extractor_.get(), + ExtractImageHeaders( + a_tmp, BinaryFeatureExtractor::kDefaultOptions, _)).Times(1); download_service_->CheckClientDownload( &item, @@ -969,8 +979,9 @@ MatchDownloadWhitelistUrl(_)).WillRepeatedly(Return(false)); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(a_tmp, _)) .Times(1); - EXPECT_CALL(*binary_feature_extractor_.get(), ExtractImageHeaders(a_tmp, _)) - .Times(1); + EXPECT_CALL(*binary_feature_extractor_.get(), + ExtractImageHeaders( + a_tmp, BinaryFeatureExtractor::kDefaultOptions, _)).Times(1); download_service_->CheckClientDownload( &item, @@ -1206,8 +1217,9 @@ .WillRepeatedly(Return(false)); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(a_tmp, _)) .Times(1); - EXPECT_CALL(*binary_feature_extractor_.get(), ExtractImageHeaders(a_tmp, _)) - .Times(1); + EXPECT_CALL(*binary_feature_extractor_.get(), + ExtractImageHeaders( + a_tmp, BinaryFeatureExtractor::kDefaultOptions, _)).Times(1); EXPECT_FALSE(download_service_->IsSupportedDownload(item, a_crx)); download_service_->CheckClientDownload( @@ -1254,8 +1266,9 @@ .WillRepeatedly(Return(false)); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path, _)) .WillOnce(SetCertificateContents("dummy cert data")); - EXPECT_CALL(*binary_feature_extractor_.get(), - ExtractImageHeaders(tmp_path, _)) + EXPECT_CALL( + *binary_feature_extractor_.get(), + ExtractImageHeaders(tmp_path, BinaryFeatureExtractor::kDefaultOptions, _)) .WillOnce(SetDosHeaderContents("dummy dos header")); download_service_->CheckClientDownload( &item, @@ -1300,8 +1313,9 @@ .WillRepeatedly(Return(false)); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path, _)) .WillOnce(SetCertificateContents("dummy cert data")); - EXPECT_CALL(*binary_feature_extractor_.get(), - ExtractImageHeaders(tmp_path, _)) + EXPECT_CALL( + *binary_feature_extractor_.get(), + ExtractImageHeaders(tmp_path, BinaryFeatureExtractor::kDefaultOptions, _)) .WillOnce(SetDosHeaderContents("dummy dos header")); download_service_->CheckClientDownload( &item, @@ -1390,7 +1404,8 @@ .WillRepeatedly(Return(false)); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path, _)); EXPECT_CALL(*binary_feature_extractor_.get(), - ExtractImageHeaders(tmp_path, _)); + ExtractImageHeaders(tmp_path, + BinaryFeatureExtractor::kDefaultOptions, _)); download_service_->CheckClientDownload( &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, @@ -1475,8 +1490,9 @@ .WillRepeatedly(Return(false)); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path, _)) .WillRepeatedly(SetCertificateContents("dummy cert data")); - EXPECT_CALL(*binary_feature_extractor_.get(), - ExtractImageHeaders(tmp_path, _)) + EXPECT_CALL( + *binary_feature_extractor_.get(), + ExtractImageHeaders(tmp_path, BinaryFeatureExtractor::kDefaultOptions, _)) .WillRepeatedly(SetDosHeaderContents("dummy dos header")); // First test with no history match for the tab URL. @@ -1718,7 +1734,8 @@ .WillRepeatedly(Return(false)); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path, _)); EXPECT_CALL(*binary_feature_extractor_.get(), - ExtractImageHeaders(tmp_path, _)); + ExtractImageHeaders(tmp_path, + BinaryFeatureExtractor::kDefaultOptions, _)); download_service_->download_request_timeout_ms_ = 10; download_service_->CheckClientDownload( @@ -1769,7 +1786,8 @@ .WillRepeatedly(Return(false)); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path, _)); EXPECT_CALL(*binary_feature_extractor_.get(), - ExtractImageHeaders(tmp_path, _)); + ExtractImageHeaders( + tmp_path, BinaryFeatureExtractor::kDefaultOptions, _)); download_service_->CheckClientDownload( &item, @@ -1817,7 +1835,8 @@ })); EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path, _)); EXPECT_CALL(*binary_feature_extractor_.get(), - ExtractImageHeaders(tmp_path, _)); + ExtractImageHeaders(tmp_path, + BinaryFeatureExtractor::kDefaultOptions, _)); download_service_->CheckClientDownload( item.get(),
diff --git a/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer_win.cc b/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer_win.cc index a40fd08..fafc62b 100644 --- a/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer_win.cc +++ b/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer_win.cc
@@ -92,8 +92,12 @@ base::TimeTicks::Now() - start_time); // Image headers. - binary_feature_extractor->ExtractImageHeaders( - module_path, blacklist_load->mutable_image_headers()); + if (!binary_feature_extractor->ExtractImageHeaders( + module_path, + BinaryFeatureExtractor::kDefaultOptions, + blacklist_load->mutable_image_headers())) { + blacklist_load->clear_image_headers(); + } // Send the report. incident_receiver->AddIncidentForProcess(
diff --git a/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win.cc b/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win.cc index 8e8cd30..74caeed 100644 --- a/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win.cc +++ b/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win.cc
@@ -8,12 +8,14 @@ #include <set> #include "base/i18n/case_conversion.h" +#include "base/memory/ref_counted.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/win/registry.h" #include "chrome/browser/install_verification/win/module_info.h" #include "chrome/browser/install_verification/win/module_verification_common.h" #include "chrome/browser/net/service_providers_win.h" +#include "chrome/browser/safe_browsing/binary_feature_extractor.h" #include "chrome/browser/safe_browsing/incident_reporting/module_integrity_verifier_win.h" #include "chrome/browser/safe_browsing/path_sanitizer.h" #include "chrome/common/safe_browsing/csd.pb.h" @@ -59,18 +61,28 @@ if (!GetLoadedModules(&loaded_modules)) return false; - // Sanitize path of each module and add it to the incident report. + // Sanitize path of each module and add it to the incident report along with + // its headers. PathSanitizer path_sanitizer; - for (std::set<ModuleInfo>::const_iterator it = loaded_modules.begin(); - it != loaded_modules.end(); - ++it) { - base::FilePath dll_path(it->name); - path_sanitizer.StripHomeDirectory(&dll_path); + scoped_refptr<BinaryFeatureExtractor> feature_extractor( + new BinaryFeatureExtractor()); + for (const auto& module : loaded_modules) { + base::FilePath dll_path(module.name); + base::FilePath sanitized_path(dll_path); + path_sanitizer.StripHomeDirectory(&sanitized_path); ClientIncidentReport_EnvironmentData_Process_Dll* dll = process->add_dll(); - dll->set_path(base::WideToUTF8(base::i18n::ToLower(dll_path.value()))); - dll->set_base_address(it->base_address); - dll->set_length(it->size); + dll->set_path( + base::WideToUTF8(base::i18n::ToLower(sanitized_path.value()))); + dll->set_base_address(module.base_address); + dll->set_length(module.size); + // TODO(grt): Consider skipping this for valid system modules. + if (!feature_extractor->ExtractImageHeaders( + dll_path, + BinaryFeatureExtractor::kOmitExports, + dll->mutable_image_headers())) { + dll->clear_image_headers(); + } } return true;
diff --git a/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win_unittest.cc index b5b559b..9be80141 100644 --- a/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win_unittest.cc +++ b/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win.h" +#include <algorithm> #include <string> #include "base/base_paths.h" @@ -21,43 +22,39 @@ #include "net/base/winsock_init.h" #include "testing/gtest/include/gtest/gtest.h" +namespace safe_browsing { + namespace { const wchar_t test_dll[] = L"test_name.dll"; -// Helper function that returns true if a dll with filename |dll_name| is -// found in |process_report|. -bool ProcessReportContainsDll( - const safe_browsing::ClientIncidentReport_EnvironmentData_Process& - process_report, - const base::FilePath& dll_name) { - for (int i = 0; i < process_report.dll_size(); ++i) { - base::FilePath current_dll = - base::FilePath::FromUTF8Unsafe(process_report.dll(i).path()); - - if (current_dll.BaseName() == dll_name) +// Returns true if a dll with filename |dll_name| is found in |process_report|, +// providing a copy of it in |result|. +bool GetProcessReportDll( + const ClientIncidentReport_EnvironmentData_Process& process_report, + const base::FilePath& dll_name, + ClientIncidentReport_EnvironmentData_Process_Dll* result) { + for (const auto& dll : process_report.dll()) { + if (base::FilePath::FromUTF8Unsafe(dll.path()).BaseName() == dll_name) { + result->CopyFrom(dll); return true; + } } - return false; } // Look through dll entries and check for the presence of the LSP feature for -// |dll|. +// |dll_path|. bool DllEntryContainsLspFeature( - const safe_browsing::ClientIncidentReport_EnvironmentData_Process& - process_report, - const std::string& dll) { - for (int i = 0; i < process_report.dll_size(); ++i) { - if (process_report.dll(i).path() == dll) { - // Verify each feature of |dll|. - for (int j = 0; j < process_report.dll(i).feature_size(); ++j) { - if (process_report.dll(i).feature(j) == - safe_browsing::ClientIncidentReport_EnvironmentData_Process_Dll:: - LSP) - // LSP feature found. - return true; - } + const ClientIncidentReport_EnvironmentData_Process& process_report, + const std::string& dll_path) { + for (const auto& dll : process_report.dll()) { + if (dll.path() == dll_path && + std::find(dll.feature().begin(), dll.feature().end(), + ClientIncidentReport_EnvironmentData_Process_Dll::LSP) != + dll.feature().end()) { + // LSP feature found. + return true; } } @@ -73,26 +70,28 @@ // msvidc32.dll exists in both 32 and 64 bit versions. base::FilePath msvdc32_dll(L"msvidc32.dll"); - safe_browsing::ClientIncidentReport_EnvironmentData_Process process_report; - safe_browsing::CollectDlls(&process_report); + ClientIncidentReport_EnvironmentData_Process process_report; + CollectDlls(&process_report); - ASSERT_FALSE(ProcessReportContainsDll(process_report, msvdc32_dll)); + ClientIncidentReport_EnvironmentData_Process_Dll dll; + ASSERT_FALSE(GetProcessReportDll(process_report, msvdc32_dll, &dll)); // Redo the same verification after loading a new dll. base::ScopedNativeLibrary library(msvdc32_dll); process_report.clear_dll(); - safe_browsing::CollectDlls(&process_report); + CollectDlls(&process_report); - ASSERT_TRUE(ProcessReportContainsDll(process_report, msvdc32_dll)); + ASSERT_TRUE(GetProcessReportDll(process_report, msvdc32_dll, &dll)); + ASSERT_TRUE(dll.has_image_headers()); } TEST(SafeBrowsingEnvironmentDataCollectionWinTest, RecordLspFeature) { net::EnsureWinsockInit(); // Populate our incident report with loaded modules. - safe_browsing::ClientIncidentReport_EnvironmentData_Process process_report; - safe_browsing::CollectDlls(&process_report); + ClientIncidentReport_EnvironmentData_Process process_report; + CollectDlls(&process_report); // We'll test RecordLspFeatures against a real dll registered as a LSP. All // dll paths are expected to be lowercase in the process report. @@ -100,7 +99,7 @@ int base_address = 0x77770000; int length = 0x180000; - safe_browsing::RecordLspFeature(&process_report); + RecordLspFeature(&process_report); // Return successfully if LSP feature is found. if (DllEntryContainsLspFeature(process_report, lsp)) @@ -108,13 +107,13 @@ // |lsp| was not already loaded into the current process. Manually add it // to the process report so that it will get marked as a LSP. - safe_browsing::ClientIncidentReport_EnvironmentData_Process_Dll* dll = + ClientIncidentReport_EnvironmentData_Process_Dll* dll = process_report.add_dll(); dll->set_path(lsp); dll->set_base_address(base_address); dll->set_length(length); - safe_browsing::RecordLspFeature(&process_report); + RecordLspFeature(&process_report); // Return successfully if LSP feature is found. if (DllEntryContainsLspFeature(process_report, lsp)) @@ -134,14 +133,14 @@ KEY_QUERY_VALUE | KEY_SET_VALUE); // Check that with an empty registry the blacklisted dlls field is left empty. - safe_browsing::ClientIncidentReport_EnvironmentData_Process process_report; - safe_browsing::CollectDllBlacklistData(&process_report); + ClientIncidentReport_EnvironmentData_Process process_report; + CollectDllBlacklistData(&process_report); EXPECT_EQ(0, process_report.blacklisted_dll_size()); // Check that after adding exactly one dll to the registry it appears in the // process report. blacklist_registry_key.WriteValue(test_dll, test_dll); - safe_browsing::CollectDllBlacklistData(&process_report); + CollectDllBlacklistData(&process_report); ASSERT_EQ(1, process_report.blacklisted_dll_size()); base::string16 process_report_dll = @@ -163,7 +162,7 @@ .AsUTF8Unsafe(); blacklist_registry_key.WriteValue(input_path.c_str(), input_path.c_str()); - safe_browsing::CollectDllBlacklistData(&process_report); + CollectDllBlacklistData(&process_report); ASSERT_EQ(1, process_report.blacklisted_dll_size()); std::string process_report_path = process_report.blacklisted_dll(0); @@ -172,19 +171,18 @@ TEST(SafeBrowsingEnvironmentDataCollectionWinTest, VerifyLoadedModules) { // Load the test modules. - std::vector<base::ScopedNativeLibrary> test_dlls( - safe_browsing::kTestDllNamesCount); - for (size_t i = 0; i < safe_browsing::kTestDllNamesCount; ++i) { - test_dlls[i].Reset(LoadNativeLibrary( - base::FilePath(safe_browsing::kTestDllNames[i]), NULL)); + std::vector<base::ScopedNativeLibrary> test_dlls(kTestDllNamesCount); + for (size_t i = 0; i < kTestDllNamesCount; ++i) { + test_dlls[i].Reset( + LoadNativeLibrary(base::FilePath(kTestDllNames[i]), NULL)); } // Edit the first byte of the function exported by the first module. Calling // GetModuleHandle so we do not increment the library ref count. - HMODULE module_handle = GetModuleHandle(safe_browsing::kTestDllNames[0]); + HMODULE module_handle = GetModuleHandle(kTestDllNames[0]); ASSERT_NE(reinterpret_cast<HANDLE>(NULL), module_handle); uint8_t* export_addr = reinterpret_cast<uint8_t*>( - GetProcAddress(module_handle, safe_browsing::kTestExportName)); + GetProcAddress(module_handle, kTestExportName)); ASSERT_NE(reinterpret_cast<uint8_t*>(NULL), export_addr); uint8_t new_val = (*export_addr) + 1; @@ -196,11 +194,9 @@ &bytes_written); ASSERT_EQ(1, bytes_written); - safe_browsing::ClientIncidentReport_EnvironmentData_Process process_report; - safe_browsing::CollectModuleVerificationData( - safe_browsing::kTestDllNames, - safe_browsing::kTestDllNamesCount, - &process_report); + ClientIncidentReport_EnvironmentData_Process process_report; + CollectModuleVerificationData(kTestDllNames, kTestDllNamesCount, + &process_report); // CollectModuleVerificationData should return the single modified module and // its modified export. The other module, being unmodified, is omitted from @@ -214,12 +210,13 @@ EXPECT_EQ(1, process_report.module_state(0).modified_export_size()); #endif - EXPECT_EQ(base::WideToUTF8(safe_browsing::kTestDllNames[0]), + EXPECT_EQ(base::WideToUTF8(kTestDllNames[0]), process_report.module_state(0).name()); - EXPECT_EQ( - safe_browsing::ClientIncidentReport_EnvironmentData_Process_ModuleState:: - MODULE_STATE_MODIFIED, - process_report.module_state(0).modified_state()); - EXPECT_EQ(std::string(safe_browsing::kTestExportName), + EXPECT_EQ(ClientIncidentReport_EnvironmentData_Process_ModuleState:: + MODULE_STATE_MODIFIED, + process_report.module_state(0).modified_state()); + EXPECT_EQ(std::string(kTestExportName), process_report.module_state(0).modified_export(0)); } + +} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_database.h b/chrome/browser/safe_browsing/safe_browsing_database.h index 7bfaa8b..149cb18 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database.h +++ b/chrome/browser/safe_browsing/safe_browsing_database.h
@@ -240,44 +240,45 @@ static base::FilePath UnwantedSoftwareDBFilename( const base::FilePath& db_filename); - // Enumerate failures for histogramming purposes. DO NOT CHANGE THE - // ORDERING OF THESE VALUES. + // SafeBrowsing Database failure types for histogramming purposes. Explicitly + // label new values and do not re-use old values. Also make sure to reflect + // modifications made below in the SB2DatabaseFailure histogram enum. enum FailureType { - FAILURE_DATABASE_CORRUPT, - FAILURE_DATABASE_CORRUPT_HANDLER, - FAILURE_BROWSE_DATABASE_UPDATE_BEGIN, - FAILURE_BROWSE_DATABASE_UPDATE_FINISH, - FAILURE_DATABASE_FILTER_MISSING_OBSOLETE, - FAILURE_DATABASE_FILTER_READ_OBSOLETE, - FAILURE_DATABASE_FILTER_WRITE_OBSOLETE, - FAILURE_DATABASE_FILTER_DELETE, - FAILURE_DATABASE_STORE_MISSING, - FAILURE_DATABASE_STORE_DELETE, - FAILURE_DOWNLOAD_DATABASE_UPDATE_BEGIN, - FAILURE_DOWNLOAD_DATABASE_UPDATE_FINISH, - FAILURE_WHITELIST_DATABASE_UPDATE_BEGIN, - FAILURE_WHITELIST_DATABASE_UPDATE_FINISH, - FAILURE_BROWSE_PREFIX_SET_READ, - FAILURE_BROWSE_PREFIX_SET_WRITE, - FAILURE_BROWSE_PREFIX_SET_DELETE, - FAILURE_EXTENSION_BLACKLIST_UPDATE_BEGIN, - FAILURE_EXTENSION_BLACKLIST_UPDATE_FINISH, - FAILURE_EXTENSION_BLACKLIST_DELETE, - FAILURE_SIDE_EFFECT_FREE_WHITELIST_UPDATE_BEGIN, - FAILURE_SIDE_EFFECT_FREE_WHITELIST_UPDATE_FINISH, - FAILURE_SIDE_EFFECT_FREE_WHITELIST_DELETE, - FAILURE_SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_READ, - FAILURE_SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_WRITE, - FAILURE_SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_DELETE, - FAILURE_IP_BLACKLIST_UPDATE_BEGIN, - FAILURE_IP_BLACKLIST_UPDATE_FINISH, - FAILURE_IP_BLACKLIST_UPDATE_INVALID, - FAILURE_IP_BLACKLIST_DELETE, - FAILURE_UNWANTED_SOFTWARE_DATABASE_UPDATE_BEGIN, - FAILURE_UNWANTED_SOFTWARE_DATABASE_UPDATE_FINISH, - FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_READ, - FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_WRITE, - FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_DELETE, + FAILURE_DATABASE_CORRUPT = 0, + FAILURE_DATABASE_CORRUPT_HANDLER = 1, + FAILURE_BROWSE_DATABASE_UPDATE_BEGIN = 2, + FAILURE_BROWSE_DATABASE_UPDATE_FINISH = 3, + FAILURE_DATABASE_FILTER_MISSING_OBSOLETE = 4, + FAILURE_DATABASE_FILTER_READ_OBSOLETE = 5, + FAILURE_DATABASE_FILTER_WRITE_OBSOLETE = 6, + FAILURE_DATABASE_FILTER_DELETE = 7, + FAILURE_DATABASE_STORE_MISSING = 8, + FAILURE_DATABASE_STORE_DELETE = 9, + FAILURE_DOWNLOAD_DATABASE_UPDATE_BEGIN = 10, + FAILURE_DOWNLOAD_DATABASE_UPDATE_FINISH = 11, + FAILURE_WHITELIST_DATABASE_UPDATE_BEGIN = 12, + FAILURE_WHITELIST_DATABASE_UPDATE_FINISH = 13, + FAILURE_BROWSE_PREFIX_SET_READ = 14, + FAILURE_BROWSE_PREFIX_SET_WRITE = 15, + FAILURE_BROWSE_PREFIX_SET_DELETE = 16, + FAILURE_EXTENSION_BLACKLIST_UPDATE_BEGIN = 17, + FAILURE_EXTENSION_BLACKLIST_UPDATE_FINISH = 18, + FAILURE_EXTENSION_BLACKLIST_DELETE = 19, + FAILURE_SIDE_EFFECT_FREE_WHITELIST_UPDATE_BEGIN = 20, + FAILURE_SIDE_EFFECT_FREE_WHITELIST_UPDATE_FINISH = 21, + FAILURE_SIDE_EFFECT_FREE_WHITELIST_DELETE = 22, + FAILURE_SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_READ = 23, + FAILURE_SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_WRITE = 24, + FAILURE_SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_DELETE = 25, + FAILURE_IP_BLACKLIST_UPDATE_BEGIN = 26, + FAILURE_IP_BLACKLIST_UPDATE_FINISH = 27, + FAILURE_IP_BLACKLIST_UPDATE_INVALID = 28, + FAILURE_IP_BLACKLIST_DELETE = 29, + FAILURE_UNWANTED_SOFTWARE_DATABASE_UPDATE_BEGIN = 30, + FAILURE_UNWANTED_SOFTWARE_DATABASE_UPDATE_FINISH = 31, + FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_READ = 32, + FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_WRITE = 33, + FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_DELETE = 34, // Memory space for histograms is determined by the max. ALWAYS // ADD NEW VALUES BEFORE THIS ONE.
diff --git a/chrome/browser/services/gcm/OWNERS b/chrome/browser/services/gcm/OWNERS index 0eba0b77..0f8cc7a 100644 --- a/chrome/browser/services/gcm/OWNERS +++ b/chrome/browser/services/gcm/OWNERS
@@ -2,7 +2,3 @@ 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 3d2d2109cd..e1926a3 100644 --- a/chrome/browser/services/gcm/fake_gcm_profile_service.cc +++ b/chrome/browser/services/gcm/fake_gcm_profile_service.cc
@@ -115,8 +115,6 @@ FakeGCMProfileService::FakeGCMProfileService(Profile* profile) : collect_(false), registration_count_(0) { - static_cast<PushMessagingServiceImpl*>(push_messaging_service()) - ->SetProfileForTesting(profile); } FakeGCMProfileService::~FakeGCMProfileService() {}
diff --git a/chrome/browser/services/gcm/gcm_profile_service.cc b/chrome/browser/services/gcm/gcm_profile_service.cc index df86051..ccc7205e 100644 --- a/chrome/browser/services/gcm/gcm_profile_service.cc +++ b/chrome/browser/services/gcm/gcm_profile_service.cc
@@ -127,18 +127,11 @@ #endif // defined(OS_ANDROID) } -// static -void GCMProfileService::RegisterProfilePrefs( - user_prefs::PrefRegistrySyncable* registry) { - PushMessagingServiceImpl::RegisterProfilePrefs(registry); -} - #if defined(OS_ANDROID) static GCMProfileService* debug_instance = nullptr; GCMProfileService::GCMProfileService(Profile* profile) - : profile_(profile), - push_messaging_service_(this, profile) { + : profile_(profile) { CHECK(!profile->IsOffTheRecord()); // TODO(johnme): Remove debug_instance and this logging code once @@ -166,8 +159,7 @@ GCMProfileService::GCMProfileService( Profile* profile, scoped_ptr<GCMClientFactory> gcm_client_factory) - : profile_(profile), - push_messaging_service_(this, profile) { + : profile_(profile) { DCHECK(!profile->IsOffTheRecord()); driver_ = CreateGCMDriverDesktop( @@ -181,8 +173,7 @@ #endif // defined(OS_ANDROID) GCMProfileService::GCMProfileService() - : profile_(NULL), - push_messaging_service_(this, NULL) { + : profile_(NULL) { } GCMProfileService::~GCMProfileService() {
diff --git a/chrome/browser/services/gcm/gcm_profile_service.h b/chrome/browser/services/gcm/gcm_profile_service.h index 4adb01f9..7eba5eaf 100644 --- a/chrome/browser/services/gcm/gcm_profile_service.h +++ b/chrome/browser/services/gcm/gcm_profile_service.h
@@ -10,7 +10,6 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" -#include "chrome/browser/services/gcm/push_messaging_service_impl.h" #include "components/keyed_service/core/keyed_service.h" class Profile; @@ -34,9 +33,6 @@ // Returns whether GCM is enabled for |profile|. static bool IsGCMEnabled(Profile* profile); - // Register profile-specific prefs for GCM. - static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); - #if defined(OS_ANDROID) explicit GCMProfileService(Profile* profile); #else @@ -53,10 +49,6 @@ GCMDriver* driver() const { return driver_.get(); } - content::PushMessagingService* push_messaging_service() { - return &push_messaging_service_; - } - protected: // Used for constructing fake GCMProfileService for testing purpose. GCMProfileService(); @@ -67,9 +59,6 @@ scoped_ptr<GCMDriver> driver_; - // Implementation of content::PushMessagingService using GCMProfileService. - PushMessagingServiceImpl push_messaging_service_; - // Used for both account tracker and GCM.UserSignedIn UMA. #if !defined(OS_ANDROID) class IdentityObserver;
diff --git a/chrome/browser/services/gcm/push_messaging_application_id.cc b/chrome/browser/services/gcm/push_messaging_application_id.cc deleted file mode 100644 index eb2b436e..0000000 --- a/chrome/browser/services/gcm/push_messaging_application_id.cc +++ /dev/null
@@ -1,172 +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 "chrome/browser/services/gcm/push_messaging_application_id.h" - -#include "base/guid.h" -#include "base/logging.h" -#include "base/prefs/pref_service.h" -#include "base/prefs/scoped_user_pref_update.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/values.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/common/pref_names.h" -#include "components/pref_registry/pref_registry_syncable.h" - -namespace { -const char kSeparator = '#'; // Ok as only the origin of the url is used. -} // namespace - -namespace gcm { - -const char kPushMessagingApplicationIdPrefix[] = "wp:"; - -// static -void PushMessagingApplicationId::RegisterProfilePrefs( - user_prefs::PrefRegistrySyncable* registry) { - registry->RegisterDictionaryPref( - prefs::kPushMessagingApplicationIdMap, - user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); -} - -// static -PushMessagingApplicationId PushMessagingApplicationId::Generate( - const GURL& origin, int64 service_worker_registration_id) -{ - // TODO(johnme): Does GenerateGUID produce good enough random numbers? - std::string guid = base::GenerateGUID(); - CHECK(!guid.empty()); - std::string app_id_guid = - kPushMessagingApplicationIdPrefix + guid; - - PushMessagingApplicationId application_id(app_id_guid, origin, - service_worker_registration_id); - DCHECK(application_id.IsValid()); - return application_id; -} - -// static -PushMessagingApplicationId PushMessagingApplicationId::Get( - Profile* profile, const std::string& app_id_guid) { - // Workaround crbug.com/461867 in GCM where it converts subtypes to lowercase. - // TODO(johnme): Remove this when obsolete - const size_t prefix_len = strlen(kPushMessagingApplicationIdPrefix); - if (app_id_guid.size() < prefix_len) - return PushMessagingApplicationId(); - std::string uppercase_app_id = - app_id_guid.substr(0, prefix_len) + - StringToUpperASCII(app_id_guid.substr(prefix_len, std::string::npos)); - - const base::DictionaryValue* map = - profile->GetPrefs()->GetDictionary(prefs::kPushMessagingApplicationIdMap); - - std::string origin_and_sw_id; - if (!map->GetStringWithoutPathExpansion(uppercase_app_id, &origin_and_sw_id)) - return PushMessagingApplicationId(); - - std::vector<std::string> parts; - base::SplitString(origin_and_sw_id, kSeparator, &parts); - if (parts.size() != 2) - return PushMessagingApplicationId(); - - GURL origin = GURL(parts[0]); - - int64 service_worker_registration_id; - if (!base::StringToInt64(parts[1], &service_worker_registration_id)) - return PushMessagingApplicationId(); - - PushMessagingApplicationId application_id(uppercase_app_id, origin, - service_worker_registration_id); - DCHECK(application_id.IsValid()); - return application_id; -} - -// static -PushMessagingApplicationId PushMessagingApplicationId::Get( - Profile* profile, const GURL& origin, int64 service_worker_registration_id) -{ - base::StringValue origin_and_sw_id = base::StringValue(origin.spec() + - kSeparator + base::Int64ToString(service_worker_registration_id)); - - const base::DictionaryValue* map = - profile->GetPrefs()->GetDictionary(prefs::kPushMessagingApplicationIdMap); - for (auto it = base::DictionaryValue::Iterator(*map); !it.IsAtEnd(); - it.Advance()) { - if (it.value().Equals(&origin_and_sw_id)) - return Get(profile, it.key()); - } - return PushMessagingApplicationId(); -} - -// static -std::vector<PushMessagingApplicationId> PushMessagingApplicationId::GetAll( - Profile* profile) { - std::vector<PushMessagingApplicationId> result; - - const base::DictionaryValue* map = - profile->GetPrefs()->GetDictionary(prefs::kPushMessagingApplicationIdMap); - for (auto it = base::DictionaryValue::Iterator(*map); !it.IsAtEnd(); - it.Advance()) { - result.push_back(Get(profile, it.key())); - } - - return result; -} - -void PushMessagingApplicationId::PersistToDisk(Profile* profile) const { - DCHECK(IsValid()); - - DictionaryPrefUpdate update(profile->GetPrefs(), - prefs::kPushMessagingApplicationIdMap); - base::DictionaryValue* map = update.Get(); - - // Delete any stale entry with the same origin and Service Worker - // registration id (hence we ensure there is a 1:1 not 1:many mapping). - PushMessagingApplicationId old = Get(profile, origin_, - service_worker_registration_id_); - if (old.IsValid()) - map->RemoveWithoutPathExpansion(old.app_id_guid_, nullptr); - - std::string origin_and_sw_id = origin_.spec() + kSeparator + - base::Int64ToString(service_worker_registration_id_); - map->SetStringWithoutPathExpansion(app_id_guid_, origin_and_sw_id); -} - -void PushMessagingApplicationId::DeleteFromDisk(Profile* profile) const { - DCHECK(IsValid()); - - DictionaryPrefUpdate update(profile->GetPrefs(), - prefs::kPushMessagingApplicationIdMap); - base::DictionaryValue* map = update.Get(); - map->RemoveWithoutPathExpansion(app_id_guid_, nullptr); -} - -PushMessagingApplicationId::PushMessagingApplicationId() - : origin_(GURL::EmptyGURL()), - service_worker_registration_id_(-1) { -} - -PushMessagingApplicationId::PushMessagingApplicationId( - const std::string& app_id_guid, - const GURL& origin, - int64 service_worker_registration_id) - : app_id_guid_(app_id_guid), - origin_(origin), - service_worker_registration_id_(service_worker_registration_id) { -} - -PushMessagingApplicationId::~PushMessagingApplicationId() { -} - -bool PushMessagingApplicationId::IsValid() const { - const size_t prefix_len = strlen(kPushMessagingApplicationIdPrefix); - return origin_.is_valid() && origin_.GetOrigin() == origin_ - && service_worker_registration_id_ >= 0 - && !app_id_guid_.compare(0, prefix_len, kPushMessagingApplicationIdPrefix) - && base::IsValidGUID(app_id_guid_.substr(prefix_len, std::string::npos)); -} - -} // namespace gcm
diff --git a/chrome/browser/services/gcm/push_messaging_application_id.h b/chrome/browser/services/gcm/push_messaging_application_id.h deleted file mode 100644 index ddb24d64..0000000 --- a/chrome/browser/services/gcm/push_messaging_application_id.h +++ /dev/null
@@ -1,85 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_APPLICATION_ID_H_ -#define CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_APPLICATION_ID_H_ - -#include <string> -#include <vector> - -#include "base/basictypes.h" -#include "url/gurl.h" - -class Profile; - -namespace user_prefs { -class PrefRegistrySyncable; -} - -namespace gcm { - -// The prefix used for all push messaging application ids. -extern const char kPushMessagingApplicationIdPrefix[]; - -// Type used to identify a web app from a Push API perspective. -// These can be persisted to disk, in a 1:1 mapping between app_id_guid and -// pair<origin, service_worker_registration_id>. -class PushMessagingApplicationId { - public: - // Register profile-specific prefs. - static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); - - // Generates a new application id with random app_id_guid. - static PushMessagingApplicationId Generate( - const GURL& origin, - int64 service_worker_registration_id); - - // Looks up an application id by app_id_guid. Will be invalid if not found. - static PushMessagingApplicationId Get(Profile* profile, - const std::string& app_id_guid); - - // Looks up an application id by origin & service worker registration id. - // Will be invalid if not found. - static PushMessagingApplicationId Get(Profile* profile, - const GURL& origin, - int64 service_worker_registration_id); - - // Returns all the PushMessagingApplicationId currently registered for the - // given |profile|. - static std::vector<PushMessagingApplicationId> GetAll(Profile* profile); - - ~PushMessagingApplicationId(); - - // Persist this application id to disk. - void PersistToDisk(Profile* profile) const; - - // Delete this application id from disk. - void DeleteFromDisk(Profile* profile) const; // TODO: Does const make sense? - - bool IsValid() const; - - const std::string& app_id_guid() const { return app_id_guid_; } - const GURL& origin() const { return origin_; } - int64 service_worker_registration_id() const { - return service_worker_registration_id_; - } - - private: - friend class PushMessagingApplicationIdTest; - - // Constructs an invalid app id. - PushMessagingApplicationId(); - // Constructs a valid app id. - PushMessagingApplicationId(const std::string& app_id_guid, - const GURL& origin, - int64 service_worker_registration_id); - - std::string app_id_guid_; - GURL origin_; - int64 service_worker_registration_id_; -}; - -} // namespace gcm - -#endif // CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_APPLICATION_ID_H_
diff --git a/chrome/browser/services/gcm/push_messaging_application_id_unittest.cc b/chrome/browser/services/gcm/push_messaging_application_id_unittest.cc deleted file mode 100644 index 34944db..0000000 --- a/chrome/browser/services/gcm/push_messaging_application_id_unittest.cc +++ /dev/null
@@ -1,41 +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 "chrome/browser/services/gcm/push_messaging_application_id.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace gcm { - -class PushMessagingApplicationIdTest : public testing::Test { - protected: - PushMessagingApplicationId GenerateId( - const GURL& origin, - int64 service_worker_registration_id) { - // To bypass DCHECK in PushMessagingApplicationId::Generate, we just use it - // to generate app_id_guid, and then use private constructor. - std::string app_id_guid = gcm::PushMessagingApplicationId::Generate( - GURL("https://www.example.com/"), 1).app_id_guid(); - return PushMessagingApplicationId(app_id_guid, origin, - service_worker_registration_id); - } -}; - -TEST_F(PushMessagingApplicationIdTest, ConstructorValidity) { - EXPECT_TRUE(GenerateId(GURL("https://www.example.com/"), 1).IsValid()); - EXPECT_TRUE(GenerateId(GURL("https://www.example.com"), 1).IsValid()); - EXPECT_FALSE(GenerateId(GURL(""), 1).IsValid()); - EXPECT_FALSE(GenerateId(GURL("foo"), 1).IsValid()); - EXPECT_FALSE(GenerateId(GURL("https://www.example.com/foo"), 1).IsValid()); - EXPECT_FALSE(GenerateId(GURL("https://www.example.com/#foo"), 1).IsValid()); - EXPECT_FALSE(GenerateId(GURL("https://www.example.com/"), -1).IsValid()); -} - -TEST_F(PushMessagingApplicationIdTest, UniqueGuids) { - EXPECT_NE(gcm::PushMessagingApplicationId::Generate( - GURL("https://www.example.com/"), 1).app_id_guid(), - gcm::PushMessagingApplicationId::Generate( - GURL("https://www.example.com/"), 1).app_id_guid()); -} - -} // namespace gcm
diff --git a/chrome/browser/services/gcm/push_messaging_browsertest.cc b/chrome/browser/services/gcm/push_messaging_browsertest.cc deleted file mode 100644 index 2baa489..0000000 --- a/chrome/browser/services/gcm/push_messaging_browsertest.cc +++ /dev/null
@@ -1,1013 +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 <map> -#include <string> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/infobars/infobar_service.h" -#include "chrome/browser/notifications/notification_test_util.h" -#include "chrome/browser/notifications/platform_notification_service_impl.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/services/gcm/fake_gcm_profile_service.h" -#include "chrome/browser/services/gcm/gcm_profile_service_factory.h" -#include "chrome/browser/services/gcm/push_messaging_application_id.h" -#include "chrome/browser/services/gcm/push_messaging_constants.h" -#include "chrome/browser/ui/browser.h" -#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.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" -#include "components/infobars/core/infobar_manager.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/content_switches.h" -#include "content/public/test/browser_test_utils.h" -#include "ui/base/window_open_disposition.h" - -#if defined(OS_ANDROID) -#include "base/android/build_info.h" -#endif - -namespace gcm { - -namespace { -// Responds to a confirm infobar by accepting or cancelling it. Responds to at -// most one infobar. -class InfoBarResponder : public infobars::InfoBarManager::Observer { - public: - InfoBarResponder(Browser* browser, bool accept) - : infobar_service_(InfoBarService::FromWebContents( - browser->tab_strip_model()->GetActiveWebContents())), - accept_(accept), - has_observed_(false) { - infobar_service_->AddObserver(this); - } - - ~InfoBarResponder() override { infobar_service_->RemoveObserver(this); } - - // infobars::InfoBarManager::Observer - void OnInfoBarAdded(infobars::InfoBar* infobar) override { - if (has_observed_) - return; - has_observed_ = true; - ConfirmInfoBarDelegate* delegate = - infobar->delegate()->AsConfirmInfoBarDelegate(); - DCHECK(delegate); - - // Respond to the infobar asynchronously, like a person. - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind( - &InfoBarResponder::Respond, base::Unretained(this), delegate)); - } - - private: - void Respond(ConfirmInfoBarDelegate* delegate) { - if (accept_) { - delegate->Accept(); - } else { - delegate->Cancel(); - } - } - - InfoBarService* infobar_service_; - 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), waiting_(false) {} - - void Run(const std::string& app_id) { - app_id_ = app_id; - done_ = true; - if (waiting_) - base::MessageLoop::current()->Quit(); - } - - void WaitUntilSatisfied() { - if (done_) - return; - - waiting_ = true; - while (!done_) - content::RunMessageLoop(); - } - - const std::string& app_id() { - return app_id_; - } - - private: - bool done_; - bool waiting_; - std::string app_id_; -}; - -// Class to instantiate on the stack that is meant to be used with -// StubNotificationUIManager::SetNotificationAddedCallback. Mind that Run() -// might be invoked prior to WaitUntilSatisfied() being called. -class NotificationAddedCallback { - public: - NotificationAddedCallback() : done_(false), waiting_(false) {} - - void Run() { - done_ = true; - if (waiting_) - base::MessageLoop::current()->Quit(); - } - - void WaitUntilSatisfied() { - if (done_) - return; - - waiting_ = true; - while (!done_) - content::RunMessageLoop(); - } - - private: - bool done_; - bool waiting_; -}; - -// The Push API depends on Web Notifications, which is only available on Android -// Jelly Bean and later. -bool IsPushSupported() { -#if defined(OS_ANDROID) - if (base::android::BuildInfo::GetInstance()->sdk_int() < - base::android::SDK_VERSION_JELLY_BEAN) { - DVLOG(0) << "The Push API is only supported in Android 4.1 and later."; - return false; - } -#endif - return true; -} - -} // namespace - -class PushMessagingBrowserTest : public InProcessBrowserTest { - public: - PushMessagingBrowserTest() : gcm_service_(nullptr) {} - ~PushMessagingBrowserTest() override {} - - // InProcessBrowserTest: - void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitch(switches::kEnablePushMessagePayload); - command_line->AppendSwitch(switches::kEnablePushMessagingHasPermission); - - InProcessBrowserTest::SetUpCommandLine(command_line); - } - - // InProcessBrowserTest: - void SetUp() override { - https_server_.reset(new net::SpawnedTestServer( - net::SpawnedTestServer::TYPE_HTTPS, - net::BaseTestServer::SSLOptions( - net::BaseTestServer::SSLOptions::CERT_OK), - base::FilePath(FILE_PATH_LITERAL("chrome/test/data/")))); - ASSERT_TRUE(https_server_->Start()); - -#if defined(ENABLE_NOTIFICATIONS) - notification_manager_.reset(new StubNotificationUIManager); - notification_service()->SetNotificationUIManagerForTesting( - notification_manager()); -#endif - - InProcessBrowserTest::SetUp(); - } - - // InProcessBrowserTest: - void SetUpOnMainThread() override { - gcm_service_ = static_cast<FakeGCMProfileService*>( - GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse( - browser()->profile(), &FakeGCMProfileService::Build)); - gcm_service_->set_collect(true); - - LoadTestPage(); - - InProcessBrowserTest::SetUpOnMainThread(); - } - - // InProcessBrowserTest: - void TearDown() override { -#if defined(ENABLE_NOTIFICATIONS) - notification_service()->SetNotificationUIManagerForTesting(nullptr); -#endif - - InProcessBrowserTest::TearDown(); - } - - void LoadTestPage(const std::string& path) { - ui_test_utils::NavigateToURL(browser(), https_server_->GetURL(path)); - } - - void LoadTestPage() { - LoadTestPage(GetTestURL()); - } - - bool RunScript(const std::string& script, std::string* result) { - return RunScript(script, result, nullptr); - } - - bool RunScript(const std::string& script, std::string* result, - content::WebContents* web_contents) { - if (!web_contents) - web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - return content::ExecuteScriptAndExtractString(web_contents->GetMainFrame(), - script, - result); - } - - void TryToRegisterSuccessfully( - const std::string& expected_push_registration_id); - - PushMessagingApplicationId GetServiceWorkerAppId( - int64 service_worker_registration_id); - - net::SpawnedTestServer* https_server() const { return https_server_.get(); } - - FakeGCMProfileService* gcm_service() const { return gcm_service_; } - -#if defined(ENABLE_NOTIFICATIONS) - StubNotificationUIManager* notification_manager() const { - return notification_manager_.get(); - } - - PlatformNotificationServiceImpl* notification_service() const { - return PlatformNotificationServiceImpl::GetInstance(); - } -#endif - - PushMessagingServiceImpl* push_service() { - return static_cast<PushMessagingServiceImpl*>( - gcm_service_->push_messaging_service()); - } - - protected: - virtual std::string GetTestURL() { - return "files/push_messaging/test.html"; - } - - private: - scoped_ptr<net::SpawnedTestServer> https_server_; - FakeGCMProfileService* gcm_service_; - scoped_ptr<StubNotificationUIManager> notification_manager_; - - DISALLOW_COPY_AND_ASSIGN(PushMessagingBrowserTest); -}; - -class PushMessagingBadManifestBrowserTest : public PushMessagingBrowserTest { - std::string GetTestURL() override { - return "files/push_messaging/test_bad_manifest.html"; - } -}; - -IN_PROC_BROWSER_TEST_F(PushMessagingBadManifestBrowserTest, - RegisterFailsNotVisibleMessages) { - if (!IsPushSupported()) - return; - - std::string script_result; - - ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); - ASSERT_EQ("ok - service worker registered", script_result); - ASSERT_TRUE(RunScript("registerPush()", &script_result)); - EXPECT_EQ("AbortError - Registration failed - permission denied", - script_result); -} - -void PushMessagingBrowserTest::TryToRegisterSuccessfully( - const std::string& expected_push_registration_id) { - std::string script_result; - - EXPECT_TRUE(RunScript("registerServiceWorker()", &script_result)); - EXPECT_EQ("ok - service worker registered", script_result); - - InfoBarResponder accepting_responder(browser(), true); - EXPECT_TRUE(RunScript("requestNotificationPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); - - EXPECT_TRUE(RunScript("registerPush()", &script_result)); - EXPECT_EQ(std::string(kPushMessagingEndpoint) + " - " - + expected_push_registration_id, script_result); -} - -PushMessagingApplicationId PushMessagingBrowserTest::GetServiceWorkerAppId( - int64 service_worker_registration_id) { - GURL origin = https_server()->GetURL(std::string()).GetOrigin(); - PushMessagingApplicationId application_id = PushMessagingApplicationId::Get( - browser()->profile(), origin, service_worker_registration_id); - EXPECT_TRUE(application_id.IsValid()); - return application_id; -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - RegisterSuccessNotificationsGranted) { - if (!IsPushSupported()) - return; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); - EXPECT_EQ(app_id.app_id_guid(), gcm_service()->last_registered_app_id()); - EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - RegisterSuccessNotificationsPrompt) { - if (!IsPushSupported()) - return; - - 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("registerPush()", &script_result)); - EXPECT_EQ(std::string(kPushMessagingEndpoint) + " - 1-0", script_result); - - PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); - EXPECT_EQ(app_id.app_id_guid(), gcm_service()->last_registered_app_id()); - EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - RegisterFailureNotificationsBlocked) { - if (!IsPushSupported()) - return; - - 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)); - ASSERT_EQ("permission status - denied", script_result); - - ASSERT_TRUE(RunScript("registerPush()", &script_result)); - EXPECT_EQ("AbortError - Registration failed - permission denied", - script_result); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, RegisterFailureNoManifest) { - if (!IsPushSupported()) - return; - - 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("removeManifest()", &script_result)); - ASSERT_EQ("manifest removed", script_result); - - ASSERT_TRUE(RunScript("registerPush()", &script_result)); - EXPECT_EQ("AbortError - Registration failed - no sender id provided", - script_result); -} - -// TODO(johnme): Test registering from a worker - see https://crbug.com/437298. - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, RegisterPersisted) { - if (!IsPushSupported()) - return; - - std::string script_result; - - // First, test that Service Worker registration IDs are assigned in order of - // registering the Service Workers, and the (fake) push registration ids are - // assigned in order of push registration (even when these orders are - // different). - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - PushMessagingApplicationId app_id_sw0 = GetServiceWorkerAppId(0LL); - EXPECT_EQ(app_id_sw0.app_id_guid(), gcm_service()->last_registered_app_id()); - - LoadTestPage("files/push_messaging/subscope1/test.html"); - ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); - ASSERT_EQ("ok - service worker registered", script_result); - - LoadTestPage("files/push_messaging/subscope2/test.html"); - ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); - ASSERT_EQ("ok - service worker registered", script_result); - - // Note that we need to reload the page after registering, otherwise - // navigator.serviceWorker.ready is going to be resolved with the parent - // Service Worker which still controls the page. - LoadTestPage("files/push_messaging/subscope2/test.html"); - TryToRegisterSuccessfully("1-1" /* expected_push_registration_id */); - PushMessagingApplicationId app_id_sw2 = GetServiceWorkerAppId(2LL); - EXPECT_EQ(app_id_sw2.app_id_guid(), gcm_service()->last_registered_app_id()); - - LoadTestPage("files/push_messaging/subscope1/test.html"); - TryToRegisterSuccessfully("1-2" /* expected_push_registration_id */); - PushMessagingApplicationId app_id_sw1 = GetServiceWorkerAppId(1LL); - EXPECT_EQ(app_id_sw1.app_id_guid(), gcm_service()->last_registered_app_id()); - - // Now test that the Service Worker registration IDs and push registration IDs - // generated above were persisted to SW storage, by checking that they are - // unchanged despite requesting them in a different order. - // TODO(johnme): Ideally we would restart the browser at this point to check - // they were persisted to disk, but that's not currently possible since the - // test server uses random port numbers for each test (even PRE_Foo and Foo), - // so we wouldn't be able to load the test pages with the same origin. - - LoadTestPage("files/push_messaging/subscope1/test.html"); - TryToRegisterSuccessfully("1-2" /* expected_push_registration_id */); - EXPECT_EQ(app_id_sw1.app_id_guid(), gcm_service()->last_registered_app_id()); - - LoadTestPage("files/push_messaging/subscope2/test.html"); - TryToRegisterSuccessfully("1-1" /* expected_push_registration_id */); - EXPECT_EQ(app_id_sw1.app_id_guid(), gcm_service()->last_registered_app_id()); - - LoadTestPage(); - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - EXPECT_EQ(app_id_sw1.app_id_guid(), gcm_service()->last_registered_app_id()); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventSuccess) { - if (!IsPushSupported()) - return; - - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); - EXPECT_EQ(app_id.app_id_guid(), 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); - - GCMClient::IncomingMessage message; - message.sender_id = "1234567890"; - message.data["data"] = "testdata"; - push_service()->OnMessage(app_id.app_id_guid(), message); - ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result)); - EXPECT_EQ("testdata", script_result); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventNoServiceWorker) { - if (!IsPushSupported()) - return; - - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); - EXPECT_EQ(app_id.app_id_guid(), 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; - message.sender_id = "1234567890"; - message.data["data"] = "testdata"; - push_service()->OnMessage(app_id.app_id_guid(), message); - - callback.WaitUntilSatisfied(); - EXPECT_EQ(app_id.app_id_guid(), callback.app_id()); - - // No push data should have been received. - ASSERT_TRUE(RunScript("resultQueue.popImmediately()", &script_result)); - EXPECT_EQ("null", script_result); -} - -#if defined(ENABLE_NOTIFICATIONS) -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - PushEventEnforcesUserVisibleNotification) { - if (!IsPushSupported()) - return; - - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); - EXPECT_EQ(app_id.app_id_guid(), 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); - - notification_manager()->CancelAll(); - ASSERT_EQ(0u, notification_manager()->GetNotificationCount()); - - // We'll need to specify the web_contents in which to eval script, since we're - // going to run script in a background tab. - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - - // If the site is visible in an active tab, we should not force a notification - // to be shown. Try it twice, since we allow one mistake per 10 push events. - GCMClient::IncomingMessage message; - message.sender_id = "1234567890"; - for (int n = 0; n < 2; n++) { - message.data["data"] = "testdata"; - push_service()->OnMessage(app_id.app_id_guid(), message); - ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result)); - EXPECT_EQ("testdata", script_result); - EXPECT_EQ(0u, notification_manager()->GetNotificationCount()); - } - - // Open a blank foreground tab so site is no longer visible. - ui_test_utils::NavigateToURLWithDisposition( - browser(), GURL("about:blank"), NEW_FOREGROUND_TAB, - ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB); - - // If the Service Worker push event handler does not show a notification, we - // should show a forced one, but only on the 2nd occurrence since we allow one - // mistake per 10 push events. - message.data["data"] = "testdata"; - push_service()->OnMessage(app_id.app_id_guid(), message); - ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents)); - EXPECT_EQ("testdata", script_result); - EXPECT_EQ(0u, notification_manager()->GetNotificationCount()); - message.data["data"] = "testdata"; - push_service()->OnMessage(app_id.app_id_guid(), message); - ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents)); - EXPECT_EQ("testdata", script_result); - EXPECT_EQ(1u, notification_manager()->GetNotificationCount()); - EXPECT_EQ(base::ASCIIToUTF16(kPushMessagingForcedNotificationTag), - notification_manager()->GetNotificationAt(0).replace_id()); - - // Currently, this notification will stick around until the user or webapp - // explicitly dismisses it (though we may change this later). - message.data["data"] = "shownotification"; - push_service()->OnMessage(app_id.app_id_guid(), message); - ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents)); - EXPECT_EQ("shownotification", script_result); - EXPECT_EQ(2u, notification_manager()->GetNotificationCount()); - - notification_manager()->CancelAll(); - EXPECT_EQ(0u, notification_manager()->GetNotificationCount()); - - // However if the Service Worker push event handler shows a notification, we - // should not show a forced one. - message.data["data"] = "shownotification"; - for (int n = 0; n < 9; n++) { - push_service()->OnMessage(app_id.app_id_guid(), message); - ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents)); - EXPECT_EQ("shownotification", script_result); - EXPECT_EQ(1u, notification_manager()->GetNotificationCount()); - EXPECT_EQ(base::ASCIIToUTF16("push_test_tag"), - notification_manager()->GetNotificationAt(0).replace_id()); - notification_manager()->CancelAll(); - } - - // Now that 10 push messages in a row have shown notifications, we should - // allow the next one to mistakenly not show a notification. - message.data["data"] = "testdata"; - push_service()->OnMessage(app_id.app_id_guid(), message); - ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents)); - EXPECT_EQ("testdata", script_result); - EXPECT_EQ(0u, notification_manager()->GetNotificationCount()); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - PushEventNotificationWithoutEventWaitUntil) { - if (!IsPushSupported()) - return; - - std::string script_result; - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); - EXPECT_EQ(app_id.app_id_guid(), 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); - - NotificationAddedCallback callback; - notification_manager()->SetNotificationAddedCallback( - base::Bind(&NotificationAddedCallback::Run, base::Unretained(&callback))); - - GCMClient::IncomingMessage message; - message.sender_id = "1234567890"; - message.data["data"] = "shownotification-without-waituntil"; - push_service()->OnMessage(app_id.app_id_guid(), message); - ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents)); - EXPECT_EQ("immediate:shownotification-without-waituntil", script_result); - - callback.WaitUntilSatisfied(); - - ASSERT_EQ(1u, notification_manager()->GetNotificationCount()); - EXPECT_EQ(base::ASCIIToUTF16("push_test_tag"), - notification_manager()->GetNotificationAt(0).replace_id()); - - // Verify that the renderer process hasn't crashed. - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); -} -#endif - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, HasPermissionSaysDefault) { - if (!IsPushSupported()) - return; - - 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) { - if (!IsPushSupported()) - return; - - 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-0", script_result); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, HasPermissionSaysDenied) { - if (!IsPushSupported()) - return; - - 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); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, UnregisterSuccess) { - if (!IsPushSupported()) - return; - - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - gcm_service()->AddExpectedUnregisterResponse(GCMClient::SUCCESS); - - ASSERT_TRUE(RunScript("unregister()", &script_result)); - EXPECT_EQ("unregister result: true", script_result); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, UnregisterNetworkError) { - if (!IsPushSupported()) - return; - - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - gcm_service()->AddExpectedUnregisterResponse(GCMClient::NETWORK_ERROR); - - ASSERT_TRUE(RunScript("unregister()", &script_result)); - EXPECT_EQ("unregister error: NetworkError: " - "Unregistration failed - could not connect to push server", - script_result); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, UnregisterAbortError) { - if (!IsPushSupported()) - return; - - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - gcm_service()->AddExpectedUnregisterResponse(GCMClient::UNKNOWN_ERROR); - - ASSERT_TRUE(RunScript("unregister()", &script_result)); - EXPECT_EQ("unregister error: " - "AbortError: Unregistration failed - push service error", - script_result); -} - -#if defined(OS_ANDROID) -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushUnavailableOnAndroidICS) { - // This test should only run on Android ICS to confirm that the Push API - // is not available on that version of Android. - if (IsPushSupported()) - return; - - std::string script_result; - ASSERT_TRUE(RunScript("window.PushManager", &script_result)); - EXPECT_EQ("undefined", script_result); -} -#endif - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - GlobalResetPushPermissionUnregisters) { - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("true - registered", script_result); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); - - browser()->profile()->GetHostContentSettingsMap()-> - ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - default", script_result); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("false - not registered", script_result); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - LocalResetPushPermissionUnregisters) { - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("true - registered", script_result); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); - - GURL origin = https_server()->GetURL(std::string()).GetOrigin(); - browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( - ContentSettingsPattern::FromURLNoWildcard(origin), - ContentSettingsPattern::FromURLNoWildcard(origin), - CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, - std::string(), - CONTENT_SETTING_DEFAULT); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - default", script_result); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("false - not registered", script_result); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - DenyPushPermissionUnregisters) { - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("true - registered", script_result); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); - - GURL origin = https_server()->GetURL(std::string()).GetOrigin(); - browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( - ContentSettingsPattern::FromURLNoWildcard(origin), - ContentSettingsPattern::FromURLNoWildcard(origin), - CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, - std::string(), - CONTENT_SETTING_BLOCK); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - denied", script_result); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("false - not registered", script_result); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - GlobalResetNotificationsPermissionUnregisters) { - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("true - registered", script_result); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); - - browser()->profile()->GetHostContentSettingsMap()-> - ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_NOTIFICATIONS); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - default", script_result); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("false - not registered", script_result); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - LocalResetNotificationsPermissionUnregisters) { - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("true - registered", script_result); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); - - GURL origin = https_server()->GetURL(std::string()).GetOrigin(); - browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( - ContentSettingsPattern::FromURLNoWildcard(origin), - ContentSettingsPattern::Wildcard(), - CONTENT_SETTINGS_TYPE_NOTIFICATIONS, - std::string(), - CONTENT_SETTING_DEFAULT); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - default", script_result); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("false - not registered", script_result); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - DenyNotificationsPermissionUnregisters) { - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("true - registered", script_result); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); - - GURL origin = https_server()->GetURL(std::string()).GetOrigin(); - browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( - ContentSettingsPattern::FromURLNoWildcard(origin), - ContentSettingsPattern::Wildcard(), - CONTENT_SETTINGS_TYPE_NOTIFICATIONS, - std::string(), - CONTENT_SETTING_BLOCK); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - denied", script_result); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("false - not registered", script_result); -} - -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - GrantAlreadyGrantedPermissionDoesNotUnregister) { - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("true - registered", script_result); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); - - GURL origin = https_server()->GetURL(std::string()).GetOrigin(); - browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( - ContentSettingsPattern::FromURLNoWildcard(origin), - ContentSettingsPattern::Wildcard(), - CONTENT_SETTINGS_TYPE_NOTIFICATIONS, - std::string(), - CONTENT_SETTING_ALLOW); - browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( - ContentSettingsPattern::FromURLNoWildcard(origin), - ContentSettingsPattern::FromURLNoWildcard(origin), - CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, - std::string(), - CONTENT_SETTING_ALLOW); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("true - registered", script_result); -} - -// This test is testing some non-trivial content settings rules and make sure -// that they are respected with regards to automatic unregistration. In other -// words, it checks that the push service does not end up unregistering origins -// that have push permission with some non-common rules. -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - AutomaticUnregistrationFollowsContentSettingRules) { - std::string script_result; - - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("true - registered", script_result); - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); - - GURL origin = https_server()->GetURL(std::string()).GetOrigin(); - browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( - ContentSettingsPattern::Wildcard(), - ContentSettingsPattern::Wildcard(), - CONTENT_SETTINGS_TYPE_NOTIFICATIONS, - std::string(), - CONTENT_SETTING_ALLOW); - browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( - ContentSettingsPattern::FromString("https://*"), - ContentSettingsPattern::FromString("https://*"), - CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, - std::string(), - CONTENT_SETTING_ALLOW); - browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( - ContentSettingsPattern::FromURLNoWildcard(origin), - ContentSettingsPattern::Wildcard(), - CONTENT_SETTINGS_TYPE_NOTIFICATIONS, - std::string(), - CONTENT_SETTING_DEFAULT); - browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( - ContentSettingsPattern::FromURLNoWildcard(origin), - ContentSettingsPattern::FromURLNoWildcard(origin), - CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, - std::string(), - CONTENT_SETTING_DEFAULT); - - // The two first rules should give |origin| the permission to use Push even - // if the rules it used to have have been reset. - // The Push service should not unsubcribe |origin| because at no point it was - // left without permission to use Push. - - ASSERT_TRUE(RunScript("hasPermission()", &script_result)); - EXPECT_EQ("permission status - granted", script_result); - - ASSERT_TRUE(RunScript("hasRegistration()", &script_result)); - EXPECT_EQ("true - registered", script_result); -} - -} // namespace gcm
diff --git a/chrome/browser/services/gcm/push_messaging_constants.cc b/chrome/browser/services/gcm/push_messaging_constants.cc deleted file mode 100644 index 9b46d59..0000000 --- a/chrome/browser/services/gcm/push_messaging_constants.cc +++ /dev/null
@@ -1,14 +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 "chrome/browser/services/gcm/push_messaging_constants.h" - -namespace gcm { - -const char kPushMessagingEndpoint[] = "https://android.googleapis.com/gcm/send"; - -const char kPushMessagingForcedNotificationTag[] = - "user_visible_auto_notification"; - -} // namespace gcm
diff --git a/chrome/browser/services/gcm/push_messaging_constants.h b/chrome/browser/services/gcm/push_messaging_constants.h deleted file mode 100644 index 9b3cb23..0000000 --- a/chrome/browser/services/gcm/push_messaging_constants.h +++ /dev/null
@@ -1,18 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_CONSTANTS_H_ -#define CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_CONSTANTS_H_ - -namespace gcm { - -extern const char kPushMessagingEndpoint[]; - -// The tag of the notification that will be automatically shown if a webapp -// receives a push message then fails to show a notification. -extern const char kPushMessagingForcedNotificationTag[]; - -} // namespace gcm - -#endif // CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_CONSTANTS_H_
diff --git a/chrome/browser/services/gcm/push_messaging_permission_context.cc b/chrome/browser/services/gcm/push_messaging_permission_context.cc deleted file mode 100644 index bb39adce..0000000 --- a/chrome/browser/services/gcm/push_messaging_permission_context.cc +++ /dev/null
@@ -1,142 +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 "chrome/browser/services/gcm/push_messaging_permission_context.h" - -#include "chrome/browser/content_settings/permission_context_uma_util.h" -#include "chrome/browser/notifications/desktop_notification_service.h" -#include "chrome/browser/notifications/desktop_notification_service_factory.h" -#include "chrome/browser/profiles/profile.h" -#include "components/content_settings/core/browser/host_content_settings_map.h" -#include "components/content_settings/core/common/permission_request_id.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_delegate.h" - -const ContentSettingsType kPushSettingType = - CONTENT_SETTINGS_TYPE_PUSH_MESSAGING; - -namespace gcm { - -PushMessagingPermissionContext::PushMessagingPermissionContext(Profile* profile) - : PermissionContextBase(profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING), - profile_(profile), - weak_factory_ui_thread_(this) { -} - -PushMessagingPermissionContext::~PushMessagingPermissionContext() { -} - -ContentSetting PushMessagingPermissionContext::GetPermissionStatus( - const GURL& requesting_origin, - const GURL& embedding_origin) const { -#if defined(ENABLE_NOTIFICATIONS) - if (requesting_origin != embedding_origin) - return CONTENT_SETTING_BLOCK; - - ContentSetting push_content_setting = - profile_->GetHostContentSettingsMap()->GetContentSetting( - requesting_origin, embedding_origin, kPushSettingType, std::string()); - - DesktopNotificationService* notification_service = - DesktopNotificationServiceFactory::GetForProfile(profile_); - DCHECK(notification_service); - - ContentSetting notifications_permission = - notification_service->GetPermissionStatus(requesting_origin, - embedding_origin); - - if (notifications_permission == CONTENT_SETTING_BLOCK || - push_content_setting == CONTENT_SETTING_BLOCK) { - return CONTENT_SETTING_BLOCK; - } - if (notifications_permission == CONTENT_SETTING_ASK || - push_content_setting == CONTENT_SETTING_ASK) { - return CONTENT_SETTING_ASK; - } - DCHECK_EQ(CONTENT_SETTING_ALLOW, notifications_permission); - DCHECK_EQ(CONTENT_SETTING_ALLOW, push_content_setting); - return CONTENT_SETTING_ALLOW; -#else - return CONTENT_SETTING_BLOCK; -#endif -} - -void PushMessagingPermissionContext::CancelPermissionRequest( - content::WebContents* web_contents, const PermissionRequestID& id) { - // TODO(peter): consider implementing this method. - NOTIMPLEMENTED() << "CancelPermission not implemented for push messaging"; -} - -// 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. -// This is done to avoid double prompting for notifications and push. -void PushMessagingPermissionContext::DecidePermission( - content::WebContents* web_contents, - const PermissionRequestID& id, - const GURL& requesting_origin, - const GURL& embedding_origin, - bool user_gesture, - const BrowserPermissionCallback& callback) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); -#if defined(ENABLE_NOTIFICATIONS) - if (requesting_origin != embedding_origin) { - NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, - false /* persist */, false /* granted */); - return; - } - DesktopNotificationService* notification_service = - DesktopNotificationServiceFactory::GetForProfile(profile_); - DCHECK(notification_service); - - notification_service->RequestPermission( - web_contents, id, requesting_origin, user_gesture, - base::Bind(&PushMessagingPermissionContext::DecidePushPermission, - weak_factory_ui_thread_.GetWeakPtr(), id, requesting_origin, - embedding_origin, callback)); -#else - NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, - false /* persist */, false /* granted */); -#endif -} - -void PushMessagingPermissionContext::DecidePushPermission( - const PermissionRequestID& id, - const GURL& requesting_origin, - const GURL& embedding_origin, - const BrowserPermissionCallback& callback, - bool notifications_permission_granted) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - ContentSetting push_content_setting = - profile_->GetHostContentSettingsMap() - ->GetContentSettingAndMaybeUpdateLastUsage( - requesting_origin, embedding_origin, kPushSettingType, - std::string()); - - if (push_content_setting == CONTENT_SETTING_BLOCK) { - DVLOG(1) << "Push permission was explicitly blocked."; - PermissionContextUmaUtil::PermissionDenied(kPushSettingType, - requesting_origin); - NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, - true /* persist */, false /* granted */); - return; - } - - if (!notifications_permission_granted) { - DVLOG(1) << "Notification permission has not been granted."; - NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, - false /* persist */, false /* granted */); - return; - } - - PermissionContextUmaUtil::PermissionGranted(kPushSettingType, - requesting_origin); - NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, - true /* persist */, true /* granted */); -} -} // namespace gcm -
diff --git a/chrome/browser/services/gcm/push_messaging_permission_context.h b/chrome/browser/services/gcm/push_messaging_permission_context.h deleted file mode 100644 index 0b4a49fb..0000000 --- a/chrome/browser/services/gcm/push_messaging_permission_context.h +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_PERMISSION_CONTEXT_H_ -#define CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_PERMISSION_CONTEXT_H_ - -#include "chrome/browser/content_settings/permission_context_base.h" - -#include "components/content_settings/core/common/content_settings_types.h" - -class PermissionRequestID; -class Profile; - -namespace gcm { - -// Permission context for push messages. -class PushMessagingPermissionContext : public PermissionContextBase { - public: - explicit PushMessagingPermissionContext(Profile* profile); - ~PushMessagingPermissionContext() override; - - // PermissionContextBase: - ContentSetting GetPermissionStatus( - const GURL& requesting_origin, - const GURL& embedding_origin) const override; - - void CancelPermissionRequest(content::WebContents* web_contents, - const PermissionRequestID& id) override; - - protected: - // PermissionContextBase: - void DecidePermission(content::WebContents* web_contents, - const PermissionRequestID& id, - const GURL& requesting_origin, - const GURL& embedding_origin, - bool user_gesture, - const BrowserPermissionCallback& callback) override; - - private: - FRIEND_TEST_ALL_PREFIXES(PushMessagingPermissionContextTest, - DecidePushPermission); - - // Used to decide the permission for push, once the permission for - // Notification has been granted/denied. - void DecidePushPermission(const PermissionRequestID& id, - const GURL& requesting_origin, - const GURL& embedding_origin, - const BrowserPermissionCallback& callback, - bool notifications_permission_granted); - - Profile* profile_; - - // Must be the last member, to ensure that it will be - // destroyed first, which will invalidate weak pointers - base::WeakPtrFactory<PushMessagingPermissionContext> weak_factory_ui_thread_; - - DISALLOW_COPY_AND_ASSIGN(PushMessagingPermissionContext); -}; - -} // namespace gcm -#endif // CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_PERMISSION_CONTEXT_H_
diff --git a/chrome/browser/services/gcm/push_messaging_permission_context_factory.cc b/chrome/browser/services/gcm/push_messaging_permission_context_factory.cc deleted file mode 100644 index d60297f4..0000000 --- a/chrome/browser/services/gcm/push_messaging_permission_context_factory.cc +++ /dev/null
@@ -1,49 +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 "chrome/browser/services/gcm/push_messaging_permission_context_factory.h" - -#include "chrome/browser/profiles/incognito_helpers.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/services/gcm/push_messaging_permission_context.h" -#include "components/keyed_service/content/browser_context_dependency_manager.h" - -namespace gcm { - -// static -PushMessagingPermissionContext* -PushMessagingPermissionContextFactory::GetForProfile( - Profile* profile) { - return static_cast<PushMessagingPermissionContext*>( - GetInstance()->GetServiceForBrowserContext(profile, true)); -} - -// static -PushMessagingPermissionContextFactory* -PushMessagingPermissionContextFactory::GetInstance() { - return Singleton<PushMessagingPermissionContextFactory>::get(); -} - -PushMessagingPermissionContextFactory::PushMessagingPermissionContextFactory() - : BrowserContextKeyedServiceFactory( - "GCMPermissionContext", - BrowserContextDependencyManager::GetInstance()) { -} - -PushMessagingPermissionContextFactory -::~PushMessagingPermissionContextFactory() { -} - -KeyedService* PushMessagingPermissionContextFactory::BuildServiceInstanceFor( - content::BrowserContext* profile) const { - return new PushMessagingPermissionContext(static_cast<Profile*>(profile)); -} - -content::BrowserContext* -PushMessagingPermissionContextFactory::GetBrowserContextToUse( - content::BrowserContext* context) const { - return chrome::GetBrowserContextOwnInstanceInIncognito(context); -} - -} // namespace gcm
diff --git a/chrome/browser/services/gcm/push_messaging_permission_context_factory.h b/chrome/browser/services/gcm/push_messaging_permission_context_factory.h deleted file mode 100644 index 45be2d3..0000000 --- a/chrome/browser/services/gcm/push_messaging_permission_context_factory.h +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_PERMISSION_CONTEXT_FACTORY_H_ -#define CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_PERMISSION_CONTEXT_FACTORY_H_ - -#include "base/memory/singleton.h" -#include "components/keyed_service/content/browser_context_keyed_service_factory.h" - -class Profile; - -namespace gcm { - -class PushMessagingPermissionContext; - -class PushMessagingPermissionContextFactory - : public BrowserContextKeyedServiceFactory { - public: - static PushMessagingPermissionContext* GetForProfile(Profile* profile); - static PushMessagingPermissionContextFactory* GetInstance(); - - private: - friend struct DefaultSingletonTraits<PushMessagingPermissionContextFactory>; - - PushMessagingPermissionContextFactory(); - ~PushMessagingPermissionContextFactory() override; - - // BrowserContextKeyedBaseFactory methods: - KeyedService* BuildServiceInstanceFor( - content::BrowserContext* profile) const override; - content::BrowserContext* GetBrowserContextToUse( - content::BrowserContext* context) const override; - - DISALLOW_COPY_AND_ASSIGN(PushMessagingPermissionContextFactory); -}; - -} // namespace gcm -#endif // CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_PERMISSION_CONTEXT_FACTORY_H_
diff --git a/chrome/browser/services/gcm/push_messaging_permission_context_unittest.cc b/chrome/browser/services/gcm/push_messaging_permission_context_unittest.cc deleted file mode 100644 index a42e2de..0000000 --- a/chrome/browser/services/gcm/push_messaging_permission_context_unittest.cc +++ /dev/null
@@ -1,166 +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 "chrome/browser/services/gcm/push_messaging_permission_context.h" -#include "chrome/test/base/testing_profile.h" -#include "components/content_settings/core/browser/host_content_settings_map.h" -#include "components/content_settings/core/common/content_settings.h" -#include "components/content_settings/core/common/content_settings_types.h" -#include "components/content_settings/core/common/permission_request_id.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "testing/gtest/include/gtest/gtest.h" - -const char kOriginA[] = "https://origina.org"; -const char kOriginB[] = "https://originb.org"; - -namespace gcm { - -class TestPushMessagingPermissionContext - : public PushMessagingPermissionContext { - public: - explicit TestPushMessagingPermissionContext(Profile* profile) - : PushMessagingPermissionContext(profile), - was_persisted_(false), - permission_granted_(false) {} - - bool was_persisted() const { return was_persisted_; } - bool was_granted() const { return permission_granted_; } - - private: - // PushMessagingPermissionContext: - void NotifyPermissionSet(const PermissionRequestID& id, - const GURL& requesting_origin, - const GURL& embedder_origin, - const BrowserPermissionCallback& callback, - bool persist, - bool allowed) override { - was_persisted_ = persist; - permission_granted_ = allowed; - } - - bool was_persisted_; - bool permission_granted_; -}; - -class PushMessagingPermissionContextTest : public testing::Test { - public: - PushMessagingPermissionContextTest() {} - - protected: - void SetContentSetting(Profile* profile, - ContentSettingsType setting, - ContentSetting value) { - ContentSettingsPattern pattern = - ContentSettingsPattern::FromString(kOriginA); - HostContentSettingsMap* host_content_settings_map = - profile->GetHostContentSettingsMap(); - host_content_settings_map->SetContentSetting(pattern, pattern, setting, - std::string(), value); - } - - content::TestBrowserThreadBundle thread_bundle_; -}; - -TEST_F(PushMessagingPermissionContextTest, HasPermissionPrompt) { - TestingProfile profile; - PushMessagingPermissionContext context(&profile); - EXPECT_EQ(CONTENT_SETTING_ASK, - context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); - - // Just granting notifications should still prompt - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, - CONTENT_SETTING_ALLOW); - - EXPECT_EQ(CONTENT_SETTING_ASK, - context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); - - // Just granting push should still prompt - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, - CONTENT_SETTING_ASK); - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, - CONTENT_SETTING_ALLOW); - - EXPECT_EQ(CONTENT_SETTING_ASK, - context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); -} - -TEST_F(PushMessagingPermissionContextTest, HasPermissionDenySettingsMismatch) { - TestingProfile profile; - PushMessagingPermissionContext context(&profile); - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, - CONTENT_SETTING_BLOCK); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, - CONTENT_SETTING_ASK); - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, - CONTENT_SETTING_BLOCK); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, - CONTENT_SETTING_ALLOW); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); - - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, - CONTENT_SETTING_ASK); - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, - CONTENT_SETTING_BLOCK); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); -} - -TEST_F(PushMessagingPermissionContextTest, HasPermissionDenyDifferentOrigins) { - TestingProfile profile; - PushMessagingPermissionContext context(&profile); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - context.GetPermissionStatus(GURL(kOriginB), GURL(kOriginA))); -} - -TEST_F(PushMessagingPermissionContextTest, HasPermissionAccept) { - TestingProfile profile; - PushMessagingPermissionContext context(&profile); - - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, - CONTENT_SETTING_ALLOW); - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, - CONTENT_SETTING_ALLOW); - EXPECT_EQ(CONTENT_SETTING_ALLOW, - context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); -} - -TEST_F(PushMessagingPermissionContextTest, DecidePushPermission) { - TestingProfile profile; - TestPushMessagingPermissionContext context(&profile); - PermissionRequestID request_id(-1, -1, -1, GURL(kOriginA)); - BrowserPermissionCallback callback; - - context.DecidePushPermission(request_id, GURL(kOriginA), GURL(kOriginA), - callback, false); - EXPECT_FALSE(context.was_persisted()); - EXPECT_FALSE(context.was_granted()); - - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, - CONTENT_SETTING_ALLOW); - context.DecidePushPermission(request_id, GURL(kOriginA), GURL(kOriginA), - callback, true); - EXPECT_TRUE(context.was_persisted()); - EXPECT_TRUE(context.was_granted()); - - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, - CONTENT_SETTING_BLOCK); - context.DecidePushPermission(request_id, GURL(kOriginA), GURL(kOriginA), - callback, true); - EXPECT_TRUE(context.was_persisted()); - EXPECT_FALSE(context.was_granted()); - - SetContentSetting(&profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, - CONTENT_SETTING_ASK); - context.DecidePushPermission(request_id, GURL(kOriginA), GURL(kOriginA), - callback, true); - EXPECT_TRUE(context.was_persisted()); - EXPECT_TRUE(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 deleted file mode 100644 index 49b36d0..0000000 --- a/chrome/browser/services/gcm/push_messaging_service_impl.cc +++ /dev/null
@@ -1,791 +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 "chrome/browser/services/gcm/push_messaging_service_impl.h" - -#include <bitset> -#include <vector> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/metrics/histogram.h" -#include "base/prefs/pref_service.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/notifications/notification_ui_manager.h" -#include "chrome/browser/notifications/platform_notification_service_impl.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/services/gcm/gcm_profile_service.h" -#include "chrome/browser/services/gcm/gcm_profile_service_factory.h" -#include "chrome/browser/services/gcm/push_messaging_application_id.h" -#include "chrome/browser/services/gcm/push_messaging_constants.h" -#include "chrome/browser/services/gcm/push_messaging_permission_context.h" -#include "chrome/browser/services/gcm/push_messaging_permission_context_factory.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/pref_names.h" -#include "chrome/grit/generated_resources.h" -#include "components/content_settings/core/browser/host_content_settings_map.h" -#include "components/content_settings/core/common/permission_request_id.h" -#include "components/gcm_driver/gcm_driver.h" -#include "components/pref_registry/pref_registry_syncable.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/service_worker_context.h" -#include "content/public/browser/storage_partition.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/child_process_host.h" -#include "content/public/common/content_switches.h" -#include "content/public/common/platform_notification_data.h" -#include "content/public/common/push_messaging_status.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/base/l10n/l10n_util.h" - -#if defined(OS_ANDROID) -#include "chrome/browser/ui/android/tab_model/tab_model.h" -#include "chrome/browser/ui/android/tab_model/tab_model_list.h" -#else -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_iterator.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" -#endif - -namespace gcm { - -namespace { -const int kMaxRegistrations = 1000000; - -void RecordDeliveryStatus(content::PushDeliveryStatus status) { - UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus", - status, - content::PUSH_DELIVERY_STATUS_LAST + 1); -} - -void RecordUserVisibleStatus(content::PushUserVisibleStatus status) { - UMA_HISTOGRAM_ENUMERATION("PushMessaging.UserVisibleStatus", - status, - content::PUSH_USER_VISIBLE_STATUS_LAST + 1); -} - -blink::WebPushPermissionStatus ToPushPermission(ContentSetting setting) { - switch (setting) { - case CONTENT_SETTING_ALLOW: - return blink::WebPushPermissionStatusGranted; - case CONTENT_SETTING_BLOCK: - return blink::WebPushPermissionStatusDenied; - case CONTENT_SETTING_ASK: - return blink::WebPushPermissionStatusDefault; - default: - NOTREACHED(); - return blink::WebPushPermissionStatusDenied; - } -} - -} // namespace - -// static -void PushMessagingServiceImpl::RegisterProfilePrefs( - user_prefs::PrefRegistrySyncable* registry) { - registry->RegisterIntegerPref( - prefs::kPushMessagingRegistrationCount, - 0, - user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); - PushMessagingApplicationId::RegisterProfilePrefs(registry); -} - -// static -void PushMessagingServiceImpl::InitializeForProfile(Profile* profile) { - // TODO(johnme): Consider whether push should be enabled in incognito. - if (!profile || profile->IsOffTheRecord()) - return; - - // TODO(johnme): If push becomes enabled in incognito (and this still uses a - // pref), be careful that this pref is read from the right profile, as prefs - // defined in a regular profile are visible in the corresponding incognito - // profile unless overridden. - // TODO(johnme): Make sure this pref doesn't get out of sync after crashes. - int count = profile->GetPrefs()->GetInteger( - prefs::kPushMessagingRegistrationCount); - if (count <= 0) - return; - - // Create the GCMProfileService, and hence instantiate this class. - GCMProfileService* gcm_service = - GCMProfileServiceFactory::GetForProfile(profile); - PushMessagingServiceImpl* push_service = - static_cast<PushMessagingServiceImpl*>( - gcm_service->push_messaging_service()); - - push_service->IncreasePushRegistrationCount(count, false /* is_pending */); -} - -PushMessagingServiceImpl::PushMessagingServiceImpl( - GCMProfileService* gcm_profile_service, - Profile* profile) - : gcm_profile_service_(gcm_profile_service), - profile_(profile), - push_registration_count_(0), - pending_push_registration_count_(0), - weak_factory_(this) { - // In some tests, we might end up with |profile_| being null at this point. - // When that is the case |profile_| will be set in SetProfileForTesting(), at - // which point the service will start to observe HostContentSettingsMap. - if (profile_) - profile_->GetHostContentSettingsMap()->AddObserver(this); -} - -PushMessagingServiceImpl::~PushMessagingServiceImpl() { - // TODO(johnme): If it's possible for this to be destroyed before GCMDriver, - // then we should call RemoveAppHandler. - profile_->GetHostContentSettingsMap()->RemoveObserver(this); -} - -void PushMessagingServiceImpl::IncreasePushRegistrationCount(int add, - bool is_pending) { - DCHECK(add > 0); - if (push_registration_count_ + pending_push_registration_count_ == 0) { - gcm_profile_service_->driver()->AddAppHandler( - kPushMessagingApplicationIdPrefix, this); - } - if (is_pending) { - pending_push_registration_count_ += add; - } else { - push_registration_count_ += add; - profile_->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount, - push_registration_count_); - } -} - -void PushMessagingServiceImpl::DecreasePushRegistrationCount(int subtract, - bool was_pending) { - DCHECK(subtract > 0); - if (was_pending) { - pending_push_registration_count_ -= subtract; - DCHECK(pending_push_registration_count_ >= 0); - } else { - push_registration_count_ -= subtract; - DCHECK(push_registration_count_ >= 0); - profile_->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount, - push_registration_count_); - } - if (push_registration_count_ + pending_push_registration_count_ == 0) { - gcm_profile_service_->driver()->RemoveAppHandler( - kPushMessagingApplicationIdPrefix); - } -} - -bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const { - return PushMessagingApplicationId::Get(profile_, app_id).IsValid(); -} - -void PushMessagingServiceImpl::ShutdownHandler() { - // TODO(johnme): Do any necessary cleanup. -} - -// OnMessage methods ----------------------------------------------------------- - -void PushMessagingServiceImpl::OnMessage( - const std::string& app_id, - const GCMClient::IncomingMessage& message) { - PushMessagingApplicationId application_id = - PushMessagingApplicationId::Get(profile_, app_id); - // Drop message and unregister if app id was unknown (maybe recently deleted). - if (!application_id.IsValid()) { - DeliverMessageCallback(app_id, GURL::EmptyGURL(), -1, message, - content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID); - return; - } - // Drop message and unregister if |origin| has lost push permission. - if (!HasPermission(application_id.origin())) { - DeliverMessageCallback(app_id, application_id.origin(), - application_id.service_worker_registration_id(), - message, - content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED); - return; - } - - // The Push API only exposes a single string of data in the push event fired - // on the Service Worker. When developers send messages using GCM to the Push - // API and want to include a message payload, they must pass a single key- - // value pair, where the key is "data" and the value is the string they want - // to be passed to their Service Worker. For example, they could send the - // following JSON using the HTTPS GCM API: - // { - // "registration_ids": ["FOO", "BAR"], - // "data": { - // "data": "BAZ", - // }, - // "delay_while_idle": true, - // } - // TODO(johnme): Make sure this is clearly documented for developers. - std::string data; - // TODO(peter): Message payloads are disabled pending mandatory encryption. - // https://crbug.com/449184 - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnablePushMessagePayload)) { - GCMClient::MessageData::const_iterator it = message.data.find("data"); - if (it != message.data.end()) - data = it->second; - } - - content::BrowserContext::DeliverPushMessage( - profile_, - application_id.origin(), - application_id.service_worker_registration_id(), - data, - base::Bind(&PushMessagingServiceImpl::DeliverMessageCallback, - weak_factory_.GetWeakPtr(), - application_id.app_id_guid(), application_id.origin(), - application_id.service_worker_registration_id(), message)); -} - -void PushMessagingServiceImpl::DeliverMessageCallback( - const std::string& app_id_guid, - const GURL& requesting_origin, - int64 service_worker_registration_id, - const GCMClient::IncomingMessage& message, - content::PushDeliveryStatus status) { - // TODO(mvanouwerkerk): Show a warning in the developer console of the - // Service Worker corresponding to app_id (and/or on an internals page). - // TODO(mvanouwerkerk): Is there a way to recover from failure? - switch (status) { - // Call RequireUserVisibleUX if the message was delivered to the Service - // Worker JS, even if the website's event handler failed (to prevent sites - // deliberately failing in order to avoid having to show notifications). - case content::PUSH_DELIVERY_STATUS_SUCCESS: - case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED: - RequireUserVisibleUX(requesting_origin, service_worker_registration_id); - break; - case content::PUSH_DELIVERY_STATUS_INVALID_MESSAGE: - case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR: - break; - case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID: - case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED: - case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER: - Unregister(app_id_guid, message.sender_id, true /* retry_on_failure */, - UnregisterCallback()); - break; - } - RecordDeliveryStatus(status); -} - -void PushMessagingServiceImpl::RequireUserVisibleUX( - const GURL& requesting_origin, int64 service_worker_registration_id) { -#if defined(ENABLE_NOTIFICATIONS) - // TODO(johnme): Relax this heuristic slightly. - PlatformNotificationServiceImpl* notification_service = - PlatformNotificationServiceImpl::GetInstance(); - // Can't use g_browser_process->notification_ui_manager(), since the test uses - // PlatformNotificationServiceImpl::SetNotificationUIManagerForTesting. - // TODO(peter): Remove the need to use both APIs here once Notification.get() - // is supported. - int notification_count = notification_service->GetNotificationUIManager()-> - GetAllIdsByProfileAndSourceOrigin(profile_, requesting_origin).size(); - // TODO(johnme): Hiding an existing notification should also count as a useful - // user-visible action done in response to a push message - but make sure that - // sending two messages in rapid succession which show then hide a - // notification doesn't count. - bool notification_shown = notification_count > 0; - - bool notification_needed = true; - // Sites with a currently visible tab don't need to show notifications. -#if defined(OS_ANDROID) - for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) { - Profile* profile = (*it)->GetProfile(); - content::WebContents* active_web_contents = - (*it)->GetActiveWebContents(); -#else - for (chrome::BrowserIterator it; !it.done(); it.Next()) { - Profile* profile = it->profile(); - content::WebContents* active_web_contents = - it->tab_strip_model()->GetActiveWebContents(); -#endif - if (!active_web_contents || !active_web_contents->GetMainFrame()) - continue; - - // Don't leak information from other profiles. - if (profile != profile_) - continue; - - // Ignore minimized windows etc. - switch (active_web_contents->GetMainFrame()->GetVisibilityState()) { - case blink::WebPageVisibilityStateHidden: - case blink::WebPageVisibilityStatePrerender: - continue; - case blink::WebPageVisibilityStateVisible: - break; - } - - // Use the visible URL since that's the one the user is aware of (and it - // doesn't matter whether the page loaded successfully). - const GURL& active_url = active_web_contents->GetVisibleURL(); - if (requesting_origin == active_url.GetOrigin()) { - notification_needed = false; - break; - } -#if defined(OS_ANDROID) - } -#else - } -#endif - - // Don't track push messages that didn't show a notification but were exempt - // from needing to do so. - if (notification_shown || notification_needed) { - content::ServiceWorkerContext* service_worker_context = - content::BrowserContext::GetStoragePartitionForSite( - profile_, requesting_origin)->GetServiceWorkerContext(); - - PushMessagingService::GetNotificationsShownByLastFewPushes( - service_worker_context, service_worker_registration_id, - base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShown, - weak_factory_.GetWeakPtr(), - requesting_origin, service_worker_registration_id, - notification_shown, notification_needed)); - } else { - RecordUserVisibleStatus( - content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN); - } -#endif // defined(ENABLE_NOTIFICATIONS) -} - -static void IgnoreResult(bool unused) { -} - -void PushMessagingServiceImpl::DidGetNotificationsShown( - const GURL& requesting_origin, int64 service_worker_registration_id, - bool notification_shown, bool notification_needed, - const std::string& data, bool success, bool not_found) { - content::ServiceWorkerContext* service_worker_context = - content::BrowserContext::GetStoragePartitionForSite( - profile_, requesting_origin)->GetServiceWorkerContext(); - - // We remember whether the last (up to) 10 pushes showed notifications. - const size_t MISSED_NOTIFICATIONS_LENGTH = 10; - // data is a string like "0001000", where '0' means shown, and '1' means - // needed but not shown. We manipulate it in bitset form. - std::bitset<MISSED_NOTIFICATIONS_LENGTH> missed_notifications(data); - - bool needed_but_not_shown = notification_needed && !notification_shown; - - // New entries go at the end, and old ones are shifted off the beginning once - // the history length is exceeded. - missed_notifications <<= 1; - missed_notifications[0] = needed_but_not_shown; - std::string updated_data(missed_notifications. - to_string<char, std::string::traits_type, std::string::allocator_type>()); - PushMessagingService::SetNotificationsShownByLastFewPushes( - service_worker_context, service_worker_registration_id, - requesting_origin, updated_data, - base::Bind(&IgnoreResult)); // This is a heuristic; ignore failure. - - if (notification_shown) { - RecordUserVisibleStatus( - notification_needed - ? content::PUSH_USER_VISIBLE_STATUS_REQUIRED_AND_SHOWN - : content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_BUT_SHOWN); - return; - } - if (needed_but_not_shown) { - if (missed_notifications.count() <= 1) { - RecordUserVisibleStatus( - content::PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_USED_GRACE); - return; - } - RecordUserVisibleStatus( - content:: - PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED); - // The site failed to show a notification when one was needed, and they have - // already failed once in the previous 10 push messages, so we will show a - // generic notification. See https://crbug.com/437277. - // TODO(johnme): The generic notification should probably automatically - // close itself when the next push message arrives? - content::PlatformNotificationData notification_data; - // TODO(johnme): Switch to FormatOriginForDisplay from crbug.com/402698 - notification_data.title = base::UTF8ToUTF16(requesting_origin.host()); - notification_data.direction = - content::PlatformNotificationData::NotificationDirectionLeftToRight; - notification_data.body = - l10n_util::GetStringUTF16(IDS_PUSH_MESSAGING_GENERIC_NOTIFICATION_BODY); - notification_data.tag = - base::ASCIIToUTF16(kPushMessagingForcedNotificationTag); - notification_data.icon = GURL(); // TODO(johnme): Better icon? - PlatformNotificationServiceImpl* notification_service = - PlatformNotificationServiceImpl::GetInstance(); - notification_service->DisplayPersistentNotification( - profile_, - service_worker_registration_id, - requesting_origin, - SkBitmap() /* icon */, - notification_data); - } -} - -// Other GCMAppHandler methods ------------------------------------------------- - -void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) { - // TODO(mvanouwerkerk): Fire push error event on the Service Worker - // corresponding to app_id. -} - -void PushMessagingServiceImpl::OnSendError( - const std::string& app_id, - const GCMClient::SendErrorDetails& send_error_details) { - NOTREACHED() << "The Push API shouldn't have sent messages upstream"; -} - -void PushMessagingServiceImpl::OnSendAcknowledged( - const std::string& app_id, - const std::string& message_id) { - NOTREACHED() << "The Push API shouldn't have sent messages upstream"; -} - -// GetPushEndpoint method ------------------------------------------------------ - -GURL PushMessagingServiceImpl::GetPushEndpoint() { - return GURL(std::string(kPushMessagingEndpoint)); -} - -// Register and GetPermissionStatus methods ------------------------------------ - -void PushMessagingServiceImpl::RegisterFromDocument( - const GURL& requesting_origin, - int64 service_worker_registration_id, - const std::string& sender_id, - int renderer_id, - int render_frame_id, - bool user_visible_only, - const content::PushMessagingService::RegisterCallback& callback) { - if (!gcm_profile_service_->driver()) { - NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?"; - return; - } - - PushMessagingApplicationId application_id = - PushMessagingApplicationId::Generate(requesting_origin, - service_worker_registration_id); - DCHECK(application_id.IsValid()); - - if (push_registration_count_ + pending_push_registration_count_ - >= kMaxRegistrations) { - RegisterEnd(callback, - std::string(), - content::PUSH_REGISTRATION_STATUS_LIMIT_REACHED); - return; - } - - content::RenderFrameHost* render_frame_host = - content::RenderFrameHost::FromID(renderer_id, render_frame_id); - if (!render_frame_host) - return; - - content::WebContents* web_contents = - content::WebContents::FromRenderFrameHost(render_frame_host); - if (!web_contents) - return; - - // TODO(miguelg) need to send this over IPC when bubble support is - // implemented. - int bridge_id = -1; - - const PermissionRequestID id( - renderer_id, web_contents->GetRoutingID(), bridge_id, GURL()); - - gcm::PushMessagingPermissionContext* permission_context = - gcm::PushMessagingPermissionContextFactory::GetForProfile(profile_); - - if (permission_context == NULL || !user_visible_only) { - RegisterEnd(callback, - std::string(), - content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); - return; - } - - // TODO(miguelg): Consider the value of |user_visible_only| when making - // the permission request. - // TODO(mlamouri): Move requesting Push permission over to using Mojo, and - // re-introduce the ability of |user_gesture| when bubbles require this. - // https://crbug.com/423770. - permission_context->RequestPermission( - web_contents, id, requesting_origin, true /* user_gesture */, - base::Bind(&PushMessagingServiceImpl::DidRequestPermission, - 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::Generate(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; - } - - 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; - } - - IncreasePushRegistrationCount(1, true /* is_pending */); - std::vector<std::string> sender_ids(1, sender_id); - gcm_profile_service_->driver()->Register( - application_id.app_id_guid(), sender_ids, - base::Bind(&PushMessagingServiceImpl::DidRegister, - weak_factory_.GetWeakPtr(), - application_id, register_callback)); -} - -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) { - callback.Run(registration_id, status); -} - -void PushMessagingServiceImpl::DidRegister( - const PushMessagingApplicationId& application_id, - const content::PushMessagingService::RegisterCallback& callback, - const std::string& registration_id, - GCMClient::Result result) { - content::PushRegistrationStatus status = - content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR; - switch (result) { - case GCMClient::SUCCESS: - status = content::PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE; - application_id.PersistToDisk(profile_); - IncreasePushRegistrationCount(1, false /* is_pending */); - break; - case GCMClient::INVALID_PARAMETER: - case GCMClient::GCM_DISABLED: - case GCMClient::ASYNC_OPERATION_PENDING: - case GCMClient::SERVER_ERROR: - case GCMClient::UNKNOWN_ERROR: - status = content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR; - break; - case GCMClient::NETWORK_ERROR: - case GCMClient::TTL_EXCEEDED: - status = content::PUSH_REGISTRATION_STATUS_NETWORK_ERROR; - break; - } - RegisterEnd(callback, registration_id, status); - DecreasePushRegistrationCount(1, true /* was_pending */); -} - -void PushMessagingServiceImpl::DidRequestPermission( - const PushMessagingApplicationId& application_id, - const std::string& sender_id, - const content::PushMessagingService::RegisterCallback& register_callback, - bool allow) { - if (!allow) { - RegisterEnd(register_callback, - std::string(), - content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); - return; - } - - // The GCMDriver could be NULL if GCMProfileService has been shut down. - if (!gcm_profile_service_->driver()) - return; - - IncreasePushRegistrationCount(1, true /* is_pending */); - std::vector<std::string> sender_ids(1, sender_id); - gcm_profile_service_->driver()->Register( - application_id.app_id_guid(), - sender_ids, - base::Bind(&PushMessagingServiceImpl::DidRegister, - weak_factory_.GetWeakPtr(), - application_id, register_callback)); -} - -// Unregister methods ---------------------------------------------------------- - -void PushMessagingServiceImpl::Unregister( - const GURL& requesting_origin, - int64 service_worker_registration_id, - const std::string& sender_id, - bool retry_on_failure, - const content::PushMessagingService::UnregisterCallback& callback) { - DCHECK(gcm_profile_service_->driver()); - - PushMessagingApplicationId application_id = PushMessagingApplicationId::Get( - profile_, requesting_origin, service_worker_registration_id); - if (!application_id.IsValid()) { - if (!callback.is_null()) { - callback.Run( - content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED); - } - return; - } - - Unregister(application_id.app_id_guid(), sender_id, retry_on_failure, - callback); -} - -void PushMessagingServiceImpl::Unregister( - const std::string& app_id_guid, - const std::string& sender_id, - bool retry_on_failure, - const content::PushMessagingService::UnregisterCallback& callback) { - DCHECK(gcm_profile_service_->driver()); - - if (retry_on_failure) { - // Delete the mapping for this app id, to guarantee that no messages get - // delivered in future (even if unregistration fails). - // TODO(johnme): Instead of deleting these app ids, store them elsewhere, - // and retry unregistration if it fails due to network errors. - PushMessagingApplicationId application_id = - PushMessagingApplicationId::Get(profile_, app_id_guid); - if (application_id.IsValid()) - application_id.DeleteFromDisk(profile_); - } - - const auto& unregister_callback = - base::Bind(&PushMessagingServiceImpl::DidUnregister, - weak_factory_.GetWeakPtr(), - app_id_guid, retry_on_failure, callback); -#if defined(OS_ANDROID) - // On Android the backend is different, and requires the original sender_id. - gcm_profile_service_->driver()->UnregisterWithSenderId(app_id_guid, sender_id, - unregister_callback); -#else - gcm_profile_service_->driver()->Unregister(app_id_guid, unregister_callback); -#endif -} - -void PushMessagingServiceImpl::DidUnregister( - const std::string& app_id_guid, - bool retry_on_failure, - const content::PushMessagingService::UnregisterCallback& callback, - GCMClient::Result result) { - if (result == GCMClient::SUCCESS) { - PushMessagingApplicationId application_id = - PushMessagingApplicationId::Get(profile_, app_id_guid); - if (!application_id.IsValid()) { - if (!callback.is_null()) { - callback.Run( - content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED); - } - return; - } - - application_id.DeleteFromDisk(profile_); - DecreasePushRegistrationCount(1, false /* was_pending */); - } - - // Internal calls pass a null callback. - if (!callback.is_null()) { - switch (result) { - case GCMClient::SUCCESS: - callback.Run(content::PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED); - break; - case GCMClient::INVALID_PARAMETER: - case GCMClient::GCM_DISABLED: - case GCMClient::ASYNC_OPERATION_PENDING: - case GCMClient::SERVER_ERROR: - case GCMClient::UNKNOWN_ERROR: - callback.Run(content::PUSH_UNREGISTRATION_STATUS_SERVICE_ERROR); - break; - case GCMClient::NETWORK_ERROR: - case GCMClient::TTL_EXCEEDED: - callback.Run( - retry_on_failure - ? content:: - PUSH_UNREGISTRATION_STATUS_PENDING_WILL_RETRY_NETWORK_ERROR - : content::PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR); - break; - } - } -} - -// OnContentSettingChanged methods --------------------------------------------- - -void PushMessagingServiceImpl::OnContentSettingChanged( - const ContentSettingsPattern& primary_pattern, - const ContentSettingsPattern& secondary_pattern, - ContentSettingsType content_type, - std::string resource_identifier) { - if (content_type != CONTENT_SETTINGS_TYPE_PUSH_MESSAGING && - content_type != CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { - return; - } - - for (const auto& id : PushMessagingApplicationId::GetAll(profile_)) { - // If |primary_pattern| is not valid, we should always check for a - // permission change because it can happen for example when the entire - // Push or Notifications permissions are cleared. - // Otherwise, the permission should be checked if the pattern matches the - // origin. - if (primary_pattern.IsValid() && !primary_pattern.Matches(id.origin())) - continue; - - if (HasPermission(id.origin())) - continue; - - PushMessagingService::GetSenderId( - profile_, id.origin(), id.service_worker_registration_id(), - base::Bind( - &PushMessagingServiceImpl::UnregisterBecausePermissionRevoked, - weak_factory_.GetWeakPtr(), id)); - } -} - -void PushMessagingServiceImpl::UnregisterBecausePermissionRevoked( - const PushMessagingApplicationId& id, - const std::string& sender_id, bool success, bool not_found) { - // Unregister the PushMessagingApplicationId with the push service. - Unregister(id.app_id_guid(), sender_id, true /* retry_on_failure */, - UnregisterCallback()); - - // Clear the associated service worker push registration id. - PushMessagingService::ClearPushRegistrationID( - profile_, id.origin(), id.service_worker_registration_id()); -} - -// Helper methods -------------------------------------------------------------- - -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::SetProfileForTesting(Profile* profile) { - profile_ = profile; - profile_->GetHostContentSettingsMap()->AddObserver(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 deleted file mode 100644 index c5cb500..0000000 --- a/chrome/browser/services/gcm/push_messaging_service_impl.h +++ /dev/null
@@ -1,171 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_SERVICE_IMPL_H_ -#define CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_SERVICE_IMPL_H_ - -#include "base/compiler_specific.h" -#include "base/memory/weak_ptr.h" -#include "components/content_settings/core/browser/content_settings_observer.h" -#include "components/gcm_driver/gcm_app_handler.h" -#include "components/gcm_driver/gcm_client.h" -#include "content/public/browser/push_messaging_service.h" -#include "content/public/common/push_messaging_status.h" -#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h" - -class Profile; - -namespace user_prefs { -class PrefRegistrySyncable; -} - -namespace gcm { - -class GCMProfileService; -class PushMessagingApplicationId; - -class PushMessagingServiceImpl : public content::PushMessagingService, - public GCMAppHandler, - public content_settings::Observer { - public: - // Register profile-specific prefs for GCM. - static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); - - // If any Service Workers are using push, starts GCM and adds an app handler. - static void InitializeForProfile(Profile* profile); - - PushMessagingServiceImpl(GCMProfileService* gcm_profile_service, - Profile* profile); - ~PushMessagingServiceImpl() override; - - // GCMAppHandler implementation. - void ShutdownHandler() override; - void OnMessage(const std::string& app_id, - const GCMClient::IncomingMessage& message) override; - void OnMessagesDeleted(const std::string& app_id) override; - void OnSendError( - const std::string& app_id, - const GCMClient::SendErrorDetails& send_error_details) override; - void OnSendAcknowledged(const std::string& app_id, - const std::string& message_id) override; - bool CanHandle(const std::string& app_id) const override; - - // content::PushMessagingService implementation: - GURL GetPushEndpoint() 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_visible_only, - 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; - void Unregister( - const GURL& requesting_origin, - int64 service_worker_registration_id, - const std::string& sender_id, - bool retry_on_failure, - const content::PushMessagingService::UnregisterCallback&) override; - blink::WebPushPermissionStatus GetPermissionStatus( - const GURL& requesting_origin, - const GURL& embedding_origin) override; - - // content_settings::Observer implementation. - void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern, - const ContentSettingsPattern& secondary_pattern, - ContentSettingsType content_type, - std::string resource_identifier) override; - - void SetProfileForTesting(Profile* profile); - - private: - // A registration is pending until it has succeeded or failed. - void IncreasePushRegistrationCount(int add, bool is_pending); - void DecreasePushRegistrationCount(int subtract, bool was_pending); - - // OnMessage methods --------------------------------------------------------- - - void DeliverMessageCallback(const std::string& app_id_guid, - const GURL& requesting_origin, - int64 service_worker_registration_id, - const GCMClient::IncomingMessage& message, - content::PushDeliveryStatus status); - - // Developers are required to display a Web Notification in response to an - // incoming push message in order to clarify to the user that something has - // happened in the background. When they forget to do so, display a default - // notification on their behalf. - void RequireUserVisibleUX(const GURL& requesting_origin, - int64 service_worker_registration_id); - void DidGetNotificationsShown( - const GURL& requesting_origin, - int64 service_worker_registration_id, - bool notification_shown, - bool notification_needed, - const std::string& data, - bool success, - bool not_found); - - // Register methods ---------------------------------------------------------- - - void RegisterEnd( - const content::PushMessagingService::RegisterCallback& callback, - const std::string& registration_id, - content::PushRegistrationStatus status); - - void DidRegister( - const PushMessagingApplicationId& application_id, - const content::PushMessagingService::RegisterCallback& callback, - const std::string& registration_id, - GCMClient::Result result); - - void DidRequestPermission( - const PushMessagingApplicationId& application_id, - const std::string& sender_id, - const content::PushMessagingService::RegisterCallback& callback, - bool allow); - - // Unregister methods -------------------------------------------------------- - - void Unregister(const std::string& app_id_guid, - const std::string& sender_id, - bool retry_on_failure, - const content::PushMessagingService::UnregisterCallback&); - - void DidUnregister(const std::string& app_id_guid, - bool retry_on_failure, - const content::PushMessagingService::UnregisterCallback&, - GCMClient::Result result); - - // OnContentSettingChanged methods ------------------------------------------- - - void UnregisterBecausePermissionRevoked(const PushMessagingApplicationId& id, - const std::string& sender_id, - bool success, bool not_found); - - // Helper methods ------------------------------------------------------------ - - // Checks if a given origin is allowed to use Push. - bool HasPermission(const GURL& origin); - - GCMProfileService* gcm_profile_service_; // It owns us. - - Profile* profile_; // It owns our owner. - - int push_registration_count_; - int pending_push_registration_count_; - - base::WeakPtrFactory<PushMessagingServiceImpl> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(PushMessagingServiceImpl); -}; - -} // namespace gcm - -#endif // CHROME_BROWSER_SERVICES_GCM_PUSH_MESSAGING_SERVICE_IMPL_H_
diff --git a/chrome/browser/signin/fake_signin_manager.cc b/chrome/browser/signin/fake_signin_manager.cc index 5704738..503f1f9 100644 --- a/chrome/browser/signin/fake_signin_manager.cc +++ b/chrome/browser/signin/fake_signin_manager.cc
@@ -89,8 +89,8 @@ set_auth_in_progress(std::string()); set_password(std::string()); const std::string account_id = GetAuthenticatedAccountId(); - const std::string username = authenticated_username_; - authenticated_username_.clear(); + const std::string username = GetAuthenticatedUsername(); + ClearAuthenticatedUsername(); FOR_EACH_OBSERVER(SigninManagerBase::Observer, observer_list_, GoogleSignedOut(account_id, username));
diff --git a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc index 37a7ce6..668fe4a 100644 --- a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc +++ b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc
@@ -33,34 +33,47 @@ const char kApiScope[] = "https://www.googleapis.com/auth/kid.permission"; const int kNumRetries = 1; -const char kNamespace[] = "PERMISSION_CHROME_URL"; + +const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s"; + +// Request keys. +const char kNamespaceKey[] = "namespace"; +const char kObjectRefKey[] = "objectRef"; +const char kStateKey[] = "state"; + +// Request values. +const char kNamespaceURLRequest[] = "PERMISSION_CHROME_URL"; +const char kNamespaceUpdateRequest[] = "PERMISSION_CHROME_CWS_ITEM_UPDATE"; const char kState[] = "PENDING"; +// Response keys. const char kPermissionRequestKey[] = "permissionRequest"; const char kIdKey[] = "id"; -static const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s"; - struct PermissionRequestCreatorApiary::Request { - Request(const GURL& url_requested, + Request(const std::string& request_namespace, + const std::string& object_ref, const SuccessCallback& callback, int url_fetcher_id); ~Request(); - GURL url_requested; + std::string request_namespace; + std::string object_ref; SuccessCallback callback; scoped_ptr<OAuth2TokenService::Request> access_token_request; std::string access_token; bool access_token_expired; int url_fetcher_id; - scoped_ptr<net::URLFetcher> url_fetcher; + scoped_ptr<URLFetcher> url_fetcher; }; PermissionRequestCreatorApiary::Request::Request( - const GURL& url_requested, + const std::string& request_namespace, + const std::string& object_ref, const SuccessCallback& callback, int url_fetcher_id) - : url_requested(url_requested), + : request_namespace(request_namespace), + object_ref(object_ref), callback(callback), access_token_expired(false), url_fetcher_id(url_fetcher_id) { @@ -97,11 +110,16 @@ return true; } -void PermissionRequestCreatorApiary::CreatePermissionRequest( +void PermissionRequestCreatorApiary::CreateURLAccessRequest( const GURL& url_requested, const SuccessCallback& callback) { - requests_.push_back(new Request(url_requested, callback, url_fetcher_id_)); - StartFetching(requests_.back()); + CreateRequest(kNamespaceURLRequest, url_requested.spec(), callback); +} + +void PermissionRequestCreatorApiary::CreateExtensionUpdateRequest( + const std::string& extension_id, + const SuccessCallback& callback) { + CreateRequest(kNamespaceUpdateRequest, extension_id, callback); } GURL PermissionRequestCreatorApiary::GetApiUrl() const { @@ -127,6 +145,15 @@ } } +void PermissionRequestCreatorApiary::CreateRequest( + const std::string& request_namespace, + const std::string& object_ref, + const SuccessCallback& callback) { + requests_.push_back( + new Request(request_namespace, object_ref, callback, url_fetcher_id_)); + StartFetching(requests_.back()); +} + void PermissionRequestCreatorApiary::StartFetching(Request* request) { OAuth2TokenService::ScopeSet scopes; scopes.insert(GetApiScope()); @@ -160,9 +187,10 @@ base::StringPrintf(kAuthorizationHeaderFormat, access_token.c_str())); base::DictionaryValue dict; - dict.SetStringWithoutPathExpansion("namespace", kNamespace); - dict.SetStringWithoutPathExpansion("objectRef", (*it)->url_requested.spec()); - dict.SetStringWithoutPathExpansion("state", kState); + dict.SetStringWithoutPathExpansion(kNamespaceKey, (*it)->request_namespace); + dict.SetStringWithoutPathExpansion(kObjectRefKey, (*it)->object_ref); + dict.SetStringWithoutPathExpansion(kStateKey, kState); + std::string body; base::JSONWriter::Write(&dict, &body); (*it)->url_fetcher->SetUploadData("application/json", body);
diff --git a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.h b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.h index 14a6aa84..9556d68 100644 --- a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.h +++ b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.h
@@ -40,8 +40,10 @@ // PermissionRequestCreator implementation: bool IsEnabled() const override; - void CreatePermissionRequest(const GURL& url_requested, - const SuccessCallback& callback) override; + void CreateURLAccessRequest(const GURL& url_requested, + const SuccessCallback& callback) override; + void CreateExtensionUpdateRequest(const std::string& extension_id, + const SuccessCallback& callback) override; void set_url_fetcher_id_for_testing(int id) { url_fetcher_id_ = id; } @@ -62,6 +64,10 @@ GURL GetApiUrl() const; std::string GetApiScope() const; + void CreateRequest(const std::string& request_namespace, + const std::string& object_ref, + const SuccessCallback& callback); + // Requests an access token, which is the first thing we need. This is where // we restart when the returned access token has expired. void StartFetching(Request* request);
diff --git a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc index 35a8693d..50b4443 100644 --- a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc +++ b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc
@@ -56,7 +56,7 @@ void CreateRequest(int url_fetcher_id, const GURL& url) { permission_creator_.set_url_fetcher_id_for_testing(url_fetcher_id); - permission_creator_.CreatePermissionRequest( + permission_creator_.CreateURLAccessRequest( url, base::Bind(&PermissionRequestCreatorApiaryTest::OnRequestCreated, base::Unretained(this)));
diff --git a/chrome/browser/supervised_user/legacy/permission_request_creator_sync.cc b/chrome/browser/supervised_user/legacy/permission_request_creator_sync.cc index a4402e8..0bba1cee 100644 --- a/chrome/browser/supervised_user/legacy/permission_request_creator_sync.cc +++ b/chrome/browser/supervised_user/legacy/permission_request_creator_sync.cc
@@ -13,10 +13,10 @@ #include "net/base/escape.h" #include "url/gurl.h" -using base::Time; - const char kSupervisedUserAccessRequestKeyPrefix[] = "X-ManagedUser-AccessRequests"; +const char kSupervisedUserUpdateRequestKeyPrefix[] = + "X-ManagedUser-UpdateRequests"; const char kSupervisedUserAccessRequestTime[] = "timestamp"; const char kSupervisedUserName[] = "name"; @@ -48,20 +48,33 @@ state == GoogleServiceAuthError::SERVICE_UNAVAILABLE); } -void PermissionRequestCreatorSync::CreatePermissionRequest( +void PermissionRequestCreatorSync::CreateURLAccessRequest( const GURL& url_requested, const SuccessCallback& callback) { - // Escape the URL and add the prefix. + CreateRequest(kSupervisedUserAccessRequestKeyPrefix, + url_requested.spec(), + callback); +} + +void PermissionRequestCreatorSync::CreateExtensionUpdateRequest( + const std::string& extension_id, + const SuccessCallback& callback) { + CreateRequest(kSupervisedUserUpdateRequestKeyPrefix, extension_id, callback); +} + +void PermissionRequestCreatorSync::CreateRequest( + const std::string& prefix, + const std::string& data, + const SuccessCallback& callback) { + // Escape the data string and add the prefix. std::string key = SupervisedUserSettingsService::MakeSplitSettingKey( - kSupervisedUserAccessRequestKeyPrefix, - net::EscapeQueryParamValue(url_requested.spec(), true)); + prefix, + net::EscapeQueryParamValue(data, true)); scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue); - // TODO(sergiu): Use sane time here when it's ready. dict->SetDouble(kSupervisedUserAccessRequestTime, base::Time::Now().ToJsTime()); - dict->SetString(kSupervisedUserName, name_); // Copy the notification setting of the custodian.
diff --git a/chrome/browser/supervised_user/legacy/permission_request_creator_sync.h b/chrome/browser/supervised_user/legacy/permission_request_creator_sync.h index 0ba5eaa..552dca0 100644 --- a/chrome/browser/supervised_user/legacy/permission_request_creator_sync.h +++ b/chrome/browser/supervised_user/legacy/permission_request_creator_sync.h
@@ -14,6 +14,9 @@ class SupervisedUserSettingsService; class SupervisedUserSharedSettingsService; +// The requests are stored using a prefix followed by a URIEncoded version of +// the URL/extension ID. Each entry contains a dictionary which currently has +// the timestamp of the request in it. class PermissionRequestCreatorSync : public PermissionRequestCreator { public: PermissionRequestCreatorSync( @@ -26,10 +29,15 @@ // PermissionRequestCreator implementation: bool IsEnabled() const override; - void CreatePermissionRequest(const GURL& url_requested, - const SuccessCallback& callback) override; + void CreateURLAccessRequest(const GURL& url_requested, + const SuccessCallback& callback) override; + void CreateExtensionUpdateRequest(const std::string& extension_id, + const SuccessCallback& callback) override; private: + void CreateRequest(const std::string& prefix, + const std::string& data, + const SuccessCallback& callback); SupervisedUserSettingsService* settings_service_; SupervisedUserSharedSettingsService* shared_settings_service_; ProfileSyncService* sync_service_;
diff --git a/chrome/browser/supervised_user/permission_request_creator.h b/chrome/browser/supervised_user/permission_request_creator.h index 6237431..549f0c9 100644 --- a/chrome/browser/supervised_user/permission_request_creator.h +++ b/chrome/browser/supervised_user/permission_request_creator.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_SUPERVISED_USER_PERMISSION_REQUEST_CREATOR_H_ #define CHROME_BROWSER_SUPERVISED_USER_PERMISSION_REQUEST_CREATOR_H_ +#include <string> + #include "base/callback_forward.h" class GURL; @@ -23,8 +25,14 @@ // Creates a permission request for |url_requested| and calls |callback| with // the result (whether creating the permission request was successful). - virtual void CreatePermissionRequest(const GURL& url_requested, - const SuccessCallback& callback) = 0; + virtual void CreateURLAccessRequest(const GURL& url_requested, + const SuccessCallback& callback) = 0; + + // Creates a request to re-enable the extension with the given |extension_id|, + // which was disabled due to a permission increase. + virtual void CreateExtensionUpdateRequest( + const std::string& extension_id, + const SuccessCallback& callback) = 0; }; #endif // CHROME_BROWSER_SUPERVISED_USER_PERMISSION_REQUEST_CREATOR_H_
diff --git a/chrome/browser/supervised_user/supervised_user_constants.cc b/chrome/browser/supervised_user/supervised_user_constants.cc index a51b61c7..889577c 100644 --- a/chrome/browser/supervised_user/supervised_user_constants.cc +++ b/chrome/browser/supervised_user/supervised_user_constants.cc
@@ -6,13 +6,13 @@ namespace supervised_users { -const char kCameraMicAllowed[] = "CameraMicAllowed"; +const char kCameraMicDisabled[] = "CameraMicDisabled"; const char kContentPackDefaultFilteringBehavior[] = "ContentPackDefaultFilteringBehavior"; const char kContentPackManualBehaviorHosts[] = "ContentPackManualBehaviorHosts"; const char kContentPackManualBehaviorURLs[] = "ContentPackManualBehaviorURLs"; const char kForceSafeSearch[] = "ForceSafeSearch"; -const char kGeolocationAllowed[] = "GeolocationAllowed"; +const char kGeolocationDisabled[] = "GeolocationDisabled"; const char kRecordHistory[] = "RecordHistory"; const char kSigninAllowed[] = "SigninAllowed"; const char kUserName[] = "UserName";
diff --git a/chrome/browser/supervised_user/supervised_user_constants.h b/chrome/browser/supervised_user/supervised_user_constants.h index f72430b..e4aa3a0f 100644 --- a/chrome/browser/supervised_user/supervised_user_constants.h +++ b/chrome/browser/supervised_user/supervised_user_constants.h
@@ -9,12 +9,12 @@ // Keys for supervised user settings. These are configured remotely and mapped // to preferences by the SupervisedUserPrefStore. -extern const char kCameraMicAllowed[]; +extern const char kCameraMicDisabled[]; extern const char kContentPackDefaultFilteringBehavior[]; extern const char kContentPackManualBehaviorHosts[]; extern const char kContentPackManualBehaviorURLs[]; extern const char kForceSafeSearch[]; -extern const char kGeolocationAllowed[]; +extern const char kGeolocationDisabled[]; extern const char kRecordHistory[]; extern const char kSigninAllowed[]; extern const char kUserName[];
diff --git a/chrome/browser/supervised_user/supervised_user_interstitial.cc b/chrome/browser/supervised_user/supervised_user_interstitial.cc index 65798dc..fe59b984 100644 --- a/chrome/browser/supervised_user/supervised_user_interstitial.cc +++ b/chrome/browser/supervised_user/supervised_user_interstitial.cc
@@ -311,7 +311,7 @@ SupervisedUserService* supervised_user_service = SupervisedUserServiceFactory::GetForProfile(profile_); - supervised_user_service->AddAccessRequest( + supervised_user_service->AddURLAccessRequest( url_, base::Bind(&SupervisedUserInterstitial::OnAccessRequestAdded, weak_ptr_factory_.GetWeakPtr())); return;
diff --git a/chrome/browser/supervised_user/supervised_user_service.cc b/chrome/browser/supervised_user/supervised_user_service.cc index e464400..102b9f5 100644 --- a/chrome/browser/supervised_user/supervised_user_service.cc +++ b/chrome/browser/supervised_user/supervised_user_service.cc
@@ -78,6 +78,20 @@ prefs::kSupervisedUserSecondCustodianProfileURL, }; +void CreateURLAccessRequest( + const GURL& url, + PermissionRequestCreator* creator, + const SupervisedUserService::SuccessCallback& callback) { + creator->CreateURLAccessRequest(url, callback); +} + +void CreateExtensionUpdateRequest( + const std::string& extension_id, + PermissionRequestCreator* creator, + const SupervisedUserService::SuccessCallback& callback) { + creator->CreateExtensionUpdateRequest(extension_id, callback); +} + #if defined(ENABLE_EXTENSIONS) enum ExtensionState { EXTENSION_FORCED, @@ -531,8 +545,8 @@ return permissions_creators_.size(); } -void SupervisedUserService::AddAccessRequestInternal( - const GURL& url, +void SupervisedUserService::AddPermissionRequestInternal( + const CreatePermissionRequestCallback& create_request, const SuccessCallback& callback, size_t index) { // Find a permission request creator that is enabled. @@ -542,14 +556,15 @@ return; } - permissions_creators_[next_index]->CreatePermissionRequest( - url, + create_request.Run( + permissions_creators_[next_index], base::Bind(&SupervisedUserService::OnPermissionRequestIssued, - weak_ptr_factory_.GetWeakPtr(), url, callback, next_index)); + weak_ptr_factory_.GetWeakPtr(), create_request, + callback, next_index)); } void SupervisedUserService::OnPermissionRequestIssued( - const GURL& url, + const CreatePermissionRequestCallback& create_request, const SuccessCallback& callback, size_t index, bool success) { @@ -558,7 +573,7 @@ return; } - AddAccessRequestInternal(url, callback, index + 1); + AddPermissionRequestInternal(create_request, callback, index + 1); } void SupervisedUserService::OnSupervisedUserIdChanged() { @@ -631,10 +646,21 @@ return FindEnabledPermissionRequestCreator(0) < permissions_creators_.size(); } -void SupervisedUserService::AddAccessRequest(const GURL& url, - const SuccessCallback& callback) { - AddAccessRequestInternal(SupervisedUserURLFilter::Normalize(url), callback, - 0); +void SupervisedUserService::AddURLAccessRequest( + const GURL& url, + const SuccessCallback& callback) { + AddPermissionRequestInternal( + base::Bind(CreateURLAccessRequest, + SupervisedUserURLFilter::Normalize(url)), + callback, 0); +} + +void SupervisedUserService::AddExtensionUpdateRequest( + const std::string& extension_id, + const SuccessCallback& callback) { + AddPermissionRequestInternal( + base::Bind(CreateExtensionUpdateRequest, extension_id), + callback, 0); } void SupervisedUserService::InitSync(const std::string& refresh_token) {
diff --git a/chrome/browser/supervised_user/supervised_user_service.h b/chrome/browser/supervised_user/supervised_user_service.h index e4b77e1..67573528 100644 --- a/chrome/browser/supervised_user/supervised_user_service.h +++ b/chrome/browser/supervised_user/supervised_user_service.h
@@ -69,9 +69,9 @@ public chrome::BrowserListObserver, public SupervisedUserURLFilter::Observer { public: - typedef base::Callback<void(content::WebContents*)> NavigationBlockedCallback; - typedef base::Callback<void(const GoogleServiceAuthError&)> AuthErrorCallback; - typedef base::Callback<void(bool)> SuccessCallback; + using NavigationBlockedCallback = base::Callback<void(content::WebContents*)>; + using AuthErrorCallback = base::Callback<void(const GoogleServiceAuthError&)>; + using SuccessCallback = base::Callback<void(bool)>; class Delegate { public: @@ -111,13 +111,16 @@ // Returns the whitelist service. SupervisedUserWhitelistService* GetWhitelistService(); - // Whether the user can request access to blocked URLs. + // Whether the user can request to get access to blocked URLs or to new + // extensions. bool AccessRequestsEnabled(); - // Adds an access request for the given URL. The requests are stored using - // a prefix followed by a URIEncoded version of the URL. Each entry contains - // a dictionary which currently has the timestamp of the request in it. - void AddAccessRequest(const GURL& url, const SuccessCallback& callback); + // Adds an access request for the given URL. + void AddURLAccessRequest(const GURL& url, const SuccessCallback& callback); + + // Adds an update request for the given WebStore item (App/Extension). + void AddExtensionUpdateRequest(const std::string& extension_id, + const SuccessCallback& callback); // Returns the email address of the custodian. std::string GetCustodianEmailAddress() const; @@ -186,6 +189,9 @@ FRIEND_TEST_ALL_PREFIXES(SupervisedUserServiceExtensionTest, ExtensionManagementPolicyProvider); + using CreatePermissionRequestCallback = + base::Callback<void(PermissionRequestCreator*, const SuccessCallback&)>; + // A bridge from the UI thread to the SupervisedUserURLFilters, one of which // lives on the IO thread. This class mediates access to them and makes sure // they are kept in sync. @@ -266,13 +272,15 @@ SupervisedUserSettingsService* GetSettingsService(); size_t FindEnabledPermissionRequestCreator(size_t start); - void AddAccessRequestInternal(const GURL& url, - const SuccessCallback& callback, - size_t index); - void OnPermissionRequestIssued(const GURL& url, - const SuccessCallback& callback, - size_t index, - bool success); + void AddPermissionRequestInternal( + const CreatePermissionRequestCallback& create_request, + const SuccessCallback& callback, + size_t index); + void OnPermissionRequestIssued( + const CreatePermissionRequestCallback& create_request, + const SuccessCallback& callback, + size_t index, + bool success); void OnSupervisedUserIdChanged();
diff --git a/chrome/browser/supervised_user/supervised_user_service_unittest.cc b/chrome/browser/supervised_user/supervised_user_service_unittest.cc index 5e604a75..fa416420 100644 --- a/chrome/browser/supervised_user/supervised_user_service_unittest.cc +++ b/chrome/browser/supervised_user/supervised_user_service_unittest.cc
@@ -190,8 +190,8 @@ ~SupervisedUserServiceTest() override {} protected: - void AddAccessRequest(const GURL& url, AsyncResultHolder* result_holder) { - supervised_user_service_->AddAccessRequest( + void AddURLAccessRequest(const GURL& url, AsyncResultHolder* result_holder) { + supervised_user_service_->AddURLAccessRequest( url, base::Bind(&AsyncResultHolder::SetResult, base::Unretained(result_holder))); } @@ -249,13 +249,18 @@ // PermissionRequestCreator: bool IsEnabled() const override { return enabled_; } - void CreatePermissionRequest(const GURL& url_requested, - const SuccessCallback& callback) override { + void CreateURLAccessRequest(const GURL& url_requested, + const SuccessCallback& callback) override { ASSERT_TRUE(enabled_); requested_urls_.push_back(url_requested); callbacks_.push_back(callback); } + void CreateExtensionUpdateRequest(const std::string& extension_id, + const SuccessCallback& callback) override { + FAIL(); + } + bool enabled_; std::vector<GURL> requested_urls_; std::vector<SuccessCallback> callbacks_; @@ -269,11 +274,11 @@ GURL url("http://www.example.com"); // Without any permission request creators, it should be disabled, and any - // AddAccessRequest() calls should fail. + // AddURLAccessRequest() calls should fail. EXPECT_FALSE(supervised_user_service_->AccessRequestsEnabled()); { AsyncResultHolder result_holder; - AddAccessRequest(url, &result_holder); + AddURLAccessRequest(url, &result_holder); EXPECT_FALSE(result_holder.GetResult()); } @@ -285,7 +290,7 @@ EXPECT_FALSE(supervised_user_service_->AccessRequestsEnabled()); { AsyncResultHolder result_holder; - AddAccessRequest(url, &result_holder); + AddURLAccessRequest(url, &result_holder); EXPECT_FALSE(result_holder.GetResult()); } @@ -295,7 +300,7 @@ EXPECT_TRUE(supervised_user_service_->AccessRequestsEnabled()); { AsyncResultHolder result_holder; - AddAccessRequest(url, &result_holder); + AddURLAccessRequest(url, &result_holder); ASSERT_EQ(1u, creator->requested_urls().size()); EXPECT_EQ(url.spec(), creator->requested_urls()[0].spec()); @@ -305,7 +310,7 @@ { AsyncResultHolder result_holder; - AddAccessRequest(url, &result_holder); + AddURLAccessRequest(url, &result_holder); ASSERT_EQ(1u, creator->requested_urls().size()); EXPECT_EQ(url.spec(), creator->requested_urls()[0].spec()); @@ -321,7 +326,7 @@ { AsyncResultHolder result_holder; - AddAccessRequest(url, &result_holder); + AddURLAccessRequest(url, &result_holder); ASSERT_EQ(1u, creator->requested_urls().size()); EXPECT_EQ(url.spec(), creator->requested_urls()[0].spec()); @@ -332,7 +337,7 @@ { AsyncResultHolder result_holder; - AddAccessRequest(url, &result_holder); + AddURLAccessRequest(url, &result_holder); ASSERT_EQ(1u, creator->requested_urls().size()); EXPECT_EQ(url.spec(), creator->requested_urls()[0].spec());
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service.cc b/chrome/browser/supervised_user/supervised_user_settings_service.cc index 69c0acf..55ff2f4 100644 --- a/chrome/browser/supervised_user/supervised_user_settings_service.cc +++ b/chrome/browser/supervised_user/supervised_user_settings_service.cc
@@ -50,10 +50,7 @@ } // namespace SupervisedUserSettingsService::SupervisedUserSettingsService() - : active_(false), - initialization_failed_(false), - local_settings_(new base::DictionaryValue) { -} + : active_(false), local_settings_(new base::DictionaryValue) {} SupervisedUserSettingsService::~SupervisedUserSettingsService() {} @@ -100,9 +97,7 @@ } bool SupervisedUserSettingsService::IsReady() { - // Initialization cannot be complete but have failed at the same time. - DCHECK(!(store_->IsInitializationComplete() && initialization_failed_)); - return initialization_failed_ || store_->IsInitializationComplete(); + return store_->IsInitializationComplete(); } void SupervisedUserSettingsService::Clear() { @@ -304,16 +299,9 @@ } void SupervisedUserSettingsService::OnInitializationCompleted(bool success) { - if (!success) { - // If this happens, it means the profile directory was not found. There is - // not much we can do, but the whole profile will probably be useless - // anyway. Just mark initialization as failed and continue otherwise, - // because subscribers might still expect to be called back. - initialization_failed_ = true; - } - // TODO(bauerb): Temporary CHECK while investigating https://crbug.com/425785. // Remove (or change back to DCHECK) once the bug is fixed. + CHECK(success); CHECK(IsReady()); InformSubscribers(); } @@ -366,7 +354,7 @@ scoped_ptr<base::DictionaryValue> SupervisedUserSettingsService::GetSettings() { DCHECK(IsReady()); - if (!active_ || initialization_failed_) + if (!active_) return scoped_ptr<base::DictionaryValue>(); scoped_ptr<base::DictionaryValue> settings(local_settings_->DeepCopy());
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service.h b/chrome/browser/supervised_user/supervised_user_settings_service.h index 7a7041ef3..29bd306 100644 --- a/chrome/browser/supervised_user/supervised_user_settings_service.h +++ b/chrome/browser/supervised_user/supervised_user_settings_service.h
@@ -152,8 +152,6 @@ bool active_; - bool initialization_failed_; - // A set of local settings that are fixed and not configured remotely. scoped_ptr<base::DictionaryValue> local_settings_;
diff --git a/chrome/browser/supervised_user/supervised_user_site_list.cc b/chrome/browser/supervised_user/supervised_user_site_list.cc index b74af9f..90c31e18 100644 --- a/chrome/browser/supervised_user/supervised_user_site_list.cc +++ b/chrome/browser/supervised_user/supervised_user_site_list.cc
@@ -140,9 +140,9 @@ const SupervisedUserSiteList::LoadedCallback& callback, const std::string& json) { if (g_load_in_process) { - JSONFileValueSerializer serializer(path); + JSONFileValueDeserializer deserializer(path); std::string error; - scoped_ptr<base::Value> value(serializer.Deserialize(nullptr, &error)); + scoped_ptr<base::Value> value(deserializer.Deserialize(nullptr, &error)); if (!value) { HandleError(path, error); return;
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc index 6b7ff7d5..67af484a 100644 --- a/chrome/browser/themes/browser_theme_pack_unittest.cc +++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -154,10 +154,10 @@ base::FilePath manifest_path = extension_path.AppendASCII("manifest.json"); std::string error; - JSONFileValueSerializer serializer(manifest_path); + JSONFileValueDeserializer deserializer(manifest_path); scoped_ptr<base::DictionaryValue> valid_value( static_cast<base::DictionaryValue*>( - serializer.Deserialize(NULL, &error))); + deserializer.Deserialize(NULL, &error))); EXPECT_EQ("", error); ASSERT_TRUE(valid_value.get()); scoped_refptr<Extension> extension(
diff --git a/chrome/browser/thumbnails/thumbnail_service_impl.cc b/chrome/browser/thumbnails/thumbnail_service_impl.cc index ccd59c1..29ff5ec 100644 --- a/chrome/browser/thumbnails/thumbnail_service_impl.cc +++ b/chrome/browser/thumbnails/thumbnail_service_impl.cc
@@ -7,7 +7,7 @@ #include "base/command_line.h" #include "base/memory/ref_counted_memory.h" #include "base/time/time.h" -#include "chrome/browser/history/history_service.h" +#include "chrome/browser/history/history_utils.h" #include "chrome/browser/history/top_sites_factory.h" #include "chrome/browser/thumbnails/content_based_thumbnailing_algorithm.h" #include "chrome/browser/thumbnails/simple_thumbnail_crop.h" @@ -99,7 +99,7 @@ return false; // Skip if the given URL is not appropriate for history. - if (!HistoryService::CanAddURL(url)) + if (!CanAddURLToHistory(url)) return false; // Skip if the top sites list is full, and the URL is not known. if (local_ptr->IsNonForcedFull() && !local_ptr->IsKnownURL(url))
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 237b239bb..47f3039 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -47,6 +47,7 @@ "//components/app_modal", "//components/auto_login_parser", "//components/dom_distiller/webui", + "//components/feedback/proto", "//components/history/core/browser:proto", "//components/invalidation", "//components/onc", @@ -134,7 +135,6 @@ "//chrome") deps += [ "//components/copresence", - "//components/feedback/proto", "//device/bluetooth", "//third_party/libusb", ] @@ -228,15 +228,31 @@ } if (is_mac) { if (mac_views_browser) { + sources += rebase_path( + gypi_values.chrome_browser_ui_views_mac_experimental_sources, + ".", + "//chrome") sources -= [ + "cocoa/apps/chrome_app_window_client_cocoa.mm", "cocoa/bookmarks/bookmark_drag_drop_cocoa.mm", "cocoa/browser_window_factory_cocoa.mm", "cocoa/tab_dialogs_cocoa.mm", ] + deps += [ "//extensions/components/native_app_window" ] } else { sources -= [ + "views/apps/chrome_native_app_window_views.cc", + "views/apps/chrome_native_app_window_views.h", + "views/apps/desktop_keyboard_capture.cc", + "views/apps/desktop_keyboard_capture.h", + "views/apps/keyboard_hook_handler.cc", + "views/apps/keyboard_hook_handler.h", "views/bookmarks/bookmark_drag_drop_views.cc", + "views/extensions/extension_keybinding_registry_views.cc", + "views/extensions/extension_keybinding_registry_views.h", "views/frame/browser_window_factory.cc", + "views/frame/taskbar_decorator.cc", + "views/frame/taskbar_decorator.h", "views/tab_dialogs_views.cc", ] } @@ -313,6 +329,7 @@ ] deps -= [ "//chrome/browser/ui/views", + "//components/feedback/proto", "//ui/events", ] sources += rebase_path(gypi_values.chrome_browser_ui_android_sources, @@ -345,7 +362,10 @@ if (is_win) { sources += rebase_path(gypi_values.chrome_browser_ui_win_sources, ".", "//chrome") - sources -= [ "views/frame/taskbar_decorator.cc" ] + sources -= [ + "views/apps/keyboard_hook_handler.cc", + "views/frame/taskbar_decorator.cc", + ] public_deps += [ "//ui/views", "//ui/views/controls/webview",
diff --git a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc index efaa710..b368ea8 100644 --- a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc +++ b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc
@@ -88,9 +88,16 @@ Java_CardUnmaskBridge_disableAndWaitForVerification(env, java_object_.obj()); } -void CardUnmaskPromptViewAndroid::GotVerificationResult(bool success) { +void CardUnmaskPromptViewAndroid::GotVerificationResult( + const base::string16& error_message, + bool allow_retry) { JNIEnv* env = base::android::AttachCurrentThread(); - Java_CardUnmaskBridge_verificationFinished(env, java_object_.obj(), success); + ScopedJavaLocalRef<jstring> message; + if (!error_message.empty()) + message = base::android::ConvertUTF16ToJavaString(env, error_message); + + Java_CardUnmaskBridge_verificationFinished(env, java_object_.obj(), + message.obj(), allow_retry); } // static
diff --git a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h index 21281f8..66d3e2d 100644 --- a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h +++ b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h
@@ -32,7 +32,8 @@ // CardUnmaskPromptView implementation. void ControllerGone() override; void DisableAndWaitForVerification() override; - void GotVerificationResult(bool success) override; + void GotVerificationResult(const base::string16& error_message, + bool allow_retry) override; static bool Register(JNIEnv* env);
diff --git a/chrome/browser/ui/android/infobars/download_overwrite_infobar.cc b/chrome/browser/ui/android/infobars/download_overwrite_infobar.cc new file mode 100644 index 0000000..a5da969 --- /dev/null +++ b/chrome/browser/ui/android/infobars/download_overwrite_infobar.cc
@@ -0,0 +1,72 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/android/infobars/download_overwrite_infobar.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "base/android/jni_weak_ref.h" +#include "base/files/file_path.h" +#include "chrome/browser/android/download/download_overwrite_infobar_delegate.h" +#include "jni/DownloadOverwriteInfoBar_jni.h" + +using chrome::android::DownloadOverwriteInfoBarDelegate; + +// static +scoped_ptr<infobars::InfoBar> DownloadOverwriteInfoBar::CreateInfoBar( + scoped_ptr<DownloadOverwriteInfoBarDelegate> delegate) { + return make_scoped_ptr(new DownloadOverwriteInfoBar(delegate.Pass())); +} + +DownloadOverwriteInfoBar::~DownloadOverwriteInfoBar() { +} + +DownloadOverwriteInfoBar::DownloadOverwriteInfoBar( + scoped_ptr<DownloadOverwriteInfoBarDelegate> delegate) + : InfoBarAndroid(delegate.Pass()) { +} + +base::android::ScopedJavaLocalRef<jobject> +DownloadOverwriteInfoBar::CreateRenderInfoBar(JNIEnv* env) { + DownloadOverwriteInfoBarDelegate* delegate = GetDelegate(); + + ScopedJavaLocalRef<jstring> j_file_name = + base::android::ConvertUTF8ToJavaString(env, delegate->GetFileName()); + ScopedJavaLocalRef<jstring> j_dir_name = + base::android::ConvertUTF8ToJavaString(env, delegate->GetDirName()); + ScopedJavaLocalRef<jstring> j_dir_full_path = + base::android::ConvertUTF8ToJavaString(env, delegate->GetDirFullPath()); + base::android::ScopedJavaLocalRef<jobject> java_infobar( + Java_DownloadOverwriteInfoBar_createInfoBar( + env, reinterpret_cast<intptr_t>(this), j_file_name.obj(), + j_dir_name.obj(), j_dir_full_path.obj())); + return java_infobar; +} + +void DownloadOverwriteInfoBar::ProcessButton(int action, + const std::string& action_value) { + if (!owner()) + return; // We're closing; don't call anything, it might access the owner. + + DownloadOverwriteInfoBarDelegate* delegate = GetDelegate(); + if (action == InfoBarAndroid::ACTION_OVERWRITE) + delegate->OverwriteExistingFile(); + else if (action == InfoBarAndroid::ACTION_CREATE_NEW_FILE) + delegate->CreateNewFile(); + else + DCHECK(false); + + RemoveSelf(); +} + +DownloadOverwriteInfoBarDelegate* DownloadOverwriteInfoBar::GetDelegate() { + return static_cast<DownloadOverwriteInfoBarDelegate*>(delegate()); +} + +// Native JNI methods --------------------------------------------------------- + +bool RegisterDownloadOverwriteInfoBarDelegate(JNIEnv* env) { + return RegisterNativesImpl(env); +}
diff --git a/chrome/browser/ui/android/infobars/download_overwrite_infobar.h b/chrome/browser/ui/android/infobars/download_overwrite_infobar.h new file mode 100644 index 0000000..67a949b --- /dev/null +++ b/chrome/browser/ui/android/infobars/download_overwrite_infobar.h
@@ -0,0 +1,43 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_ANDROID_INFOBARS_DOWNLOAD_OVERWRITE_INFOBAR_H_ +#define CHROME_BROWSER_UI_ANDROID_INFOBARS_DOWNLOAD_OVERWRITE_INFOBAR_H_ + +#include "base/android/scoped_java_ref.h" +#include "base/basictypes.h" +#include "chrome/browser/ui/android/infobars/infobar_android.h" + +namespace chrome { +namespace android { +class DownloadOverwriteInfoBarDelegate; +} +} + +// A native-side implementation of an infobar to ask whether to overwrite +// an existing file with a new download. +class DownloadOverwriteInfoBar : public InfoBarAndroid { + public: + static scoped_ptr<infobars::InfoBar> CreateInfoBar( + scoped_ptr<chrome::android::DownloadOverwriteInfoBarDelegate> delegate); + ~DownloadOverwriteInfoBar() override; + + private: + explicit DownloadOverwriteInfoBar( + scoped_ptr<chrome::android::DownloadOverwriteInfoBarDelegate> delegate); + + // InfoBarAndroid: + base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar( + JNIEnv* env) override; + void ProcessButton(int action, const std::string& action_value) override; + + chrome::android::DownloadOverwriteInfoBarDelegate* GetDelegate(); + + DISALLOW_COPY_AND_ASSIGN(DownloadOverwriteInfoBar); +}; + +// Registers the native methods through JNI. +bool RegisterDownloadOverwriteInfoBarDelegate(JNIEnv* env); + +#endif // CHROME_BROWSER_UI_ANDROID_INFOBARS_DOWNLOAD_OVERWRITE_INFOBAR_H_
diff --git a/chrome/browser/ui/android/infobars/infobar_android.h b/chrome/browser/ui/android/infobars/infobar_android.h index 39bd0e44..8070753 100644 --- a/chrome/browser/ui/android/infobars/infobar_android.h +++ b/chrome/browser/ui/android/infobars/infobar_android.h
@@ -32,6 +32,9 @@ // Translate infobar ACTION_TRANSLATE = 3, ACTION_TRANSLATE_SHOW_ORIGINAL = 4, + // Download overwrite infobar + ACTION_OVERWRITE = 5, + ACTION_CREATE_NEW_FILE = 6, }; explicit InfoBarAndroid(scoped_ptr<infobars::InfoBarDelegate> delegate);
diff --git a/chrome/browser/ui/app_list/app_list_controller_browsertest.cc b/chrome/browser/ui/app_list/app_list_controller_browsertest.cc index e47d90b..9c0b729 100644 --- a/chrome/browser/ui/app_list/app_list_controller_browsertest.cc +++ b/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
@@ -15,7 +15,9 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" #include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/testing_profile.h" #include "ui/app_list/app_list_model.h" #include "ui/app_list/app_list_switches.h" #include "ui/app_list/search_box_model.h" @@ -23,6 +25,11 @@ #include "ui/app_list/search_result_observer.h" #include "ui/base/models/list_model_observer.h" +#if defined(OS_CHROMEOS) +#include "chromeos/chromeos_switches.h" +#include "chromeos/login/user_names.h" +#endif // defined(OS_CHROMEOS) + // Browser Test for AppListController that runs on all platforms supporting // app_list. typedef InProcessBrowserTest AppListControllerBrowserTest; @@ -170,12 +177,6 @@ // Test showing search results, and uninstalling one of them while displayed. IN_PROC_BROWSER_TEST_F(AppListControllerSearchResultsBrowserTest, MAYBE_UninstallSearchResult) { - // TODO(calamity): This test fails in the experimental app list - // (http://crbug.com/438119). For now, force the test to run in the classic - // app list. - base::CommandLine::ForCurrentProcess()->AppendSwitch( - app_list::switches::kDisableExperimentalAppList); - base::FilePath test_extension_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_extension_path)); test_extension_path = test_extension_path.AppendASCII("extensions") @@ -212,3 +213,37 @@ StopWatchingResults(); service->DismissAppList(); } + +#if defined(OS_CHROMEOS) + +class AppListControllerGuestModeBrowserTest : public InProcessBrowserTest { + public: + AppListControllerGuestModeBrowserTest() {} + + protected: + void SetUpCommandLine(base::CommandLine* command_line) override; + + private: + DISALLOW_COPY_AND_ASSIGN(AppListControllerGuestModeBrowserTest); +}; + +void AppListControllerGuestModeBrowserTest::SetUpCommandLine( + base::CommandLine* command_line) { + command_line->AppendSwitch(chromeos::switches::kGuestSession); + command_line->AppendSwitchASCII(chromeos::switches::kLoginUser, + chromeos::login::kGuestUserName); + command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, + TestingProfile::kTestUserProfileDir); + command_line->AppendSwitch(switches::kIncognito); +} + +// Test creating the initial app list in guest mode. +IN_PROC_BROWSER_TEST_F(AppListControllerGuestModeBrowserTest, Incognito) { + AppListService* service = test::GetAppListService(); + EXPECT_TRUE(service->GetCurrentAppListProfile()); + + service->ShowForProfile(browser()->profile()); + EXPECT_EQ(browser()->profile(), service->GetCurrentAppListProfile()); +} + +#endif // defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate_views.cc b/chrome/browser/ui/app_list/app_list_controller_delegate_views.cc index 03ec889..6b38b8c 100644 --- a/chrome/browser/ui/app_list/app_list_controller_delegate_views.cc +++ b/chrome/browser/ui/app_list/app_list_controller_delegate_views.cc
@@ -36,8 +36,12 @@ } void AppListControllerDelegateViews::OnCloseChildDialog() { - DCHECK(service_->shower().app_list()); - service_->shower().app_list()->SetAppListOverlayVisible(false); + // If the app list is closed while a child dialog is open (for example, + // through an OS-level close command), then the app list view will already + // have been cleared from the shower by + // AppListShower::HandleViewBeingDestroyed(). + if (service_->shower().app_list()) + service_->shower().app_list()->SetAppListOverlayVisible(false); service_->set_can_dismiss(true); }
diff --git a/chrome/browser/ui/app_list/app_list_service_impl.cc b/chrome/browser/ui/app_list/app_list_service_impl.cc index 696eba71..3808fee6 100644 --- a/chrome/browser/ui/app_list/app_list_service_impl.cc +++ b/chrome/browser/ui/app_list/app_list_service_impl.cc
@@ -261,7 +261,7 @@ AppListViewDelegate* AppListServiceImpl::GetViewDelegate(Profile* profile) { if (!view_delegate_) view_delegate_.reset(new AppListViewDelegate(GetControllerDelegate())); - view_delegate_->SetProfile(profile->GetOriginalProfile()); + view_delegate_->SetProfile(profile); return view_delegate_.get(); }
diff --git a/chrome/browser/ui/app_list/app_list_service_views_browsertest.cc b/chrome/browser/ui/app_list/app_list_service_views_browsertest.cc index b9ad2cb5..0f76fab 100644 --- a/chrome/browser/ui/app_list/app_list_service_views_browsertest.cc +++ b/chrome/browser/ui/app_list/app_list_service_views_browsertest.cc
@@ -122,49 +122,66 @@ EXPECT_FALSE(service->GetAppListWindow()); } -// Browser Test for AppListController that ensures the App Info dialog opens -// correctly. -using AppListControllerAppInfoDialogBrowserTest = ExtensionBrowserTest; +// Tests for opening the app info dialog from the app list. +class AppListControllerAppInfoDialogBrowserTest : public ExtensionBrowserTest { + public: + AppListControllerAppInfoDialogBrowserTest() {} + ~AppListControllerAppInfoDialogBrowserTest() override {} + + protected: + // content::BrowserTestBase: + void SetUpOnMainThread() override { + // Install a test extension. + base::FilePath test_extension_path; + EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_extension_path)); + test_extension_path = test_extension_path.AppendASCII("extensions") + .AppendASCII("platform_apps") + .AppendASCII("minimal"); + extension_ = InstallExtension( + test_extension_path, 1 /* expected_change: new install */); + EXPECT_TRUE(extension_); + + // Open the app list. + service_ = test::GetAppListService(); + EXPECT_FALSE(service_->GetAppListWindow()); + service_->ShowForProfile(browser()->profile()); + app_list_view_ = GetAppListView(service_); + EXPECT_TRUE(app_list_view_); + native_view_ = app_list_view_->GetWidget()->GetNativeView(); + EXPECT_TRUE(native_view_); + } + + void OpenAppInfoDialog() { + AppListControllerDelegate* controller = service_->GetControllerDelegate(); + EXPECT_TRUE(controller); + EXPECT_TRUE(controller->GetAppListWindow()); + controller->DoShowAppInfoFlow(browser()->profile(), extension_->id()); + } + + AppListService* service_; + const extensions::Extension* extension_; + app_list::AppListView* app_list_view_; + gfx::NativeView native_view_; + + private: + DISALLOW_COPY_AND_ASSIGN(AppListControllerAppInfoDialogBrowserTest); +}; // Test the DoShowAppInfoFlow function of the controller delegate. // flaky: http://crbug.com/378251 IN_PROC_BROWSER_TEST_F(AppListControllerAppInfoDialogBrowserTest, DISABLED_DoShowAppInfoFlow) { - // Install an extension to open the dialog for. - base::FilePath test_extension_path; - ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_extension_path)); - test_extension_path = test_extension_path.AppendASCII("extensions") - .AppendASCII("platform_apps") - .AppendASCII("minimal"); - const extensions::Extension* extension = InstallExtension( - test_extension_path, 1 /* expected_change: new install */); - ASSERT_TRUE(extension); + test::AppListViewTestApi test_api(app_list_view_); - // Open the app list window. - AppListService* service = test::GetAppListService(); - EXPECT_FALSE(service->GetAppListWindow()); - - service->ShowForProfile(browser()->profile()); - app_list::AppListView* app_list_view = GetAppListView(service); - ASSERT_TRUE(app_list_view); - gfx::NativeView native_view = app_list_view->GetWidget()->GetNativeView(); - ASSERT_TRUE(native_view); - - test::AppListViewTestApi test_api(app_list_view); - - // Open the app info dialog. views::Widget::Widgets owned_widgets; - views::Widget::GetAllOwnedWidgets(native_view, &owned_widgets); + views::Widget::GetAllOwnedWidgets(native_view_, &owned_widgets); EXPECT_EQ(0U, owned_widgets.size()); EXPECT_FALSE(test_api.is_overlay_visible()); - AppListControllerDelegate* controller = service->GetControllerDelegate(); - ASSERT_TRUE(controller); - EXPECT_TRUE(controller->GetAppListWindow()); - controller->DoShowAppInfoFlow(browser()->profile(), extension->id()); + OpenAppInfoDialog(); owned_widgets.clear(); - views::Widget::GetAllOwnedWidgets(native_view, &owned_widgets); + views::Widget::GetAllOwnedWidgets(native_view_, &owned_widgets); EXPECT_EQ(1U, owned_widgets.size()); EXPECT_TRUE(test_api.is_overlay_visible()); @@ -173,11 +190,22 @@ app_info_dialog->CloseNow(); owned_widgets.clear(); - views::Widget::GetAllOwnedWidgets(native_view, &owned_widgets); + views::Widget::GetAllOwnedWidgets(native_view_, &owned_widgets); EXPECT_EQ(0U, owned_widgets.size()); EXPECT_FALSE(test_api.is_overlay_visible()); } +// Check that the app list can be closed with the app info dialog +// open without crashing. This is a regression test for http://crbug.com/443066. +IN_PROC_BROWSER_TEST_F(AppListControllerAppInfoDialogBrowserTest, + CanCloseAppListWithAppInfoOpen) { + OpenAppInfoDialog(); + + // Close the app list window. + app_list_view_->GetWidget()->CloseNow(); + EXPECT_FALSE(GetAppListView(service_)); +} + using AppListServiceViewsExtensionBrowserTest = ExtensionBrowserTest; IN_PROC_BROWSER_TEST_F(AppListServiceViewsExtensionBrowserTest,
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 1f268624..c57ba46 100644 --- a/chrome/browser/ui/app_list/app_list_view_delegate.cc +++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -285,6 +285,13 @@ return; } + // If we are in guest mode, the new profile should be an incognito profile. + // Otherwise, this may later hit a check (same condition as this one) in + // Browser::Browser when opening links in a browser window (see + // http://crbug.com/460437). + DCHECK(!profile_->IsGuestSession() || profile_->IsOffTheRecord()) + << "Guest mode must use incognito profile"; + // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. tracked_objects::ScopedTracker tracking_profile3( FROM_HERE_WITH_EXPLICIT_FUNCTION(
diff --git a/chrome/browser/ui/app_list/start_page_service.cc b/chrome/browser/ui/app_list/start_page_service.cc index 833fb971..8af8b47 100644 --- a/chrome/browser/ui/app_list/start_page_service.cc +++ b/chrome/browser/ui/app_list/start_page_service.cc
@@ -86,6 +86,15 @@ public: explicit ProfileDestroyObserver(StartPageService* service) : service_(service) { + if (service_->profile()->IsOffTheRecord()) { + // We need to be notified when the original profile gets destroyed as well + // as the OTR profile, because the original profile will be destroyed + // first, and a DCHECK at that time ensures that the OTR profile has 0 + // hosts. See http://crbug.com/463419. + registrar_.Add( + this, chrome::NOTIFICATION_PROFILE_DESTROYED, + content::Source<Profile>(service_->profile()->GetOriginalProfile())); + } registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, content::Source<Profile>(service_->profile())); @@ -98,7 +107,9 @@ const content::NotificationSource& source, const content::NotificationDetails& details) override { DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); - DCHECK_EQ(service_->profile(), content::Source<Profile>(source).ptr()); + DCHECK(service_->profile()->IsSameProfile( + content::Source<Profile>(source).ptr())); + registrar_.RemoveAll(); service_->Shutdown(); } @@ -650,7 +661,7 @@ if (json_start_index != std::string::npos) json_data_substr.remove_prefix(json_start_index); - JSONStringValueSerializer deserializer(json_data_substr); + JSONStringValueDeserializer deserializer(json_data_substr); deserializer.set_allow_trailing_comma(true); int error_code = 0; scoped_ptr<base::Value> doodle_json(
diff --git a/chrome/browser/ui/app_list/start_page_service.h b/chrome/browser/ui/app_list/start_page_service.h index df8a2d9..56e506c 100644 --- a/chrome/browser/ui/app_list/start_page_service.h +++ b/chrome/browser/ui/app_list/start_page_service.h
@@ -55,7 +55,7 @@ public: typedef std::vector<scoped_refptr<const extensions::Extension> > ExtensionList; - // Gets the instance for the given profile. + // Gets the instance for the given profile. May return nullptr. static StartPageService* Get(Profile* profile); void AddObserver(StartPageObserver* observer);
diff --git a/chrome/browser/ui/app_list/start_page_service_factory.cc b/chrome/browser/ui/app_list/start_page_service_factory.cc index 6e5c30b..093711b 100644 --- a/chrome/browser/ui/app_list/start_page_service_factory.cc +++ b/chrome/browser/ui/app_list/start_page_service_factory.cc
@@ -55,7 +55,7 @@ content::BrowserContext* StartPageServiceFactory::GetBrowserContextToUse( content::BrowserContext* context) const { // The start page service needs an instance in ChromeOS guest mode. - return chrome::GetBrowserContextRedirectedInIncognito(context); + return chrome::GetBrowserContextOwnInstanceInIncognito(context); } } // namespace app_list
diff --git a/chrome/browser/ui/app_list/start_page_service_factory.h b/chrome/browser/ui/app_list/start_page_service_factory.h index 1bd8031e..e023ca8 100644 --- a/chrome/browser/ui/app_list/start_page_service_factory.h +++ b/chrome/browser/ui/app_list/start_page_service_factory.h
@@ -16,7 +16,8 @@ // Singleton factory to create StartPageService. class StartPageServiceFactory : public BrowserContextKeyedServiceFactory { public: - // Gets or creates the instance of StartPageService for |profile|. + // Gets or creates the instance of StartPageService for |profile|. May return + // nullptr. static StartPageService* GetForProfile(Profile* profile); // Gets the singleton instance of this factory.
diff --git a/chrome/browser/ui/ash/app_list/app_list_service_ash.cc b/chrome/browser/ui/ash/app_list/app_list_service_ash.cc index 38da2f7c..6d0fd0a 100644 --- a/chrome/browser/ui/ash/app_list/app_list_service_ash.cc +++ b/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
@@ -56,7 +56,10 @@ void AppListServiceAsh::Init(Profile* initial_profile) { // Ensure the StartPageService is created here. This early initialization is // necessary to allow the WebContents to load before the app list is shown. - app_list::StartPageService::Get(initial_profile)->Init(); + app_list::StartPageService* service = + app_list::StartPageService::Get(initial_profile); + if (service) + service->Init(); } base::FilePath AppListServiceAsh::GetProfilePath(
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc index f07f122..ac0ae5f 100644 --- a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc
@@ -145,6 +145,11 @@ } void AppWindowLauncherController::RegisterApp(AppWindow* app_window) { + // Windows created by IME extension should be treated the same way as the + // virtual keyboard window, which does not register itself in launcher. + if (app_window->is_ime_window()) + return; + aura::Window* window = app_window->GetNativeWindow(); // Get the app's shelf identifier and add an entry to the map. DCHECK(window_to_app_shelf_id_map_.find(window) ==
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc index 28bed7c..7373454 100644 --- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc +++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
@@ -8,10 +8,12 @@ #include "ash/test/ash_test_base.h" #include "ash/test/test_session_state_delegate.h" #include "ash/test/test_shell_delegate.h" +#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h" #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile_manager.h" +#include "components/user_manager/fake_user_manager.h" #include "components/user_manager/user_info.h" #include "ui/message_center/message_center.h" #include "ui/message_center/notification.h" @@ -23,7 +25,9 @@ MultiUserNotificationBlockerChromeOSTest() : state_changed_count_(0), testing_profile_manager_(TestingBrowserProcess::GetGlobal()), - window_id_(0) {} + window_id_(0), + fake_user_manager_(new user_manager::FakeUserManager), + user_manager_enabler_(fake_user_manager_) {} ~MultiUserNotificationBlockerChromeOSTest() override {} // ash::test::AshTestBase overrides: @@ -128,6 +132,10 @@ TestingProfileManager testing_profile_manager_; int window_id_; + user_manager::FakeUserManager* fake_user_manager_; // Not owned. + + chromeos::ScopedUserManagerEnabler user_manager_enabler_; + DISALLOW_COPY_AND_ASSIGN(MultiUserNotificationBlockerChromeOSTest); };
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc index badf4a53..e6834781b 100644 --- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc +++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
@@ -18,10 +18,12 @@ #include "base/logging.h" #include "base/strings/string_util.h" #include "base/time/time.h" +#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h" #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h" #include "chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h" #include "chrome/test/base/testing_profile.h" +#include "components/user_manager/fake_user_manager.h" #include "components/user_manager/user_info.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window_event_dispatcher.h" @@ -39,7 +41,9 @@ public: MultiUserWindowManagerChromeOSTest() : multi_user_window_manager_(NULL), - session_state_delegate_(NULL) {} + session_state_delegate_(NULL), + fake_user_manager_(new user_manager::FakeUserManager), + user_manager_enabler_(fake_user_manager_) {} void SetUp() override; void TearDown() override; @@ -158,6 +162,10 @@ // The session state delegate. ash::test::TestSessionStateDelegate* session_state_delegate_; + user_manager::FakeUserManager* fake_user_manager_; // Not owned. + + chromeos::ScopedUserManagerEnabler user_manager_enabler_; + // The maximized window manager (if enabled). scoped_ptr<MaximizeModeWindowManager> maximize_mode_window_manager_;
diff --git a/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc b/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc index 62b044a0..9b5335cc 100644 --- a/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc +++ b/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc
@@ -44,9 +44,39 @@ card_unmask_view_ = CardUnmaskPromptView::CreateAndShow(this); } -void CardUnmaskPromptControllerImpl::OnVerificationResult(bool success) { - if (card_unmask_view_) - card_unmask_view_->GotVerificationResult(success); +void CardUnmaskPromptControllerImpl::OnVerificationResult( + AutofillClient::GetRealPanResult result) { + if (!card_unmask_view_) + return; + + base::string16 error_message; + bool allow_retry = true; + switch (result) { + case AutofillClient::SUCCESS: + break; + + case AutofillClient::TRY_AGAIN_FAILURE: { + error_message = l10n_util::GetStringUTF16( + IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_TRY_AGAIN); + break; + } + + case AutofillClient::PERMANENT_FAILURE: { + error_message = l10n_util::GetStringUTF16( + IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_PERMANENT); + allow_retry = false; + break; + } + + case AutofillClient::NETWORK_ERROR: { + error_message = l10n_util::GetStringUTF16( + IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_NETWORK); + allow_retry = false; + break; + } + } + + card_unmask_view_->GotVerificationResult(error_message, allow_retry); } void CardUnmaskPromptControllerImpl::OnUnmaskDialogClosed() {
diff --git a/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.h b/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.h index e2d1b975..a991c7d73 100644 --- a/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.h +++ b/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.h
@@ -8,6 +8,7 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/ui/autofill/card_unmask_prompt_controller.h" +#include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/card_unmask_delegate.h" #include "components/autofill/core/browser/credit_card.h" @@ -24,7 +25,7 @@ void ShowPrompt(const CreditCard& card, base::WeakPtr<CardUnmaskDelegate> delegate); // The CVC the user entered went through validation. - void OnVerificationResult(bool success); + void OnVerificationResult(AutofillClient::GetRealPanResult result); // CardUnmaskPromptController implementation. void OnUnmaskDialogClosed() override;
diff --git a/chrome/browser/ui/autofill/card_unmask_prompt_view.h b/chrome/browser/ui/autofill/card_unmask_prompt_view.h index de3a2ff..6754856f 100644 --- a/chrome/browser/ui/autofill/card_unmask_prompt_view.h +++ b/chrome/browser/ui/autofill/card_unmask_prompt_view.h
@@ -19,7 +19,8 @@ virtual void ControllerGone() = 0; virtual void DisableAndWaitForVerification() = 0; - virtual void GotVerificationResult(bool success) = 0; + virtual void GotVerificationResult(const base::string16& error_message, + bool allow_retry) = 0; protected: CardUnmaskPromptView() {}
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index 37c8c48..23983d92 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -136,8 +136,8 @@ unmask_controller_.ShowPrompt(card, delegate); } -void ChromeAutofillClient::OnUnmaskVerificationResult(bool success) { - unmask_controller_.OnVerificationResult(success); +void ChromeAutofillClient::OnUnmaskVerificationResult(GetRealPanResult result) { + unmask_controller_.OnVerificationResult(result); } void ChromeAutofillClient::ConfirmSaveCreditCard(
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h index 3bc63aa4..1ce82b7 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.h +++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -51,7 +51,7 @@ void ShowAutofillSettings() override; void ShowUnmaskPrompt(const CreditCard& card, base::WeakPtr<CardUnmaskDelegate> delegate) override; - void OnUnmaskVerificationResult(bool success) override; + void OnUnmaskVerificationResult(GetRealPanResult result) override; void ConfirmSaveCreditCard(const base::Closure& save_card_callback) override; bool HasCreditCardScanFeature() override; void ScanCreditCard(const CreditCardScanCallback& callback) override;
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 53dfccd..28413b7 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -446,7 +446,8 @@ #endif // defined(OS_WIN) } - exclusive_access_manager_.reset(new ExclusiveAccessManager(this)); + exclusive_access_manager_.reset( + new ExclusiveAccessManager(window_->GetExclusiveAccessContext())); // Must be initialized after window_. // Also: surprise! a modal dialog host is not necessary to host modal dialogs @@ -1339,8 +1340,7 @@ return; // GetDownloadShelf creates the download shelf if it was not yet created. - DownloadShelf* shelf = window()->GetDownloadShelf(); - shelf->AddDownload(download); + window()->GetDownloadShelf()->AddDownload(download); } /////////////////////////////////////////////////////////////////////////////// @@ -1348,6 +1348,12 @@ WebContents* Browser::OpenURLFromTab(WebContents* source, const OpenURLParams& params) { + if (is_devtools()) { + DevToolsWindow* window = DevToolsWindow::AsDevToolsWindow(source); + DCHECK(window); + return window->OpenURLFromTab(source, params); + } + chrome::NavigateParams nav_params(this, params.url, params.transition); FillNavigateParamsFromOpenURLParams(&nav_params, params); nav_params.source_contents = source;
diff --git a/chrome/browser/ui/browser_command_controller_unittest.cc b/chrome/browser/ui/browser_command_controller_unittest.cc index 0242a0a7..a80c758 100644 --- a/chrome/browser/ui/browser_command_controller_unittest.cc +++ b/chrome/browser/ui/browser_command_controller_unittest.cc
@@ -14,6 +14,8 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_window_state.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/browser_with_test_window_test.h" @@ -267,11 +269,16 @@ } ////////////////////////////////////////////////////////////////////////////// +class BrowserCommandControllerFullscreenTest; // A test browser window that can toggle fullscreen state. -class FullscreenTestBrowserWindow : public TestBrowserWindow { +class FullscreenTestBrowserWindow : public TestBrowserWindow, + ExclusiveAccessContext { public: - FullscreenTestBrowserWindow() : fullscreen_(false) {} + FullscreenTestBrowserWindow( + BrowserCommandControllerFullscreenTest* test_browser) + : fullscreen_(false), test_browser_(test_browser) {} + ~FullscreenTestBrowserWindow() override {} // TestBrowserWindow overrides: @@ -284,8 +291,21 @@ } void ExitFullscreen() override { fullscreen_ = false; } + ExclusiveAccessContext* GetExclusiveAccessContext() override { return this; } + + // Exclusive access interface: + Profile* GetProfile() override; + content::WebContents* GetActiveWebContents() override; + void HideDownloadShelf() override {} + void UnhideDownloadShelf() override {} + void UpdateExclusiveAccessExitBubbleContent( + const GURL& url, + ExclusiveAccessBubbleType bubble_type) override {} + bool IsFullscreenWithToolbar() const override { return IsFullscreen(); } + private: bool fullscreen_; + BrowserCommandControllerFullscreenTest* test_browser_; DISALLOW_COPY_AND_ASSIGN(FullscreenTestBrowserWindow); }; @@ -297,15 +317,25 @@ BrowserCommandControllerFullscreenTest() {} ~BrowserCommandControllerFullscreenTest() override {} + Browser* GetBrowser() { return BrowserWithTestWindowTest::browser(); } + // BrowserWithTestWindowTest overrides: BrowserWindow* CreateBrowserWindow() override { - return new FullscreenTestBrowserWindow; + return new FullscreenTestBrowserWindow(this); } private: DISALLOW_COPY_AND_ASSIGN(BrowserCommandControllerFullscreenTest); }; +Profile* FullscreenTestBrowserWindow::GetProfile() { + return test_browser_->GetBrowser()->profile(); +} + +content::WebContents* FullscreenTestBrowserWindow::GetActiveWebContents() { + return test_browser_->GetBrowser()->tab_strip_model()->GetActiveWebContents(); +} + TEST_F(BrowserCommandControllerFullscreenTest, UpdateCommandsForFullscreenMode) { // Defaults for a tabbed browser.
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h index 7f416fc..ea17ad5 100644 --- a/chrome/browser/ui/browser_window.h +++ b/chrome/browser/ui/browser_window.h
@@ -22,6 +22,7 @@ class Browser; class DownloadShelf; +class ExclusiveAccessContext; class FindBar; class GlobalErrorBubbleViewBase; class GURL; @@ -131,7 +132,7 @@ ExclusiveAccessBubbleType bubble_type, bool with_toolbar) = 0; virtual void ExitFullscreen() = 0; - virtual void UpdateFullscreenExitBubbleContent( + virtual void UpdateExclusiveAccessExitBubbleContent( const GURL& url, ExclusiveAccessBubbleType bubble_type) = 0; @@ -395,6 +396,9 @@ virtual void ExecuteExtensionCommand(const extensions::Extension* extension, const extensions::Command& command) = 0; + // Returns object implementing ExclusiveAccessContext interface. + virtual ExclusiveAccessContext* GetExclusiveAccessContext() = 0; + protected: friend class BrowserCloseManager; friend class BrowserView;
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 ba88f8f..be99c16 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
@@ -2,11 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h" +// This file tests whichever implementation of NativeAppWindow is used. +// I.e. it could be NativeAppWindowCocoa or ChromeNativeAppWindowViewsMac. +#include "extensions/browser/app_window/native_app_window.h" #import <Cocoa/Cocoa.h> #include "base/mac/mac_util.h" +#include "base/mac/scoped_nsobject.h" #include "base/mac/sdk_forward_declarations.h" #include "chrome/browser/apps/app_browsertest_util.h" #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h index 02ff9cf..88d1e630 100644 --- a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h +++ b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h
@@ -27,7 +27,8 @@ // CardUnmaskPromptView implementation: void ControllerGone() override; void DisableAndWaitForVerification() override; - void GotVerificationResult(bool success) override; + void GotVerificationResult(const base::string16& error_message, + bool allow_retry) override; // ConstrainedWindowMacDelegate implementation: void OnConstrainedWindowClosed(ConstrainedWindowMac* window) override;
diff --git a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm index cc8897d4..5d30a79 100644 --- a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm +++ b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
@@ -49,7 +49,9 @@ void CardUnmaskPromptViewBridge::DisableAndWaitForVerification() { } -void CardUnmaskPromptViewBridge::GotVerificationResult(bool success) { +void CardUnmaskPromptViewBridge::GotVerificationResult( + const base::string16& error_message, + bool allow_retry) { } void CardUnmaskPromptViewBridge::OnConstrainedWindowClosed(
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h index 2d42c81..0fc13806 100644 --- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h +++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h
@@ -136,9 +136,6 @@ // incomplete animations do not cause valgrind complaints. BOOL ignoreAnimations_; - // The screen to which the menu should be restricted. - NSScreen* screen_; - int selectedIndex_; NSString* typedPrefix_;
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm index a0da0c0a..ca19977 100644 --- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm +++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm
@@ -129,13 +129,18 @@ - (void)_updateTrackingAreas; @end -@interface BookmarkBarFolderController(Private) +@interface BookmarkBarFolderController () - (void)configureWindow; - (void)addOrUpdateScrollTracking; - (void)removeScrollTracking; - (void)endScroll; - (void)addScrollTimerWithDelta:(CGFloat)delta; +// Return the screen to which the menu should be restricted. The screen list is +// very volatile and can change with very short notice so it isn't worth +// caching. http://crbug.com/463458 +- (NSScreen*)menuScreen; + // Helper function to configureWindow which performs a basic layout of // the window subviews, in particular the menu buttons and the window width. - (void)layOutWindowWithHeight:(CGFloat)height; @@ -261,33 +266,6 @@ // We want the button to remain bordered as part of the menu path. [button forceButtonBorderToStayOnAlways:YES]; - // Pick the parent button's screen to be the screen upon which all display - // happens. This loop over all screens is not equivalent to - // |[[button window] screen]|. BookmarkButtons are commonly positioned near - // the edge of their windows (both in the bookmark bar and in other bookmark - // menus), and |[[button window] screen]| would return the screen that the - // majority of their window was on even if the parent button were clearly - // contained within a different screen. - NSRect parentButtonGlobalFrame = - [button convertRect:[button bounds] toView:nil]; - parentButtonGlobalFrame.origin = - [[button window] convertBaseToScreen:parentButtonGlobalFrame.origin]; - for (NSScreen* screen in [NSScreen screens]) { - if (NSIntersectsRect([screen frame], parentButtonGlobalFrame)) { - screen_ = screen; - break; - } - } - if (!screen_) { - // The parent button is offscreen. The ideal thing to do would be to - // calculate the "closest" screen, the screen which has an edge parallel - // to, and the least distance from, one of the edges of the button. - // However, popping a subfolder from an offscreen button is an unrealistic - // edge case and so this ideal remains unrealized. Cheat instead; this - // code is wrong but a lot simpler. - screen_ = [[button window] screen]; - } - parentController_.reset([parentController retain]); if (!parentController_) [self setSubFolderGrowthToRight:YES]; @@ -468,6 +446,7 @@ // left but not in that order). Limit us to three tries in case // the folder window can't fit on either side of the screen; we // don't want to loop forever. + NSRect screenVisibleFrame = [[self menuScreen] visibleFrame]; CGFloat x; int tries = 0; while (tries < 2) { @@ -477,9 +456,8 @@ x = NSMaxX([[parentButton_ window] frame]) - bookmarks::kBookmarkMenuOverlap; // If off the screen, switch direction. - if ((x + windowWidth + - bookmarks::kBookmarkHorizontalScreenPadding) > - NSMaxX([screen_ visibleFrame])) { + if ((x + windowWidth + bookmarks::kBookmarkHorizontalScreenPadding) > + NSMaxX(screenVisibleFrame)) { [self setSubFolderGrowthToRight:NO]; } else { return x; @@ -492,7 +470,7 @@ bookmarks::kBookmarkMenuOverlap - windowWidth; // If off the screen, switch direction. - if (x < NSMinX([screen_ visibleFrame])) { + if (x < NSMinX(screenVisibleFrame)) { [self setSubFolderGrowthToRight:YES]; } else { return x; @@ -500,7 +478,7 @@ } } // Unhappy; do the best we can. - return NSMaxX([screen_ visibleFrame]) - windowWidth; + return NSMaxX(screenVisibleFrame) - windowWidth; } @@ -530,26 +508,27 @@ // Make sure the window is on-screen; if not, push left or right. It is // intentional that top level folders "push left" or "push right" slightly // different than subfolders. - NSRect screenFrame = [screen_ visibleFrame]; + NSRect screenVisibleFrame = [[self menuScreen] visibleFrame]; // Test if window goes off-screen on the right side. - CGFloat spillOff = (newWindowTopLeft.x + windowWidth) - NSMaxX(screenFrame); + CGFloat spillOff = + newWindowTopLeft.x + windowWidth - NSMaxX(screenVisibleFrame); if (spillOff > 0.0) { newWindowTopLeft.x = std::max(newWindowTopLeft.x - spillOff, - NSMinX(screenFrame)); - } else if (newWindowTopLeft.x < NSMinX(screenFrame)) { + NSMinX(screenVisibleFrame)); + } else if (newWindowTopLeft.x < NSMinX(screenVisibleFrame)) { // For left side. - newWindowTopLeft.x = NSMinX(screenFrame); + newWindowTopLeft.x = NSMinX(screenVisibleFrame); } // The menu looks bad when it is squeezed up against the bottom of the // screen and ends up being only a few pixels tall. If it meets the // threshold for this case, instead show the menu above the button. CGFloat availableVerticalSpace = newWindowTopLeft.y - - (NSMinY(screenFrame) + bookmarks::kScrollWindowVerticalMargin); + (NSMinY(screenVisibleFrame) + bookmarks::kScrollWindowVerticalMargin); if ((availableVerticalSpace < kMinSqueezedMenuHeight) && (windowHeight > availableVerticalSpace)) { newWindowTopLeft.y = std::min( newWindowTopLeft.y + windowHeight + NSHeight([parentButton_ frame]), - NSMaxY(screenFrame)); + NSMaxY(screenVisibleFrame)); } } else { // Parent is a folder: expose as much as we can vertically; grow right/left. @@ -615,9 +594,9 @@ metrics.deltaScrollerHeight = 0.0; metrics.deltaScrollerY = 0.0; - metrics.minimumY = NSMinY([screen_ visibleFrame]) + + metrics.minimumY = NSMinY([[self menuScreen] visibleFrame]) + bookmarks::kScrollWindowVerticalMargin; - metrics.screenBottomY = NSMinY([screen_ frame]); + metrics.screenBottomY = NSMinY([[self menuScreen] frame]); metrics.oldWindowY = NSMinY(metrics.windowFrame); metrics.folderY = metrics.scrollerFrame.origin.y + metrics.visibleFrame.origin.y + @@ -632,7 +611,8 @@ effectiveFolderY -= metrics.windowSize.height; metrics.canScrollUp = effectiveFolderY < metrics.minimumY; CGFloat maximumY = - NSMaxY([screen_ visibleFrame]) - bookmarks::kScrollWindowVerticalMargin; + NSMaxY([[self menuScreen] visibleFrame]) - + bookmarks::kScrollWindowVerticalMargin; metrics.canScrollDown = metrics.folderTop > maximumY; // Accommodate changes in the bottom of the menu. @@ -707,7 +687,7 @@ } else { if (metrics.canScrollDown) { // Couldn't -> Can - const CGFloat maximumY = NSMaxY([screen_ visibleFrame]); + const CGFloat maximumY = NSMaxY([[self menuScreen] visibleFrame]); metrics.deltaWindowHeight += (maximumY - NSMaxY(metrics.windowFrame)); metrics.deltaVisibleHeight -= bookmarks::kScrollWindowVerticalMargin; metrics.deltaScrollerHeight -= verticalScrollArrowHeight_; @@ -839,7 +819,7 @@ // Make sure as much of a submenu is exposed (which otherwise would be a // problem if the parent button is close to the bottom of the screen). if ([parentController_ isKindOfClass:[self class]]) { - CGFloat minimumY = NSMinY([screen_ visibleFrame]) + + CGFloat minimumY = NSMinY([[self menuScreen] visibleFrame]) + bookmarks::kScrollWindowVerticalMargin + height; newWindowTopLeft.y = MAX(newWindowTopLeft.y, minimumY); @@ -984,6 +964,7 @@ (delta < 0.0 && ![scrollDownArrowView_ isHidden])) { NSWindow* window = [self window]; NSRect windowFrame = [window frame]; + NSRect screenVisibleFrame = [[self menuScreen] visibleFrame]; NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin; CGFloat scrollY = scrollPosition.y; NSRect scrollerFrame = [scrollView_ frame]; @@ -995,14 +976,13 @@ if (delta > 0.0) { // Scrolling up. - CGFloat minimumY = NSMinY([screen_ visibleFrame]) + + CGFloat minimumY = NSMinY(screenVisibleFrame) + bookmarks::kScrollWindowVerticalMargin; CGFloat maxUpDelta = scrollY - offset + minimumY; delta = MIN(delta, maxUpDelta); } else { // Scrolling down. - NSRect screenFrame = [screen_ visibleFrame]; - CGFloat topOfScreen = NSMaxY(screenFrame); + CGFloat topOfScreen = NSMaxY(screenVisibleFrame); NSRect folderFrame = [folderView_ frame]; CGFloat folderHeight = NSHeight(folderFrame); CGFloat folderTop = folderHeight - scrollY + offset; @@ -1040,6 +1020,32 @@ [[NSRunLoop mainRunLoop] addTimer:scrollTimer_ forMode:NSRunLoopCommonModes]; } +- (NSScreen*)menuScreen { + // Return the parent button's screen for use as the screen upon which all + // display happens. This loop over all screens is not equivalent to + // |[[button window] screen]|. BookmarkButtons are commonly positioned near + // the edge of their windows (both in the bookmark bar and in other bookmark + // menus), and |[[button window] screen]| would return the screen that the + // majority of their window was on even if the parent button were clearly + // contained within a different screen. + NSButton* button = parentButton_.get(); + NSRect parentButtonGlobalFrame = + [button convertRect:[button bounds] toView:nil]; + parentButtonGlobalFrame.origin = + [[button window] convertBaseToScreen:parentButtonGlobalFrame.origin]; + for (NSScreen* screen in [NSScreen screens]) { + if (NSIntersectsRect([screen frame], parentButtonGlobalFrame)) + return screen; + } + + // The parent button is offscreen. The ideal thing to do would be to calculate + // the "closest" screen, the screen which has an edge parallel to, and the + // least distance from, one of the edges of the button. However, popping a + // subfolder from an offscreen button is an unrealistic edge case and so this + // ideal remains unrealized. Cheat instead; this code is wrong but a lot + // simpler. + return [[button window] screen]; +} // Called as a result of our tracking area. Warning: on the main // screen (of a single-screened machine), the minimum mouse y value is
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h index 018d88c..a1ae062 100644 --- a/chrome/browser/ui/cocoa/browser_window_cocoa.h +++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -10,6 +10,7 @@ #include "chrome/browser/extensions/extension_keybinding_registry.h" #include "chrome/browser/signin/signin_header_helper.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" #include "chrome/browser/ui/search/search_model_observer.h" #include "components/bookmarks/browser/bookmark_model.h" #include "ui/base/ui_base_types.h" @@ -31,10 +32,11 @@ // the Cocoa NSWindow. Cross-platform code will interact with this object when // it needs to manipulate the window. -class BrowserWindowCocoa : - public BrowserWindow, - public extensions::ExtensionKeybindingRegistry::Delegate, - public SearchModelObserver { +class BrowserWindowCocoa + : public BrowserWindow, + public ExclusiveAccessContext, + public extensions::ExtensionKeybindingRegistry::Delegate, + public SearchModelObserver { public: BrowserWindowCocoa(Browser* browser, BrowserWindowController* controller); @@ -78,7 +80,7 @@ ExclusiveAccessBubbleType type, bool with_toolbar) override; void ExitFullscreen() override; - void UpdateFullscreenExitBubbleContent( + void UpdateExclusiveAccessExitBubbleContent( const GURL& url, ExclusiveAccessBubbleType bubble_type) override; bool ShouldHideUIForFullscreen() const override; @@ -157,6 +159,13 @@ int GetRenderViewHeightInsetWithDetachedBookmarkBar() override; void ExecuteExtensionCommand(const extensions::Extension* extension, const extensions::Command& command) override; + ExclusiveAccessContext* GetExclusiveAccessContext() override; + + // ExclusiveAccessContext interface + Profile* GetProfile() override; + content::WebContents* GetActiveWebContents() override; + void UnhideDownloadShelf() override; + void HideDownloadShelf() override; // Overridden from ExtensionKeybindingRegistry::Delegate: extensions::ActiveTabPermissionGranter* GetActiveTabPermissionGranter()
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm index 96ea6f1..92fe33df 100644 --- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -406,7 +406,7 @@ [controller_ exitAnyFullscreen]; } -void BrowserWindowCocoa::UpdateFullscreenExitBubbleContent( +void BrowserWindowCocoa::UpdateExclusiveAccessExitBubbleContent( const GURL& url, ExclusiveAccessBubbleType bubble_type) { [controller_ updateFullscreenExitBubbleURL:url bubbleType:bubble_type]; @@ -820,3 +820,26 @@ const extensions::Command& command) { [cocoa_controller() executeExtensionCommand:extension->id() command:command]; } + +ExclusiveAccessContext* BrowserWindowCocoa::GetExclusiveAccessContext() { + return this; +} + +Profile* BrowserWindowCocoa::GetProfile() { + return browser_->profile(); +} + +WebContents* BrowserWindowCocoa::GetActiveWebContents() { + return browser_->tab_strip_model()->GetActiveWebContents(); +} + +void BrowserWindowCocoa::UnhideDownloadShelf() { + GetDownloadShelf()->Unhide(); +} + +void BrowserWindowCocoa::HideDownloadShelf() { + GetDownloadShelf()->Hide(); + StatusBubble* statusBubble = GetStatusBubble(); + if (statusBubble) + statusBubble->Hide(); +}
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm index ba7f9486..f3557a9c 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -617,10 +617,11 @@ [exclusiveAccessBubbleWindowController_ closeImmediately]; exclusiveAccessBubbleWindowController_.reset( [[ExclusiveAccessBubbleWindowController alloc] - initWithOwner:self - browser:browser_.get() - url:fullscreenUrl_ - bubbleType:exclusiveAccessBubbleType_]); + initWithOwner:self + exclusive_access_manager:browser_.get()->exclusive_access_manager() + profile:browser_.get()->profile() + url:fullscreenUrl_ + bubbleType:exclusiveAccessBubbleType_]); [exclusiveAccessBubbleWindowController_ showWindow]; } }
diff --git a/chrome/browser/ui/cocoa/certificate_viewer_mac.mm b/chrome/browser/ui/cocoa/certificate_viewer_mac.mm index 02995b5..e5f6a9a 100644 --- a/chrome/browser/ui/cocoa/certificate_viewer_mac.mm +++ b/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
@@ -197,6 +197,10 @@ // NOOP } +- (NSWindow*)sheetWindow { + return panel_; +} + - (void)onConstrainedWindowClosed { panel_.reset(); constrainedWindow_.reset();
diff --git a/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm b/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm index d5155082..2b5c1407 100644 --- a/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm +++ b/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
@@ -72,9 +72,7 @@ void ReleaseWebContentsOnDialogClose() override { return impl_->ReleaseWebContentsOnDialogClose(); } - NativeWebContentsModalDialog GetNativeDialog() override { - return constrained_window_->GetNativeDialog(); - } + NativeWebContentsModalDialog GetNativeDialog() override { return window_; } WebContents* GetWebContents() override { return impl_->GetWebContents(); } gfx::Size GetMinimumSize() const override { NOTIMPLEMENTED();
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm index 4300036..d6d12c9 100644 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm +++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm
@@ -73,4 +73,8 @@ [customWindow_ setFrameOrigin:origin]; } +- (NSWindow*)sheetWindow { + return customWindow_; +} + @end
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h index 6f3f222..e3d981e 100644 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h +++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
@@ -7,13 +7,11 @@ #import <Cocoa/Cocoa.h> -#include "base/mac/scoped_nsobject.h" -#include "components/web_modal/native_web_contents_modal_dialog.h" - namespace content { class WebContents; } class ConstrainedWindowMac; +class SingleWebContentsDialogManagerCocoa; @protocol ConstrainedWindowSheet; // A delegate for a constrained window. The delegate is notified when the @@ -28,29 +26,25 @@ // should delete the instance when the window is closed. class ConstrainedWindowMac { public: - ConstrainedWindowMac( - ConstrainedWindowMacDelegate* delegate, - content::WebContents* web_contents, - id<ConstrainedWindowSheet> sheet); - virtual ~ConstrainedWindowMac(); + ConstrainedWindowMac(ConstrainedWindowMacDelegate* delegate, + content::WebContents* web_contents, + id<ConstrainedWindowSheet> sheet); + ~ConstrainedWindowMac(); - void ShowWebContentsModalDialog(); - // Closes the constrained window and deletes this instance. + // Closes the constrained window. void CloseWebContentsModalDialog(); - void FocusWebContentsModalDialog(); - void PulseWebContentsModalDialog(); - web_modal::NativeWebContentsModalDialog GetNativeDialog(); + + SingleWebContentsDialogManagerCocoa* manager() const { return manager_; } + void set_manager(SingleWebContentsDialogManagerCocoa* manager) { + manager_ = manager; + } + + // Called by |manager_| when the dialog is closing. + void OnDialogClosing(); private: ConstrainedWindowMacDelegate* delegate_; // weak, owns us. - - // The WebContents that owns and constrains this ConstrainedWindowMac. Weak. - content::WebContents* web_contents_; - - base::scoped_nsprotocol<id<ConstrainedWindowSheet>> sheet_; - - // This is true if the constrained window has been shown. - bool shown_; + SingleWebContentsDialogManagerCocoa* manager_; // weak, owned by WCMDM. }; #endif // CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_MAC_
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm index 3c9dc59..1da08e0 100644 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm +++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
@@ -4,89 +4,46 @@ #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h" +#include "base/memory/scoped_ptr.h" #include "base/logging.h" -#include "chrome/browser/ui/browser_finder.h" -#include "chrome/browser/ui/browser_window.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h" -#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h" -#import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h" -#include "components/web_modal/popup_manager.h" +#import "chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/web_contents.h" #include "extensions/browser/guest_view/guest_view_base.h" using web_modal::WebContentsModalDialogManager; -using web_modal::NativeWebContentsModalDialog; ConstrainedWindowMac::ConstrainedWindowMac( ConstrainedWindowMacDelegate* delegate, content::WebContents* web_contents, id<ConstrainedWindowSheet> sheet) - : delegate_(delegate), - web_contents_(NULL), - sheet_([sheet retain]), - shown_(false) { - DCHECK(web_contents); + : delegate_(delegate) { + DCHECK(sheet); extensions::GuestViewBase* guest_view = extensions::GuestViewBase::FromWebContents(web_contents); // For embedded WebContents, use the embedder's WebContents for constrained // window. - web_contents_ = guest_view && guest_view->embedder_web_contents() ? - guest_view->embedder_web_contents() : web_contents; - DCHECK(sheet_.get()); - web_modal::PopupManager* popup_manager = - web_modal::PopupManager::FromWebContents(web_contents_); - if (popup_manager) - popup_manager->ShowModalDialog(this, web_contents_); + web_contents = guest_view && guest_view->embedder_web_contents() ? + guest_view->embedder_web_contents() : web_contents; + + auto manager = WebContentsModalDialogManager::FromWebContents(web_contents); + scoped_ptr<SingleWebContentsDialogManagerCocoa> native_manager( + new SingleWebContentsDialogManagerCocoa(this, sheet, manager)); + manager->ShowDialogWithManager([sheet sheetWindow], native_manager.Pass()); } ConstrainedWindowMac::~ConstrainedWindowMac() { CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); -} - -void ConstrainedWindowMac::ShowWebContentsModalDialog() { - if (shown_) - return; - - NSWindow* parent_window = web_contents_->GetTopLevelNativeWindow(); - NSView* parent_view = GetSheetParentViewForWebContents(web_contents_); - if (!parent_window || !parent_view) - return; - - shown_ = true; - ConstrainedWindowSheetController* controller = - [ConstrainedWindowSheetController - controllerForParentWindow:parent_window]; - [controller showSheet:sheet_ forParentView:parent_view]; + DCHECK(!manager_); } void ConstrainedWindowMac::CloseWebContentsModalDialog() { - [[ConstrainedWindowSheetController controllerForSheet:sheet_] - closeSheet:sheet_]; - // TODO(gbillock): get this object in config, not from a global. - WebContentsModalDialogManager* web_contents_modal_dialog_manager = - WebContentsModalDialogManager::FromWebContents(web_contents_); + if (manager_) + manager_->Close(); +} - // Will result in the delegate being deleted. +void ConstrainedWindowMac::OnDialogClosing() { if (delegate_) delegate_->OnConstrainedWindowClosed(this); - - // Will cause this object to be deleted. - web_contents_modal_dialog_manager->WillClose(this); -} - -void ConstrainedWindowMac::FocusWebContentsModalDialog() { -} - -void ConstrainedWindowMac::PulseWebContentsModalDialog() { - [[ConstrainedWindowSheetController controllerForSheet:sheet_] - pulseSheet:sheet_]; -} - -NativeWebContentsModalDialog ConstrainedWindowMac::GetNativeDialog() { - // TODO(wittman): Ultimately this should be changed to the - // ConstrainedWindowSheet pointer, in conjunction with the corresponding - // changes to NativeWebContentsModalDialogManagerCocoa. - return this; }
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h index 2352af0..4549556 100644 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h +++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h
@@ -24,6 +24,8 @@ - (void)updateSheetPosition; +@property(readonly, nonatomic) NSWindow* sheetWindow; + @end #endif // CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_SHEET_H_
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm index e8939b8e..aeeeb92 100644 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
@@ -56,6 +56,10 @@ - (void)updateSheetPosition { } +- (NSWindow*)sheetWindow { + return [alert_ window]; +} + - (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode ctxInfo:(void *)contextInfo {
diff --git a/chrome/browser/ui/cocoa/download/OWNERS b/chrome/browser/ui/cocoa/download/OWNERS index 7487122..04a7830 100644 --- a/chrome/browser/ui/cocoa/download/OWNERS +++ b/chrome/browser/ui/cocoa/download/OWNERS
@@ -1 +1,2 @@ +asanka@chromium.org thakis@chromium.org
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller.mm b/chrome/browser/ui/cocoa/download/download_item_controller.mm index a749d314..801e739b 100644 --- a/chrome/browser/ui/cocoa/download/download_item_controller.mm +++ b/chrome/browser/ui/cocoa/download/download_item_controller.mm
@@ -75,7 +75,7 @@ public: DownloadShelfContextMenuMac(DownloadItem* downloadItem, content::PageNavigator* navigator) - : DownloadShelfContextMenu(downloadItem, navigator) { } + : DownloadShelfContextMenu(downloadItem) { } // DownloadShelfContextMenu::GetMenuModel is protected. using DownloadShelfContextMenu::GetMenuModel;
diff --git a/chrome/browser/ui/cocoa/download/download_item_mac.mm b/chrome/browser/ui/cocoa/download/download_item_mac.mm index bf1ebc9..b39137c 100644 --- a/chrome/browser/ui/cocoa/download/download_item_mac.mm +++ b/chrome/browser/ui/cocoa/download/download_item_mac.mm
@@ -30,6 +30,11 @@ void DownloadItemMac::OnDownloadUpdated(content::DownloadItem* download) { DCHECK_EQ(download, download_model_.download()); + if (!download_model_.ShouldShowInShelf()) { + [item_controller_ remove]; // We're deleted now! + return; + } + if ([item_controller_ isDangerousMode] && !download_model_.IsDangerous()) { // We have been approved. [item_controller_ clearDangerousMode];
diff --git a/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.h b/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.h index d84330a..afb9706 100644 --- a/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.h +++ b/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.h
@@ -8,8 +8,8 @@ #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h" #include "url/gurl.h" -@class BrowserWindowController; -class Browser; +class ExclusiveAccessManager; +class Profile; @class GTMUILocalizerAndLayoutTweaker; @class HyperlinkTextView; @@ -20,8 +20,9 @@ @interface ExclusiveAccessBubbleWindowController : NSWindowController<NSTextViewDelegate, NSAnimationDelegate> { @private - BrowserWindowController* owner_; // weak - Browser* browser_; // weak + NSWindowController* owner_; // weak + ExclusiveAccessManager* exclusive_access_manager_; // weak + Profile* profile_; // weak GURL url_; ExclusiveAccessBubbleType bubbleType_; @@ -43,10 +44,11 @@ }; // Initializes a new InfoBarController. -- (id)initWithOwner:(BrowserWindowController*)owner - browser:(Browser*)browser - url:(const GURL&)url - bubbleType:(ExclusiveAccessBubbleType)bubbleType; +- (id)initWithOwner:(NSWindowController*)owner + exclusive_access_manager:(ExclusiveAccessManager*)exclusive_access_manager + profile:(Profile*)profile + url:(const GURL&)url + bubbleType:(ExclusiveAccessBubbleType)bubbleType; - (void)allow:(id)sender; - (void)deny:(id)sender;
diff --git a/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.mm b/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.mm index 06d8e85..eb5abc0c 100644 --- a/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.mm +++ b/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.mm
@@ -10,13 +10,13 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" -#import "chrome/browser/ui/cocoa/browser_window_controller.h" #import "chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.h" #import "chrome/browser/ui/cocoa/info_bubble_view.h" #import "chrome/browser/ui/cocoa/info_bubble_window.h" +#import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "chrome/grit/generated_resources.h" #include "extensions/browser/extension_registry.h" @@ -65,15 +65,17 @@ @implementation ExclusiveAccessBubbleWindowController -- (id)initWithOwner:(BrowserWindowController*)owner - browser:(Browser*)browser - url:(const GURL&)url - bubbleType:(ExclusiveAccessBubbleType)bubbleType { +- (id)initWithOwner:(NSWindowController*)owner + exclusive_access_manager:(ExclusiveAccessManager*)exclusive_access_manager + profile:(Profile*)profile + url:(const GURL&)url + bubbleType:(ExclusiveAccessBubbleType)bubbleType { NSString* nibPath = [base::mac::FrameworkBundle() pathForResource:@"ExclusiveAccessBubble" ofType:@"nib"]; if ((self = [super initWithWindowNibPath:nibPath owner:self])) { - browser_ = browser; + exclusive_access_manager_ = exclusive_access_manager; + profile_ = profile; owner_ = owner; url_ = url; bubbleType_ = bubbleType; @@ -97,12 +99,12 @@ [[self window] setIgnoresMouseEvents:YES]; DCHECK(exclusive_access_bubble::ShowButtonsForType(bubbleType_)); - browser_->exclusive_access_manager()->OnAcceptExclusiveAccessPermission(); + exclusive_access_manager_->OnAcceptExclusiveAccessPermission(); } - (void)deny:(id)sender { DCHECK(exclusive_access_bubble::ShowButtonsForType(bubbleType_)); - browser_->exclusive_access_manager()->OnDenyExclusiveAccessPermission(); + exclusive_access_manager_->OnDenyExclusiveAccessPermission(); } - (void)showButtons:(BOOL)show { @@ -126,7 +128,9 @@ } [tweaker_ tweakUI:info_bubble]; [[owner_ window] addChildWindow:info_bubble ordered:NSWindowAbove]; - [owner_ layoutSubviews]; + + if ([owner_ respondsToSelector:@selector(layoutSubviews)]) + [(id)owner_ layoutSubviews]; [info_bubble orderFront:self]; } @@ -151,8 +155,7 @@ - (BOOL)textView:(NSTextView*)textView clickedOnLink:(id)link atIndex:(NSUInteger)charIndex { - browser_->exclusive_access_manager() - ->fullscreen_controller() + exclusive_access_manager_->fullscreen_controller() ->ExitExclusiveAccessToPreviousState(); return YES; } @@ -281,7 +284,7 @@ if (bubbleType_ == EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE) return @""; extensions::ExtensionRegistry* registry = - extensions::ExtensionRegistry::Get(browser_->profile()); + extensions::ExtensionRegistry::Get(profile_); return SysUTF16ToNSString(exclusive_access_bubble::GetLabelTextForType( bubbleType_, url_, registry)); }
diff --git a/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller_unittest.mm b/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller_unittest.mm index d8601068..b3520045 100644 --- a/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller_unittest.mm
@@ -61,11 +61,12 @@ site_instance_ = SiteInstance::Create(profile()); controller_.reset([[ExclusiveAccessBubbleWindowController alloc] - initWithOwner:nil - browser:browser() - url:GURL() - bubbleType: - EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION]); + initWithOwner:nil + exclusive_access_manager:browser()->exclusive_access_manager() + profile:browser()->profile() + url:GURL() + bubbleType: + EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION]); EXPECT_TRUE([controller_ window]); } @@ -143,20 +144,23 @@ // http://crbug.com/139944 TEST_F(ExclusiveAccessBubbleWindowControllerTest, DenyButtonText) { controller_.reset([[ExclusiveAccessBubbleWindowController alloc] - initWithOwner:nil - browser:browser() - url:GURL() - bubbleType:EXCLUSIVE_ACCESS_BUBBLE_TYPE_MOUSELOCK_BUTTONS]); + initWithOwner:nil + exclusive_access_manager:browser()->exclusive_access_manager() + profile:browser()->profile() + url:GURL() + bubbleType:EXCLUSIVE_ACCESS_BUBBLE_TYPE_MOUSELOCK_BUTTONS]); [controller_ initializeLabelAndButton]; NSString* mouselock_deny_button_text = [controller_ denyButtonText]; EXPECT_NSEQ(l10n_util::GetNSString(IDS_FULLSCREEN_DENY), mouselock_deny_button_text); controller_.reset([[ExclusiveAccessBubbleWindowController alloc] - initWithOwner:nil - browser:browser() - url:GURL() - bubbleType:EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_MOUSELOCK_BUTTONS]); + initWithOwner:nil + exclusive_access_manager:browser()->exclusive_access_manager() + profile:browser()->profile() + url:GURL() + bubbleType: + EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_MOUSELOCK_BUTTONS]); [controller_ initializeLabelAndButton]; NSString* fullscreen_mouselock_deny_button_text = [controller_ denyButtonText];
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm index cb77cb9..bbfc886 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm
@@ -35,9 +35,9 @@ .AppendASCII(manifest_file); std::string error; - JSONFileValueSerializer serializer(path); + JSONFileValueDeserializer deserializer(path); scoped_ptr<base::DictionaryValue> value(static_cast<base::DictionaryValue*>( - serializer.Deserialize(NULL, &error))); + deserializer.Deserialize(NULL, &error))); if (!value.get()) { LOG(ERROR) << error; return extension;
diff --git a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm index 8378993..659f2a6 100644 --- a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm +++ b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
@@ -151,7 +151,7 @@ // If the page is at default zoom then hiding the zoom decoration // was suppressed while the bubble was open. Now that the bubble is // closed the decoration can be hidden. - if (IsVisible()) { + if (IsAtDefaultZoom() && IsVisible()) { SetVisible(false); owner_->OnDecorationsChanged(); }
diff --git a/chrome/browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm b/chrome/browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm index 0e4d425..e9d92b8 100644 --- a/chrome/browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm +++ b/chrome/browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm
@@ -108,6 +108,32 @@ EXPECT_FALSE(zoom_decoration->IsVisible()); } +// Regression test for https://crbug.com/462482. +IN_PROC_BROWSER_TEST_F(ZoomDecorationTest, IconRemainsVisibleAfterBubble) { + ZoomDecoration* zoom_decoration = GetZoomDecoration(); + + // See comment in BubbleAtDefaultZoom regarding this next line. + ui_zoom::ZoomController::FromWebContents( + GetLocationBar()->GetWebContents())->SetShowsNotificationBubble(false); + + // Zoom in to turn on decoration icon. + EXPECT_FALSE(zoom_decoration->IsVisible()); + Zoom(content::PAGE_ZOOM_IN); + EXPECT_TRUE(zoom_decoration->IsVisible()); + + // Show zoom bubble, verify decoration icon remains visible. + zoom_decoration->ShowBubble(/* auto_close = */false); + EXPECT_TRUE(zoom_decoration->IsVisible()); + + // Close bubble and verify the decoration is still visible. + zoom_decoration->CloseBubble(); + EXPECT_TRUE(zoom_decoration->IsVisible()); + + // Verify the decoration does go away when we expect it to. + Zoom(content::PAGE_ZOOM_RESET); + EXPECT_FALSE(zoom_decoration->IsVisible()); +} + IN_PROC_BROWSER_TEST_F(ZoomDecorationTest, HideOnInputProgress) { ZoomDecoration* zoom_decoration = GetZoomDecoration();
diff --git a/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.h b/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.h new file mode 100644 index 0000000..92f3321 --- /dev/null +++ b/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.h
@@ -0,0 +1,33 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_COCOA_PASSWORDS_ACCOUNT_AVATAR_FETCHER_MANAGER_H_ +#define CHROME_BROWSER_UI_COCOA_PASSWORDS_ACCOUNT_AVATAR_FETCHER_MANAGER_H_ + +#include <Cocoa/Cocoa.h> + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_vector.h" +#include "net/url_request/url_request_context_getter.h" + +class AccountAvatarFetcherBridge; +@class CredentialItemView; +class GURL; + +// Handles retrieving avatar images for credential items. +@interface AccountAvatarFetcherManager : NSObject { + ScopedVector<AccountAvatarFetcherBridge> bridges_; + scoped_refptr<net::URLRequestContextGetter> requestContext_; +} + +// Initializes a manager with the specified request context. +- (id)initWithRequestContext: + (scoped_refptr<net::URLRequestContextGetter>)requestContext; + +// Retrieves the image located at |avatarURL| and updates |view| if successful. +- (void)fetchAvatar:(const GURL&)avatarURL forView:(CredentialItemView*)view; + +@end + +#endif // CHROME_BROWSER_UI_COCOA_PASSWORDS_ACCOUNT_AVATAR_FETCHER_MANAGER_H_
diff --git a/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.mm b/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.mm new file mode 100644 index 0000000..618b782 --- /dev/null +++ b/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.mm
@@ -0,0 +1,85 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.h" + +#include "base/memory/weak_ptr.h" +#import "chrome/browser/ui/cocoa/passwords/credential_item_view.h" +#include "chrome/browser/ui/passwords/account_avatar_fetcher.h" +#include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/image/image_skia_util_mac.h" + +class AccountAvatarFetcherBridge; + +@interface AccountAvatarFetcherManager() +- (void)updateAvatar:(NSImage*)image + fromBridge:(AccountAvatarFetcherBridge*)bridge + forView:(CredentialItemView*)view; +@end + +class AccountAvatarFetcherBridge + : public AccountAvatarFetcherDelegate, + public base::SupportsWeakPtr<AccountAvatarFetcherBridge> { + public: + AccountAvatarFetcherBridge(AccountAvatarFetcherManager* manager, + CredentialItemView* view); + virtual ~AccountAvatarFetcherBridge(); + + // AccountAvatarFetcherDelegate: + void UpdateAvatar(const gfx::ImageSkia& image) override; + + private: + AccountAvatarFetcherManager* manager_; + CredentialItemView* view_; +}; + +AccountAvatarFetcherBridge::AccountAvatarFetcherBridge( + AccountAvatarFetcherManager* manager, + CredentialItemView* view) + : manager_(manager), view_(view) { +} + +AccountAvatarFetcherBridge::~AccountAvatarFetcherBridge() = default; + +void AccountAvatarFetcherBridge::UpdateAvatar(const gfx::ImageSkia& image) { + [manager_ + updateAvatar:gfx::NSImageFromImageSkia(ScaleImageForAccountAvatar(image)) + fromBridge:this + forView:view_]; +} + +@implementation AccountAvatarFetcherManager + +- (id)initWithRequestContext: + (scoped_refptr<net::URLRequestContextGetter>)requestContext { + if ((self = [super init])) { + requestContext_ = requestContext; + } + return self; +} + +- (void)startRequestWithFetcher:(AccountAvatarFetcher*)fetcher { + fetcher->Start(requestContext_.get()); +} + +- (void)fetchAvatar:(const GURL&)avatarURL forView:(CredentialItemView*)view { + scoped_ptr<AccountAvatarFetcherBridge> bridge( + new AccountAvatarFetcherBridge(self, view)); + AccountAvatarFetcher* fetcher = + new AccountAvatarFetcher(avatarURL, bridge->AsWeakPtr()); + bridges_.push_back(bridge.Pass()); + [self startRequestWithFetcher:fetcher]; +} + +- (void)updateAvatar:(NSImage*)image + fromBridge:(AccountAvatarFetcherBridge*)bridge + forView:(CredentialItemView*)view { + [view updateAvatar:image]; + auto it = std::find(bridges_.begin(), bridges_.end(), bridge); + if (it != bridges_.end()) + bridges_.erase(it); +} + +@end
diff --git a/chrome/browser/ui/cocoa/passwords/credential_item_view.h b/chrome/browser/ui/cocoa/passwords/credential_item_view.h new file mode 100644 index 0000000..c032759d --- /dev/null +++ b/chrome/browser/ui/cocoa/passwords/credential_item_view.h
@@ -0,0 +1,54 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_COCOA_PASSWORDS_CREDENTIAL_ITEM_VIEW_H_ +#define CHROME_BROWSER_UI_COCOA_PASSWORDS_CREDENTIAL_ITEM_VIEW_H_ + +#import <Cocoa/Cocoa.h> + +#import "base/mac/scoped_nsobject.h" +#include "components/autofill/core/common/password_form.h" +#include "components/password_manager/content/common/credential_manager_types.h" + +@class CredentialItemView; +class GURL; + +// Handles user interaction with and image fetching for a CredentialItemView. +@protocol CredentialItemDelegate<NSObject> + +// Retrieves the image located at |avatarURL| and updates |view| by calling +// [CredentialItemView updateAvatar:] if successful. +- (void)fetchAvatar:(const GURL&)avatarURL forView:(CredentialItemView*)view; + +@end + +// A view to show a single account credential. +@interface CredentialItemView : NSView { + autofill::PasswordForm passwordForm_; + password_manager::CredentialType credentialType_; + NSTextField* nameLabel_; + NSTextField* usernameLabel_; + NSImageView* avatarView_; + id<CredentialItemDelegate> delegate_; // Weak. +} + +@property(nonatomic, readonly) autofill::PasswordForm passwordForm; +@property(nonatomic, readonly) password_manager::CredentialType credentialType; + +// Initializes an item view populated with the data in |passwordForm|. Uses +// |delegate| to asynchronously fetch the avatar image. +- (id)initWithPasswordForm:(const autofill::PasswordForm&)passwordForm + credentialType:(password_manager::CredentialType)credentialType + delegate:(id<CredentialItemDelegate>)delegate; + +// Sets a custom avatar for this item. The image should be scaled and cropped +// to a circle of size |kAvatarImageSize|, otherwise it will look ridiculous. +- (void)updateAvatar:(NSImage*)avatar; + +// The default avatar image, used when a custom one is not set. ++ (NSImage*)defaultAvatar; + +@end + +#endif // CHROME_BROWSER_UI_COCOA_PASSWORDS_CREDENTIAL_ITEM_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/passwords/credential_item_view.mm b/chrome/browser/ui/cocoa/passwords/credential_item_view.mm new file mode 100644 index 0000000..1ea2341 --- /dev/null +++ b/chrome/browser/ui/cocoa/passwords/credential_item_view.mm
@@ -0,0 +1,158 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/ui/cocoa/passwords/credential_item_view.h" + +#include <algorithm> + +#include "base/i18n/rtl.h" +#include "base/mac/foundation_util.h" +#include "base/strings/sys_string_conversions.h" +#include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h" +#include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" +#include "grit/theme_resources.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/image/image_skia_util_mac.h" + +namespace { +const CGFloat kHorizontalPaddingBetweenAvatarAndLabels = 10.0f; +const CGFloat kVerticalPaddingBetweenLabels = 2.0f; +} // namespace + +@interface CredentialItemView() +@property(nonatomic, readonly) NSTextField* nameLabel; +@property(nonatomic, readonly) NSTextField* usernameLabel; +@property(nonatomic, readonly) NSImageView* avatarView; +@end + +@implementation CredentialItemView + +@synthesize nameLabel = nameLabel_; +@synthesize usernameLabel = usernameLabel_; +@synthesize avatarView = avatarView_; +@synthesize passwordForm = passwordForm_; +@synthesize credentialType = credentialType_; + +- (id)initWithPasswordForm:(const autofill::PasswordForm&)passwordForm + credentialType:(password_manager::CredentialType)credentialType + delegate:(id<CredentialItemDelegate>)delegate { + if ((self = [super init])) { + passwordForm_ = passwordForm; + credentialType_ = credentialType; + delegate_ = delegate; + + // ----------------------------------------------- + // | | John Q. Facebooker | + // | icon | john@somewhere.com | + // ----------------------------------------------- + + // Create the views. + + avatarView_ = [[[NSImageView alloc] initWithFrame:NSZeroRect] autorelease]; + [avatarView_ setWantsLayer:YES]; + [[avatarView_ layer] setCornerRadius:kAvatarImageSize / 2.0f]; + [[avatarView_ layer] setMasksToBounds:YES]; + [self addSubview:avatarView_]; + + if (!passwordForm_.display_name.empty()) { + nameLabel_ = [[[NSTextField alloc] initWithFrame:NSZeroRect] autorelease]; + [self addSubview:nameLabel_]; + [nameLabel_ setBezeled:NO]; + [nameLabel_ setDrawsBackground:NO]; + [nameLabel_ setEditable:NO]; + [nameLabel_ setSelectable:NO]; + [nameLabel_ + setStringValue:base::SysUTF16ToNSString(passwordForm_.display_name)]; + [nameLabel_ setAlignment:base::i18n::IsRTL() ? NSRightTextAlignment + : NSLeftTextAlignment]; + [nameLabel_ sizeToFit]; + } + + usernameLabel_ = + [[[NSTextField alloc] initWithFrame:NSZeroRect] autorelease]; + [self addSubview:usernameLabel_]; + [usernameLabel_ setBezeled:NO]; + [usernameLabel_ setDrawsBackground:NO]; + [usernameLabel_ setEditable:NO]; + [usernameLabel_ setSelectable:NO]; + [usernameLabel_ + setStringValue:base::SysUTF16ToNSString(passwordForm_.username_value)]; + [usernameLabel_ setAlignment:base::i18n::IsRTL() ? NSRightTextAlignment + : NSLeftTextAlignment]; + [usernameLabel_ sizeToFit]; + + // Compute the heights and widths of everything, as the layout depends on + // these measurements. + const CGFloat labelsHeight = NSHeight([nameLabel_ frame]) + + NSHeight([usernameLabel_ frame]) + + kVerticalPaddingBetweenLabels; + const CGFloat height = std::max(labelsHeight, CGFloat(kAvatarImageSize)); + const CGFloat width = + kAvatarImageSize + kHorizontalPaddingBetweenAvatarAndLabels + + std::max(NSWidth([nameLabel_ frame]), NSWidth([usernameLabel_ frame])); + self.frame = NSMakeRect(0, 0, width, height); + + // Lay out the views (RTL reverses the order horizontally). + + const CGFloat avatarX = base::i18n::IsRTL() ? width - kAvatarImageSize : 0; + const CGFloat avatarY = + (kAvatarImageSize > height) ? 0 : (height - kAvatarImageSize) / 2.0f; + [avatarView_ setFrame:NSMakeRect(avatarX, avatarY, kAvatarImageSize, + kAvatarImageSize)]; + + const CGFloat usernameX = + base::i18n::IsRTL() + ? NSMinX([avatarView_ frame]) - + kHorizontalPaddingBetweenAvatarAndLabels - + NSWidth([usernameLabel_ frame]) + : NSMaxX([avatarView_ frame]) + + kHorizontalPaddingBetweenAvatarAndLabels; + const CGFloat usernameLabelY = + (labelsHeight > height) ? 0 : (height - labelsHeight) / 2.0f; + NSRect usernameFrame = [usernameLabel_ frame]; + usernameFrame.origin = NSMakePoint(usernameX, usernameLabelY); + [usernameLabel_ setFrame:usernameFrame]; + + const CGFloat nameX = base::i18n::IsRTL() + ? NSMinX([avatarView_ frame]) - + kHorizontalPaddingBetweenAvatarAndLabels - + NSWidth([nameLabel_ frame]) + : NSMaxX([avatarView_ frame]) + + kHorizontalPaddingBetweenAvatarAndLabels; + const CGFloat nameLabelY = + NSMaxY(usernameFrame) + kVerticalPaddingBetweenLabels; + NSRect nameFrame = [nameLabel_ frame]; + nameFrame.origin = NSMakePoint(nameX, nameLabelY); + [nameLabel_ setFrame:nameFrame]; + + // Use a default avatar and fetch the custom one, if it exists. + [self updateAvatar:[[self class] defaultAvatar]]; + if (passwordForm_.avatar_url.is_valid()) + [delegate_ fetchAvatar:passwordForm_.avatar_url forView:self]; + + // When resizing, stick to the left (resp. right for RTL) edge. + const NSUInteger autoresizingMask = + (base::i18n::IsRTL() ? NSViewMinXMargin : NSViewMaxXMargin); + [avatarView_ setAutoresizingMask:autoresizingMask]; + [usernameLabel_ setAutoresizingMask:autoresizingMask]; + [nameLabel_ setAutoresizingMask:autoresizingMask]; + [self setAutoresizingMask:NSViewWidthSizable]; + } + + return self; +} + +- (void)updateAvatar:(NSImage*)avatar { + [avatarView_ setImage:avatar]; +} + ++ (NSImage*)defaultAvatar { + return gfx::NSImageFromImageSkia(ScaleImageForAccountAvatar( + *ResourceBundle::GetSharedInstance() + .GetImageNamed(IDR_PROFILE_AVATAR_PLACEHOLDER_LARGE) + .ToImageSkia())); +} + +@end
diff --git a/chrome/browser/ui/cocoa/passwords/credential_item_view_unittest.mm b/chrome/browser/ui/cocoa/passwords/credential_item_view_unittest.mm new file mode 100644 index 0000000..97e7048 --- /dev/null +++ b/chrome/browser/ui/cocoa/passwords/credential_item_view_unittest.mm
@@ -0,0 +1,184 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/ui/cocoa/passwords/credential_item_view.h" + +#include "base/strings/sys_string_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ui/cocoa/cocoa_test_helper.h" +#include "testing/gtest_mac.h" +#import "third_party/ocmock/OCMock/OCMock.h" +#include "third_party/ocmock/gtest_support.h" +#include "ui/gfx/image/image.h" + +@interface CredentialItemView(Testing) +@property(nonatomic, readonly) NSTextField* nameLabel; +@property(nonatomic, readonly) NSTextField* usernameLabel; +@property(nonatomic, readonly) NSImageView* avatarView; +@end + +// A test implementation of a CredentialItemDelegate to stub out interactions. +@interface CredentialItemTestDelegate : NSObject<CredentialItemDelegate> +@property(nonatomic, readonly) BOOL didFetchAvatar; +@property(nonatomic, readonly) GURL fetchedAvatarURL; +@property(nonatomic, readonly) CredentialItemView* viewForFetchedAvatar; +@property(nonatomic, readonly) BOOL didSelectPasswordForm; +@property(nonatomic, readonly) autofill::PasswordForm selectedPasswordForm; +@property(nonatomic, readonly) + password_manager::CredentialType selectedCredentialType; +@end + +@implementation CredentialItemTestDelegate +@synthesize didFetchAvatar = didFetchAvatar_; +@synthesize fetchedAvatarURL = fetchedAvatarURL_; +@synthesize viewForFetchedAvatar = viewForFetchedAvatar_; +@synthesize didSelectPasswordForm = didSelectPasswordForm_; +@synthesize selectedPasswordForm = selectedPasswordForm_; +@synthesize selectedCredentialType = selectedCredentialType_; + +- (void)fetchAvatar:(const GURL&)avatarURL forView:(CredentialItemView*)view { + didFetchAvatar_ = YES; + fetchedAvatarURL_ = avatarURL; + viewForFetchedAvatar_ = view; +} + +- (void)selectPasswordForm:(const autofill::PasswordForm&)passwordForm + credentialType:(password_manager::CredentialType)credentialType { + didSelectPasswordForm_ = YES; + selectedPasswordForm_ = passwordForm; + selectedCredentialType_ = credentialType; +} + +@end + +namespace { + +// Determines whether |left| and |right| have the same data representation. +// Necessary because [CredentialItemView defaultAvatar] does some ImageSkia +// stuff that creates new NSImage instances. +bool ImagesEqual(NSImage* left, NSImage* right) { + if (!left || !right) + return left == right; + + gfx::Image leftImage([left copy]); + gfx::Image rightImage([right copy]); + return leftImage.As1xPNGBytes()->Equals(rightImage.As1xPNGBytes()); +} + +// Returns a PasswordForm with only a username. +autofill::PasswordForm BasicCredential() { + autofill::PasswordForm credential; + credential.username_value = base::ASCIIToUTF16("taco"); + return credential; +} + +// Returns a PasswordForm with a username and display name. +autofill::PasswordForm CredentialWithName() { + autofill::PasswordForm credential; + credential.username_value = base::ASCIIToUTF16("pizza"); + credential.display_name = base::ASCIIToUTF16("margherita pizza"); + return credential; +} + +// Returns a PasswordForm with a username and avatar URL. +autofill::PasswordForm CredentialWithAvatar() { + autofill::PasswordForm credential; + credential.username_value = base::ASCIIToUTF16("sandwich"); + credential.avatar_url = GURL("http://sandwich.com/pastrami.jpg"); + return credential; +} + +// Returns a PasswordForm with a username, display name, and avatar URL. +autofill::PasswordForm CredentialWithNameAndAvatar() { + autofill::PasswordForm credential; + credential.username_value = base::ASCIIToUTF16("noodle"); + credential.display_name = base::ASCIIToUTF16("pasta amatriciana"); + credential.avatar_url = GURL("http://pasta.com/amatriciana.png"); + return credential; +} + +// Tests for CredentialItemViewTest. +class CredentialItemViewTest : public CocoaTest { + protected: + void SetUp() override { + delegate_.reset([[CredentialItemTestDelegate alloc] init]); + } + + // Returns a delegate for testing. + CredentialItemTestDelegate* delegate() { return delegate_.get(); } + + // Returns an autoreleased view populated from |form|. + CredentialItemView* view(const autofill::PasswordForm& form) { + return [[[CredentialItemView alloc] + initWithPasswordForm:form + credentialType:password_manager::CredentialType:: + CREDENTIAL_TYPE_LOCAL + delegate:delegate()] autorelease]; + } + + private: + base::scoped_nsobject<CredentialItemTestDelegate> delegate_; +}; + +TEST_F(CredentialItemViewTest, BasicCredential) { + autofill::PasswordForm form(BasicCredential()); + CredentialItemView* item = view(form); + + EXPECT_NSEQ(base::SysUTF16ToNSString(form.username_value), + [item usernameLabel].stringValue); + EXPECT_EQ(nil, [item nameLabel]); + EXPECT_FALSE([delegate() didFetchAvatar]); + EXPECT_TRUE( + ImagesEqual([CredentialItemView defaultAvatar], [item avatarView].image)); +} + +TEST_F(CredentialItemViewTest, CredentialWithName) { + autofill::PasswordForm form(CredentialWithName()); + CredentialItemView* item = view(form); + + EXPECT_NSEQ(base::SysUTF16ToNSString(form.username_value), + [item usernameLabel].stringValue); + EXPECT_NSEQ(base::SysUTF16ToNSString(form.display_name), + [item nameLabel].stringValue); + EXPECT_FALSE([delegate() didFetchAvatar]); + EXPECT_TRUE( + ImagesEqual([CredentialItemView defaultAvatar], [item avatarView].image)); +} + +TEST_F(CredentialItemViewTest, CredentialWithAvatar) { + autofill::PasswordForm form(CredentialWithAvatar()); + CredentialItemView* item = view(form); + + EXPECT_NSEQ(base::SysUTF16ToNSString(form.username_value), + [item usernameLabel].stringValue); + EXPECT_EQ(nil, [item nameLabel]); + EXPECT_TRUE([delegate() didFetchAvatar]); + EXPECT_EQ(form.avatar_url, [delegate() fetchedAvatarURL]); + EXPECT_EQ(item, [delegate() viewForFetchedAvatar]); + EXPECT_TRUE( + ImagesEqual([CredentialItemView defaultAvatar], [item avatarView].image)); + + [item updateAvatar:nil]; + EXPECT_FALSE([item avatarView].image); +} + +TEST_F(CredentialItemViewTest, CredentialWithNameAndAvatar) { + autofill::PasswordForm form(CredentialWithNameAndAvatar()); + CredentialItemView* item = view(form); + + EXPECT_NSEQ(base::SysUTF16ToNSString(form.username_value), + [item usernameLabel].stringValue); + EXPECT_NSEQ(base::SysUTF16ToNSString(form.display_name), + [item nameLabel].stringValue); + EXPECT_TRUE([delegate() didFetchAvatar]); + EXPECT_EQ(form.avatar_url, [delegate() fetchedAvatarURL]); + EXPECT_EQ(item, [delegate() viewForFetchedAvatar]); + EXPECT_TRUE( + ImagesEqual([CredentialItemView defaultAvatar], [item avatarView].image)); + + [item updateAvatar:nil]; + EXPECT_FALSE([item avatarView].image); +} + +} // namespace
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm index 12ee052..4c5aac73 100644 --- a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm +++ b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
@@ -178,7 +178,7 @@ NSMaxX([anchor bounds]) - kMenuXOffsetAdjust : NSMidX([anchor bounds]); NSPoint point = NSMakePoint(anchorX, - NSMaxY([anchor bounds]) - kMenuYOffsetAdjust); + NSMaxY([anchor bounds]) + kMenuYOffsetAdjust); point = [anchor convertPoint:point toView:nil]; point = [[anchor window] convertBaseToScreen:point];
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.mm b/chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.mm index 588fdea..3d0f39d8 100644 --- a/chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.mm
@@ -5,6 +5,7 @@ #import "chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.h" #include "base/mac/bundle_locations.h" +#include "base/mac/sdk_forward_declarations.h" #include "base/strings/sys_string_conversions.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/avatar_menu.h" @@ -159,6 +160,8 @@ NSRect frame = [nameField frame]; frame.size.width = kMaxItemTextWidth; [nameField setFrame:frame]; + if ([nameField respondsToSelector:@selector(setAllowsExpansionToolTips:)]) + [nameField setAllowsExpansionToolTips:YES]; } *widthAdjust = std::max(*widthAdjust, delta.width);
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm index 6844522..bd7a542 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
@@ -618,7 +618,7 @@ @end // A custom text control that turns into a textfield for editing when clicked. -@interface EditableProfileNameButton : HoverImageButton { +@interface EditableProfileNameButton : HoverImageButton<NSTextFieldDelegate> { @private base::scoped_nsobject<NSTextField> profileNameTextField_; Profile* profile_; // Weak. @@ -635,7 +635,7 @@ - (void)showEditableView:(id)sender; // Called when enter is pressed in the text field. -- (void)saveProfileName:(id)sender; +- (void)saveProfileName; @end @@ -691,8 +691,7 @@ NSLineBreakByTruncatingTail]; [[profileNameTextField_ cell] setUsesSingleLineMode:YES]; [self addSubview:profileNameTextField_]; - [profileNameTextField_ setTarget:self]; - [profileNameTextField_ setAction:@selector(saveProfileName:)]; + [profileNameTextField_ setDelegate:self]; // Hide the textfield until the user clicks on the button. [profileNameTextField_ setHidden:YES]; @@ -701,6 +700,13 @@ IDS_PROFILES_NEW_AVATAR_MENU_EDIT_NAME_ACCESSIBLE_NAME, base::SysNSStringToUTF16(profileName)) forAttribute:NSAccessibilityTitleAttribute]; + + NSSize textSize = [profileName sizeWithAttributes:@{ + NSFontAttributeName : [profileNameTextField_ font] + }]; + + if (textSize.width > frameRect.size.width - [hoverImage size].width * 2) + [self setToolTip:profileName]; } [[self cell] accessibilitySetOverrideValue:NSAccessibilityButtonRole @@ -719,21 +725,23 @@ return self; } -- (void)saveProfileName:(id)sender { +- (void)saveProfileName { base::string16 newProfileName = base::SysNSStringToUTF16([profileNameTextField_ stringValue]); - // Empty profile names are not allowed, and are treated as a cancel. + // Empty profile names are not allowed, and do nothing. base::TrimWhitespace(newProfileName, base::TRIM_ALL, &newProfileName); if (!newProfileName.empty()) { profiles::UpdateProfileName(profile_, newProfileName); [controller_ postActionPerformed:ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME]; - } else { - // Since the text is empty and not allowed, revert it from the textbox. - [profileNameTextField_ setStringValue:[self title]]; + [profileNameTextField_ setHidden:YES]; + // This needs to be called async as the firstResponder is reset + // at the same time that controlTextDidEndEditing happens. + dispatch_async(dispatch_get_main_queue(), ^{ + [[self window] makeFirstResponder:nil]; + }); } - [profileNameTextField_ setHidden:YES]; } - (void)showEditableView:(id)sender { @@ -745,6 +753,10 @@ return false; } +- (void)controlTextDidEndEditing:(NSNotification*)notification { + [self saveProfileName]; +} + @end // A custom button that allows for setting a background color when hovered over. @@ -1805,6 +1817,16 @@ [profileButton setTarget:self]; [profileButton setAction:@selector(switchToProfile:)]; + NSSize textSize = [[profileButton title] sizeWithAttributes:@{ + NSFontAttributeName : [profileButton font] + }]; + + CGFloat availableWidth = rect.size.width - kSmallImageSide - + kImageTitleSpacing - kHorizontalSpacing; + + if (std::ceil(textSize.width) > availableWidth) + [profileButton setToolTip:[profileButton title]]; + return profileButton.autorelease(); }
diff --git a/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h b/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h new file mode 100644 index 0000000..55efe46 --- /dev/null +++ b/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h
@@ -0,0 +1,43 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_COCOA_SINGLE_WEB_CONTENTS_DIALOG_MANAGER_COCOA_H_ +#define CHROME_BROWSER_UI_COCOA_SINGLE_WEB_CONTENTS_DIALOG_MANAGER_COCOA_H_ + +#import "base/mac/scoped_nsobject.h" +#include "components/web_modal/single_web_contents_dialog_manager.h" + +class ConstrainedWindowMac; +@protocol ConstrainedWindowSheet; + +// Cocoa implementation of web_modal::SingleWebContentsDialogManager. +class SingleWebContentsDialogManagerCocoa + : public web_modal::SingleWebContentsDialogManager { + public: + SingleWebContentsDialogManagerCocoa( + ConstrainedWindowMac* client, + id<ConstrainedWindowSheet> sheet, + web_modal::SingleWebContentsDialogManagerDelegate* delegate); + ~SingleWebContentsDialogManagerCocoa() override; + + // SingleWebContentsDialogManager overrides. + void Show() override; + void Hide() override; + void Close() override; + void Focus() override; + void Pulse() override; + void HostChanged(web_modal::WebContentsModalDialogHost* new_host) override; + web_modal::NativeWebContentsModalDialog dialog() override; + + private: + ConstrainedWindowMac* client_; // Weak. Can be null. + base::scoped_nsprotocol<id<ConstrainedWindowSheet>> sheet_; + // Weak. Owns this. + web_modal::SingleWebContentsDialogManagerDelegate* delegate_; + bool shown_; + + DISALLOW_COPY_AND_ASSIGN(SingleWebContentsDialogManagerCocoa); +}; + +#endif // CHROME_BROWSER_UI_COCOA_SINGLE_WEB_CONTENTS_DIALOG_MANAGER_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.mm b/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.mm new file mode 100644 index 0000000..3bd76bd --- /dev/null +++ b/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.mm
@@ -0,0 +1,87 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h" + +#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h" +#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h" +#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h" +#import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" + +using web_modal::NativeWebContentsModalDialog; +using web_modal::SingleWebContentsDialogManagerDelegate; + +SingleWebContentsDialogManagerCocoa::SingleWebContentsDialogManagerCocoa( + ConstrainedWindowMac* client, + id<ConstrainedWindowSheet> sheet, + web_modal::SingleWebContentsDialogManagerDelegate* delegate) + : client_(client), + sheet_([sheet retain]), + delegate_(delegate), + shown_(false) { + if (client) + client->set_manager(this); +} + +SingleWebContentsDialogManagerCocoa::~SingleWebContentsDialogManagerCocoa() { +} + +void SingleWebContentsDialogManagerCocoa::Show() { + if (shown_) + return; + + content::WebContents* web_contents = delegate_->GetWebContents(); + NSWindow* parent_window = web_contents->GetTopLevelNativeWindow(); + NSView* parent_view = GetSheetParentViewForWebContents(web_contents); + if (!parent_window || !parent_view) + return; + + shown_ = true; + [[ConstrainedWindowSheetController controllerForParentWindow:parent_window] + showSheet:sheet_ forParentView:parent_view]; +} + +void SingleWebContentsDialogManagerCocoa::Hide() { +} + +void SingleWebContentsDialogManagerCocoa::Close() { + [[ConstrainedWindowSheetController controllerForSheet:sheet_] + closeSheet:sheet_]; + if (client_) { + client_->set_manager(nullptr); + client_->OnDialogClosing(); // |client_| might delete itself here. + client_ = nullptr; + } + delegate_->WillClose(dialog()); +} + +void SingleWebContentsDialogManagerCocoa::Focus() { +} + +void SingleWebContentsDialogManagerCocoa::Pulse() { + [[ConstrainedWindowSheetController controllerForSheet:sheet_] + pulseSheet:sheet_]; +} + +void SingleWebContentsDialogManagerCocoa::HostChanged( + web_modal::WebContentsModalDialogHost* new_host) { +} + +NativeWebContentsModalDialog SingleWebContentsDialogManagerCocoa::dialog() { + return [sheet_ sheetWindow]; +} + +namespace web_modal { + +SingleWebContentsDialogManager* +WebContentsModalDialogManager::CreateNativeWebModalManager( + NativeWebContentsModalDialog dialog, + SingleWebContentsDialogManagerDelegate* delegate) { + base::scoped_nsobject<CustomConstrainedWindowSheet> sheet( + [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:dialog]); + return new SingleWebContentsDialogManagerCocoa(nullptr, sheet, delegate); +} + +} // namespace web_modal
diff --git a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm index 9d471b9..a8d7912 100644 --- a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm +++ b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
@@ -227,6 +227,10 @@ // NOOP } +- (NSWindow*)sheetWindow { + return panel_; +} + - (void)onConstrainedWindowClosed { observer_->StopObserving(); panel_.reset();
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.mm b/chrome/browser/ui/cocoa/status_bubble_mac.mm index 667d952..272cb9d9 100644 --- a/chrome/browser/ui/cocoa/status_bubble_mac.mm +++ b/chrome/browser/ui/cocoa/status_bubble_mac.mm
@@ -142,6 +142,32 @@ @end +// Mac implementation of the status bubble. +// +// Child windows interact with Spaces in interesting ways, so this code has to +// follow these rules: +// +// 1) NSWindows cannot have zero size. At times when the status bubble window +// has no specific size (for example, when hidden), its size is set to +// ui::kWindowSizeDeterminedLater. +// +// 2) Child window frames are in the coordinate space of the screen, not of the +// parent window. If a child window has its origin at (0, 0), Spaces will +// position it in the corner of the screen but group it with the parent +// window in Spaces. This causes Chrome windows to have a large (mostly +// blank) area in Spaces. To avoid this, child windows always have their +// origin set to the lower-left corner of the window. +// +// 3) Detached child windows may show up as top-level windows in Spaces. To +// avoid this, once the status bubble is Attach()ed to the parent, it is +// never detached (except in rare cases when reparenting to a fullscreen +// window). +// +// 4) To avoid unnecessary redraws, if a bubble is in the kBubbleHidden state, +// its size is always set to ui::kWindowSizeDeterminedLater. The proper +// width for the current URL or status text is not calculated until the +// bubble leaves the kBubbleHidden state. + StatusBubbleMac::StatusBubbleMac(NSWindow* parent, id delegate) : parent_(parent), delegate_(delegate), @@ -177,16 +203,16 @@ url_ = url; languages_ = languages; - NSRect frame = [window_ frame]; - - // Reset frame size when bubble is hidden. + CGFloat bubble_width = NSWidth([window_ frame]); if (state_ == kBubbleHidden) { - is_expanded_ = false; - frame.size.width = NSWidth(CalculateWindowFrame(/*expand=*/false)); - [window_ setFrame:frame display:NO]; + DCHECK_EQ(ui::kWindowSizeDeterminedLater.size.width, + [window_ frame].size.width); + DCHECK_EQ(ui::kWindowSizeDeterminedLater.size.height, + [window_ frame].size.height); + bubble_width = NSWidth(CalculateWindowFrame(/*expand=*/false)); } - int text_width = static_cast<int>(NSWidth(frame) - + int text_width = static_cast<int>(bubble_width - kBubbleViewTextPositionX - kTextPadding); @@ -260,8 +286,10 @@ show = false; if (show) { - UpdateSizeAndPosition(); + // Call StartShowing() first to update the current bubble state before + // calculating a new size. StartShowing(); + UpdateSizeAndPosition(); } else { StartHiding(); } @@ -284,21 +312,22 @@ } } + NSRect frame = CalculateWindowFrame(/*expand=*/false); if (!fade_out) { // No animation is in progress, so the opacity can be set directly. [window_ setAlphaValue:0.0]; SetState(kBubbleHidden); + frame.size = ui::kWindowSizeDeterminedLater.size; } // Stop any width animation and reset the bubble size. if (!immediate_) { [NSAnimationContext beginGrouping]; [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval]; - [[window_ animator] setFrame:CalculateWindowFrame(/*expand=*/false) - display:NO]; + [[window_ animator] setFrame:frame display:NO]; [NSAnimationContext endGrouping]; } else { - [window_ setFrame:CalculateWindowFrame(/*expand=*/false) display:NO]; + [window_ setFrame:frame display:NO]; } [status_text_ release]; @@ -446,7 +475,14 @@ DCHECK(is_attached()); // Magic setFrame: See http://crbug.com/58506 and http://crrev.com/3564021 . - [window_ setFrame:CalculateWindowFrame(/*expand=*/false) display:NO]; + // TODO(rohitrao): Does the frame size actually matter here? Can we always + // set it to kWindowSizeDeterminedLater? + NSRect frame = [window_ frame]; + frame.size = ui::kWindowSizeDeterminedLater.size; + if (state_ != kBubbleHidden) { + frame = CalculateWindowFrame(/*expand=*/false); + } + [window_ setFrame:frame display:NO]; [parent_ removeChildWindow:window_]; // See crbug.com/28107 ... [window_ orderOut:nil]; // ... and crbug.com/29054. @@ -472,6 +508,8 @@ return; if (state == kBubbleHidden) { + is_expanded_ = false; + // When hidden (with alpha of 0), make the window have the minimum size, // while still keeping the same origin. It's important to not set the // origin to 0,0 as that will cause the window to use more space in @@ -717,6 +755,17 @@ if (!window_) return; + // There is no need to update the size if the bubble is hidden. + if (state_ == kBubbleHidden) { + // Verify that hidden bubbles always have size equal to + // ui::kWindowSizeDeterminedLater. + DCHECK_EQ(ui::kWindowSizeDeterminedLater.size.width, + [window_ frame].size.width); + DCHECK_EQ(ui::kWindowSizeDeterminedLater.size.height, + [window_ frame].size.height); + return; + } + SetFrameAvoidingMouse(CalculateWindowFrame(/*expand=*/false), GetMouseLocation()); }
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm index a828a43..0ffc1133 100644 --- a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm +++ b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
@@ -667,3 +667,19 @@ ASSERT_TRUE(CheckAvoidsMouse(x, smallValue)); } } + +TEST_F(StatusBubbleMacTest, ReparentBubble) { + // The second window is borderless, like the window used in fullscreen mode. + base::scoped_nsobject<NSWindow> fullscreenParent( + [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600) + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]); + + // Switch parents with the bubble hidden. + bubble_->SwitchParentWindow(fullscreenParent); + + // Switch back to the original parent with the bubble showing. + bubble_->SetStatus(UTF8ToUTF16("Showing")); + bubble_->SwitchParentWindow(test_window()); +}
diff --git a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h index 48d2f40..19ff9d2a4 100644 --- a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h +++ b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h
@@ -7,6 +7,7 @@ #import <Cocoa/Cocoa.h> +#import "base/mac/scoped_nsobject.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h" #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
diff --git a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_cocoa.mm b/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_cocoa.mm deleted file mode 100644 index 5d025f6c..0000000 --- a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_cocoa.mm +++ /dev/null
@@ -1,71 +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 "components/web_modal/web_contents_modal_dialog_manager.h" - -#include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h" -#include "components/web_modal/single_web_contents_dialog_manager.h" - -using web_modal::NativeWebContentsModalDialog; - -namespace { - -class NativeWebContentsModalDialogManagerCocoa - : public web_modal::SingleWebContentsDialogManager { - public: - NativeWebContentsModalDialogManagerCocoa( - NativeWebContentsModalDialog dialog) - : dialog_(dialog) { - } - - ~NativeWebContentsModalDialogManagerCocoa() override {} - - // SingleWebContentsDialogManager overrides - void Show() override { - GetConstrainedWindowMac(dialog())->ShowWebContentsModalDialog(); - } - - void Hide() override {} - - void Close() override { - GetConstrainedWindowMac(dialog())->CloseWebContentsModalDialog(); - } - - void Focus() override { - GetConstrainedWindowMac(dialog())->FocusWebContentsModalDialog(); - } - - void Pulse() override { - GetConstrainedWindowMac(dialog())->PulseWebContentsModalDialog(); - } - - void HostChanged(web_modal::WebContentsModalDialogHost* new_host) override {} - - NativeWebContentsModalDialog dialog() override { return dialog_; } - - private: - static ConstrainedWindowMac* GetConstrainedWindowMac( - NativeWebContentsModalDialog dialog) { - return static_cast<ConstrainedWindowMac*>(dialog); - } - - // In mac this is a pointer to a ConstrainedWindowMac. - // TODO(gbillock): Replace this casting system with a more typesafe call path. - NativeWebContentsModalDialog dialog_; - - DISALLOW_COPY_AND_ASSIGN(NativeWebContentsModalDialogManagerCocoa); -}; - -} // namespace - -namespace web_modal { - -SingleWebContentsDialogManager* - WebContentsModalDialogManager::CreateNativeWebModalManager( - NativeWebContentsModalDialog dialog, - SingleWebContentsDialogManagerDelegate* native_delegate) { - return new NativeWebContentsModalDialogManagerCocoa(dialog); -} - -} // namespace web_modal
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc index 0df4fa7..23c1275 100644 --- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc +++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -1199,6 +1199,7 @@ return; // Reset this embedder's entry to default for each of the requesting // origins currently on the page. + const GURL& embedder_url = web_contents()->GetURL(); TabSpecificContentSettings* content_settings = TabSpecificContentSettings::FromWebContents(web_contents()); const ContentSettingsUsagesState::StateMap& state_map = @@ -1210,7 +1211,7 @@ state_map.begin(); it != state_map.end(); ++it) { settings_map->SetContentSetting( ContentSettingsPattern::FromURLNoWildcard(it->first), - ContentSettingsPattern::Wildcard(), + ContentSettingsPattern::FromURLNoWildcard(embedder_url), CONTENT_SETTINGS_TYPE_MIDI_SYSEX, std::string(), CONTENT_SETTING_DEFAULT);
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.cc b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.cc index b960ce1..5d9f554e 100644 --- a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.cc +++ b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.cc
@@ -7,8 +7,8 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "chrome/grit/generated_resources.h" #include "extensions/browser/extension_registry.h" @@ -32,10 +32,10 @@ const int ExclusiveAccessBubble::kPopupTopPx = 15; ExclusiveAccessBubble::ExclusiveAccessBubble( - Browser* browser, + ExclusiveAccessManager* manager, const GURL& url, ExclusiveAccessBubbleType bubble_type) - : browser_(browser), url_(url), bubble_type_(bubble_type) { + : manager_(manager), url_(url), bubble_type_(bubble_type) { DCHECK_NE(EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE, bubble_type_); } @@ -114,24 +114,22 @@ } } -void ExclusiveAccessBubble::ToggleFullscreen() { - browser_->exclusive_access_manager() - ->fullscreen_controller() - ->ExitExclusiveAccessToPreviousState(); +void ExclusiveAccessBubble::ExitExclusiveAccess() { + manager_->ExitExclusiveAccess(); } void ExclusiveAccessBubble::Accept() { - browser_->exclusive_access_manager()->OnAcceptExclusiveAccessPermission(); + manager_->OnAcceptExclusiveAccessPermission(); } void ExclusiveAccessBubble::Cancel() { - browser_->exclusive_access_manager()->OnDenyExclusiveAccessPermission(); + manager_->OnDenyExclusiveAccessPermission(); } base::string16 ExclusiveAccessBubble::GetCurrentMessageText() const { return exclusive_access_bubble::GetLabelTextForType( bubble_type_, url_, - extensions::ExtensionRegistry::Get(browser_->profile())); + extensions::ExtensionRegistry::Get(manager_->context()->GetProfile())); } base::string16 ExclusiveAccessBubble::GetCurrentDenyButtonText() const {
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h index d7654ab..57f55c0 100644 --- a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h +++ b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h
@@ -11,7 +11,7 @@ #include "ui/gfx/geometry/point.h" #include "url/gurl.h" -class Browser; +class ExclusiveAccessManager; namespace gfx { class Rect; @@ -22,7 +22,7 @@ // state, namely fullscreen and mouse lock. class ExclusiveAccessBubble : public gfx::AnimationDelegate { public: - explicit ExclusiveAccessBubble(Browser* browser, + explicit ExclusiveAccessBubble(ExclusiveAccessManager* manager, const GURL& url, ExclusiveAccessBubbleType bubble_type); ~ExclusiveAccessBubble() override; @@ -71,7 +71,7 @@ // on or off the screen as appropriate. void CheckMousePosition(); - void ToggleFullscreen(); + void ExitExclusiveAccess(); // Accepts the request. Can cause FullscreenExitBubble to be deleted. void Accept(); // Denys the request. Can cause FullscreenExitBubble to be deleted. @@ -85,8 +85,8 @@ // The following strings never change. base::string16 GetInstructionText() const; - // The browser this bubble is in. - Browser* browser_; + // The Manager associated with this bubble. + ExclusiveAccessManager* const manager_; // The host the bubble is for, can be empty. GURL url_;
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_context.cc b/chrome/browser/ui/exclusive_access/exclusive_access_context.cc new file mode 100644 index 0000000..f85582c --- /dev/null +++ b/chrome/browser/ui/exclusive_access/exclusive_access_context.cc
@@ -0,0 +1,33 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" + +#include "base/logging.h" + +bool ExclusiveAccessContext::SupportsFullscreenWithToolbar() const { + return false; +} + +void ExclusiveAccessContext::UpdateFullscreenWithToolbar(bool with_toolbar) { + NOTIMPLEMENTED(); +} + +#if defined(OS_WIN) +void ExclusiveAccessContext::SetMetroSnapMode(bool enable) { + NOTIMPLEMENTED(); +} + +bool ExclusiveAccessContext::IsInMetroSnapMode() const { + return false; +} +#endif // defined(OS_WIN) + +void ExclusiveAccessContext::UnhideDownloadShelf() { + // NOOP implementation. +} + +void ExclusiveAccessContext::HideDownloadShelf() { + // NOOP implementation. +}
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_context.h b/chrome/browser/ui/exclusive_access/exclusive_access_context.h new file mode 100644 index 0000000..36fc41b --- /dev/null +++ b/chrome/browser/ui/exclusive_access/exclusive_access_context.h
@@ -0,0 +1,80 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_EXCLUSIVE_ACCESS_EXCLUSIVE_ACCESS_CONTEXT_H_ +#define CHROME_BROWSER_UI_EXCLUSIVE_ACCESS_EXCLUSIVE_ACCESS_CONTEXT_H_ + +#include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h" + +class GURL; +class Profile; + +namespace content { +class WebContents; +} + +// Context in which exclusive access operation is being performed. This +// interface is implemented once in Browser context and in Platform Application +// context. +class ExclusiveAccessContext { + public: + virtual ~ExclusiveAccessContext() {} + + // Returns the current profile associated with the window. + virtual Profile* GetProfile() = 0; + + // Returns true if the window hosting the exclusive access bubble is + // fullscreen. + virtual bool IsFullscreen() const = 0; + + // Returns true if fullscreen with toolbar is supported. + virtual bool SupportsFullscreenWithToolbar() const; + + // Shows or hides the tab strip, toolbar and bookmark bar with in browser + // fullscreen. + // Currently only supported on Mac. + virtual void UpdateFullscreenWithToolbar(bool with_toolbar); + + // Returns true if the window is fullscreen with additional UI elements. See + // EnterFullscreen |with_toolbar|. + virtual bool IsFullscreenWithToolbar() const = 0; + + // Enters fullscreen and update exit bubble. + // On Mac, the tab strip and toolbar will be shown if |with_toolbar| is true, + // |with_toolbar| is ignored on other platforms. + virtual void EnterFullscreen(const GURL& url, + ExclusiveAccessBubbleType bubble_type, + bool with_toolbar) = 0; + + // Exits fullscreen and update exit bubble. + virtual void ExitFullscreen() = 0; + + // Updates the content of exclusive access exit bubble content. + virtual void UpdateExclusiveAccessExitBubbleContent( + const GURL& url, + ExclusiveAccessBubbleType bubble_type) = 0; + +#if defined(OS_WIN) + // Sets state for entering or exiting Win8 Metro snap mode. + virtual void SetMetroSnapMode(bool enable); + + // Returns whether the window is currently in Win8 Metro snap mode. + virtual bool IsInMetroSnapMode() const; +#endif // defined(OS_WIN) + + // Returns the currently active WebContents, or nullptr if there is none. + virtual content::WebContents* GetActiveWebContents() = 0; + + // TODO(sriramsr): This is abstraction violation as the following two function + // does not apply to a platform app window. Ideally, the BrowserView should + // hide/unhide its download shelf widget when it is instructed to enter/exit + // fullscreen mode. + // Displays the download shelf associated with currently active window. + virtual void UnhideDownloadShelf(); + + // Hides download shelf associated with currently active window. + virtual void HideDownloadShelf(); +}; + +#endif // CHROME_BROWSER_UI_EXCLUSIVE_ACCESS_EXCLUSIVE_ACCESS_CONTEXT_H_
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_controller_base.cc b/chrome/browser/ui/exclusive_access/exclusive_access_controller_base.cc index db8a243c..bbc7545 100644 --- a/chrome/browser/ui/exclusive_access/exclusive_access_controller_base.cc +++ b/chrome/browser/ui/exclusive_access/exclusive_access_controller_base.cc
@@ -16,13 +16,8 @@ using content::WebContents; ExclusiveAccessControllerBase::ExclusiveAccessControllerBase( - ExclusiveAccessManager* manager, - Browser* browser) - : manager_(manager), - browser_(browser), - profile_(browser->profile()), - tab_with_exclusive_access_(nullptr) { - DCHECK(profile_); + ExclusiveAccessManager* manager) + : manager_(manager), tab_with_exclusive_access_(nullptr) { } ExclusiveAccessControllerBase::~ExclusiveAccessControllerBase() {
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_controller_base.h b/chrome/browser/ui/exclusive_access/exclusive_access_controller_base.h index 99c5614..1d127c4 100644 --- a/chrome/browser/ui/exclusive_access/exclusive_access_controller_base.h +++ b/chrome/browser/ui/exclusive_access/exclusive_access_controller_base.h
@@ -6,13 +6,11 @@ #define CHROME_BROWSER_UI_EXCLUSIVE_ACCESS_EXCLUSIVE_ACCESS_CONTROLLER_BASE_H_ #include "base/basictypes.h" -#include "base/memory/weak_ptr.h" +#include "base/memory/ref_counted.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" -class Browser; -class BrowserWindow; class ExclusiveAccessManager; class GURL; class Profile; @@ -26,8 +24,7 @@ // which the resource (screen/mouse) is held exclusively. class ExclusiveAccessControllerBase : public content::NotificationObserver { public: - explicit ExclusiveAccessControllerBase(ExclusiveAccessManager* manager, - Browser* browser); + explicit ExclusiveAccessControllerBase(ExclusiveAccessManager* manager); ~ExclusiveAccessControllerBase() override; GURL GetExclusiveAccessBubbleURL() const; @@ -73,10 +70,6 @@ ExclusiveAccessManager* exclusive_access_manager() const { return manager_; } - Browser* browser() const { return browser_; } - - Profile* profile() const { return profile_; } - // Exits exclusive access mode for the tab if currently exclusive. virtual void ExitExclusiveAccessIfNecessary() = 0; @@ -88,8 +81,6 @@ void UpdateNotificationRegistrations(); ExclusiveAccessManager* const manager_; - Browser* const browser_; - Profile* const profile_; content::NotificationRegistrar registrar_;
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_manager.cc b/chrome/browser/ui/exclusive_access/exclusive_access_manager.cc index 56a8cc6..e252a39 100644 --- a/chrome/browser/ui/exclusive_access/exclusive_access_manager.cc +++ b/chrome/browser/ui/exclusive_access/exclusive_access_manager.cc
@@ -7,15 +7,17 @@ #include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "chrome/browser/ui/exclusive_access/mouse_lock_controller.h" using content::WebContents; -ExclusiveAccessManager::ExclusiveAccessManager(Browser* browser) - : browser_(browser), - fullscreen_controller_(this, browser), - mouse_lock_controller_(this, browser) { +ExclusiveAccessManager::ExclusiveAccessManager( + ExclusiveAccessContext* exclusive_access_context) + : exclusive_access_context_(exclusive_access_context), + fullscreen_controller_(this), + mouse_lock_controller_(this) { } ExclusiveAccessManager::~ExclusiveAccessManager() { @@ -71,7 +73,8 @@ mouse_lock_controller_.IsMouseLocked()) mouse_lock_controller_.UnlockMouse(); - browser_->window()->UpdateFullscreenExitBubbleContent(url, bubble_type); + exclusive_access_context_->UpdateExclusiveAccessExitBubbleContent( + url, bubble_type); } GURL ExclusiveAccessManager::GetExclusiveAccessBubbleURL() const { @@ -117,3 +120,8 @@ if (updateBubble) UpdateExclusiveAccessExitBubbleContent(); } + +void ExclusiveAccessManager::ExitExclusiveAccess() { + fullscreen_controller_.ExitExclusiveAccessToPreviousState(); + mouse_lock_controller_.LostMouseLock(); +}
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_manager.h b/chrome/browser/ui/exclusive_access/exclusive_access_manager.h index 0c10fe5..539958c2 100644 --- a/chrome/browser/ui/exclusive_access/exclusive_access_manager.h +++ b/chrome/browser/ui/exclusive_access/exclusive_access_manager.h
@@ -10,7 +10,7 @@ #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "chrome/browser/ui/exclusive_access/mouse_lock_controller.h" -class Browser; +class ExclusiveAccessContext; class FullscreenController; class GURL; class MouseLockController; @@ -24,7 +24,8 @@ // the exit bubble to reflect the combined state. class ExclusiveAccessManager { public: - explicit ExclusiveAccessManager(Browser* browser); + explicit ExclusiveAccessManager( + ExclusiveAccessContext* exclusive_access_context); ~ExclusiveAccessManager(); FullscreenController* fullscreen_controller() { @@ -35,6 +36,8 @@ return &mouse_lock_controller_; } + ExclusiveAccessContext* context() const { return exclusive_access_context_; } + ExclusiveAccessBubbleType GetExclusiveAccessExitBubbleType() const; void UpdateExclusiveAccessExitBubbleContent(); @@ -57,9 +60,10 @@ // Called by platform ExclusiveAccessExitBubble. void OnAcceptExclusiveAccessPermission(); void OnDenyExclusiveAccessPermission(); + void ExitExclusiveAccess(); private: - Browser* const browser_; + ExclusiveAccessContext* const exclusive_access_context_; FullscreenController fullscreen_controller_; MouseLockController mouse_lock_controller_;
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc index 0209cfc..8f0f7fc 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc +++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
@@ -9,10 +9,9 @@ #include "base/message_loop/message_loop.h" #include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/download/download_shelf.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.h" #include "chrome/browser/ui/status_bubble.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -37,9 +36,8 @@ using content::RenderViewHost; using content::WebContents; -FullscreenController::FullscreenController(ExclusiveAccessManager* manager, - Browser* browser) - : ExclusiveAccessControllerBase(manager, browser), +FullscreenController::FullscreenController(ExclusiveAccessManager* manager) + : ExclusiveAccessControllerBase(manager), state_prior_to_tab_fullscreen_(STATE_INVALID), tab_fullscreen_accepted_(false), toggled_into_fullscreen_(false), @@ -52,7 +50,8 @@ } bool FullscreenController::IsFullscreenForBrowser() const { - return browser()->window()->IsFullscreen() && !IsFullscreenCausedByTab(); + return exclusive_access_manager()->context()->IsFullscreen() && + !IsFullscreenCausedByTab(); } void FullscreenController::ToggleBrowserFullscreenMode() { @@ -92,7 +91,7 @@ const WebContents* web_contents) const { if (web_contents == exclusive_access_tab()) { DCHECK(web_contents == - browser()->tab_strip_model()->GetActiveWebContents()); + exclusive_access_manager()->context()->GetActiveWebContents()); DCHECK(web_contents->GetCapturerCount() == 0); return true; } @@ -113,7 +112,8 @@ return; } - if (web_contents != browser()->tab_strip_model()->GetActiveWebContents() || + if (web_contents != + exclusive_access_manager()->context()->GetActiveWebContents() || IsWindowFullscreenForTabOrPending()) { return; } @@ -130,18 +130,19 @@ SetTabWithExclusiveAccess(web_contents); fullscreened_origin_ = origin; - BrowserWindow* window = browser()->window(); + ExclusiveAccessContext* exclusive_access_context = + exclusive_access_manager()->context(); - if (!window->IsFullscreen()) { + if (!exclusive_access_context->IsFullscreen()) { // Normal -> Tab Fullscreen. state_prior_to_tab_fullscreen_ = STATE_NORMAL; ToggleFullscreenModeInternal(TAB); return; } - if (window->IsFullscreenWithToolbar()) { + if (exclusive_access_context->IsFullscreenWithToolbar()) { // Browser Fullscreen with Toolbar -> Tab Fullscreen (no toolbar). - window->UpdateFullscreenWithToolbar(false); + exclusive_access_context->UpdateFullscreenWithToolbar(false); state_prior_to_tab_fullscreen_ = STATE_BROWSER_FULLSCREEN_WITH_TOOLBAR; } else { // Browser Fullscreen without Toolbar -> Tab Fullscreen. @@ -181,8 +182,10 @@ return; #endif - BrowserWindow* window = browser()->window(); - if (!window->IsFullscreen()) + ExclusiveAccessContext* exclusive_access_context = + exclusive_access_manager()->context(); + + if (!exclusive_access_context->IsFullscreen()) return; if (IsFullscreenCausedByTab()) { @@ -194,7 +197,7 @@ // Tab Fullscreen -> Browser Fullscreen (with or without toolbar). if (state_prior_to_tab_fullscreen_ == STATE_BROWSER_FULLSCREEN_WITH_TOOLBAR) { // Tab Fullscreen (no toolbar) -> Browser Fullscreen with Toolbar. - window->UpdateFullscreenWithToolbar(true); + exclusive_access_context->UpdateFullscreenWithToolbar(true); } #if defined(OS_MACOSX) @@ -214,20 +217,16 @@ PostFullscreenChangeNotification(true); } -bool FullscreenController::IsInMetroSnapMode() { #if defined(OS_WIN) - return browser()->window()->IsInMetroSnapMode(); -#else - return false; -#endif +bool FullscreenController::IsInMetroSnapMode() { + return exclusive_access_manager()->context()->IsInMetroSnapMode(); } -#if defined(OS_WIN) void FullscreenController::SetMetroSnapMode(bool enable) { reentrant_window_state_change_call_check_ = false; toggled_into_fullscreen_ = false; - browser()->window()->SetMetroSnapMode(enable); + exclusive_access_manager()->context()->SetMetroSnapMode(enable); // FullscreenController unit tests for metro snap assume that on Windows calls // to WindowFullscreenStateChanged are reentrant. If that assumption is @@ -278,28 +277,24 @@ void FullscreenController::WindowFullscreenStateChanged() { reentrant_window_state_change_call_check_ = true; - - BrowserWindow* const window = browser()->window(); - bool exiting_fullscreen = !window->IsFullscreen(); + ExclusiveAccessContext* const exclusive_access_context = + exclusive_access_manager()->context(); + bool exiting_fullscreen = !exclusive_access_context->IsFullscreen(); PostFullscreenChangeNotification(!exiting_fullscreen); if (exiting_fullscreen) { toggled_into_fullscreen_ = false; extension_caused_fullscreen_ = GURL(); NotifyTabExclusiveAccessLost(); - } - if (exiting_fullscreen) { - window->GetDownloadShelf()->Unhide(); + exclusive_access_context->UnhideDownloadShelf(); } else { - window->GetDownloadShelf()->Hide(); - if (window->GetStatusBubble()) - window->GetStatusBubble()->Hide(); + exclusive_access_context->HideDownloadShelf(); } } bool FullscreenController::HandleUserPressedEscape() { WebContents* const active_web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); + exclusive_access_manager()->context()->GetActiveWebContents(); if (IsFullscreenForCapturedTab(active_web_contents)) { active_web_contents->ExitFullscreen(); return true; @@ -355,8 +350,10 @@ // TODO(estark): Revisit this when crbug.com/455882 is fixed. if (!requester.SchemeIsFile() && !embedder.SchemeIsFile() && primary_pattern.IsValid() && secondary_pattern.IsValid()) { - HostContentSettingsMap* settings_map = - profile()->GetHostContentSettingsMap(); + HostContentSettingsMap* settings_map = exclusive_access_manager() + ->context() + ->GetProfile() + ->GetHostContentSettingsMap(); settings_map->SetContentSetting( primary_pattern, secondary_pattern, CONTENT_SETTINGS_TYPE_FULLSCREEN, std::string(), CONTENT_SETTING_ALLOW); @@ -426,23 +423,27 @@ return; #endif - BrowserWindow* const window = browser()->window(); - bool enter_fullscreen = !window->IsFullscreen(); + ExclusiveAccessContext* const exclusive_access_context = + exclusive_access_manager()->context(); + bool enter_fullscreen = !exclusive_access_context->IsFullscreen(); // When a Mac user requests a toggle they may be toggling between // FullscreenWithoutChrome and FullscreenWithToolbar. - if (window->IsFullscreen() && !IsWindowFullscreenForTabOrPending() && - window->SupportsFullscreenWithToolbar()) { + if (exclusive_access_context->IsFullscreen() && + !IsWindowFullscreenForTabOrPending() && + exclusive_access_context->SupportsFullscreenWithToolbar()) { if (option == BROWSER_WITH_TOOLBAR) { - enter_fullscreen = enter_fullscreen || !window->IsFullscreenWithToolbar(); + enter_fullscreen = enter_fullscreen || + !exclusive_access_context->IsFullscreenWithToolbar(); } else { - enter_fullscreen = enter_fullscreen || window->IsFullscreenWithToolbar(); + enter_fullscreen = enter_fullscreen || + exclusive_access_context->IsFullscreenWithToolbar(); } } // In kiosk mode, we always want to be fullscreen. When the browser first // starts we're not yet fullscreen, so let the initial toggle go through. - if (chrome::IsRunningInAppMode() && window->IsFullscreen()) + if (chrome::IsRunningInAppMode() && exclusive_access_context->IsFullscreen()) return; #if !defined(OS_MACOSX) @@ -450,7 +451,8 @@ // from manually entering fullscreen mode and also disables kiosk mode on // desktop platforms. if (enter_fullscreen && - !profile()->GetPrefs()->GetBoolean(prefs::kFullscreenAllowed)) { + !exclusive_access_context->GetProfile()->GetPrefs()->GetBoolean( + prefs::kFullscreenAllowed)) { return; } #endif @@ -478,7 +480,7 @@ // TODO(scheib): Record metrics for WITH_TOOLBAR, without counting transitions // from tab fullscreen out to browser with toolbar. - browser()->window()->EnterFullscreen( + exclusive_access_manager()->context()->EnterFullscreen( url, exclusive_access_manager()->GetExclusiveAccessExitBubbleType(), option == BROWSER_WITH_TOOLBAR); @@ -498,7 +500,7 @@ // state_prior_to_tab_fullscreen_ will be incorrect. NotifyTabExclusiveAccessLost(); #endif - browser()->window()->ExitFullscreen(); + exclusive_access_manager()->context()->ExitFullscreen(); extension_caused_fullscreen_ = GURL(); exclusive_access_manager()->UpdateExclusiveAccessExitBubbleContent(); @@ -520,17 +522,23 @@ // If the permission was granted to the website with no embedder, it should // always be allowed, even if embedded. - if (profile()->GetHostContentSettingsMap()->GetContentSetting( - url, url, CONTENT_SETTINGS_TYPE_FULLSCREEN, std::string()) == - CONTENT_SETTING_ALLOW) { + if (exclusive_access_manager() + ->context() + ->GetProfile() + ->GetHostContentSettingsMap() + ->GetContentSetting(url, url, CONTENT_SETTINGS_TYPE_FULLSCREEN, + std::string()) == CONTENT_SETTING_ALLOW) { return CONTENT_SETTING_ALLOW; } // See the comment above the call to |SetContentSetting()| for how the // requesting and embedding origins interact with each other wrt permissions. - return profile()->GetHostContentSettingsMap()->GetContentSetting( - url, GetEmbeddingOrigin(), CONTENT_SETTINGS_TYPE_FULLSCREEN, - std::string()); + return exclusive_access_manager() + ->context() + ->GetProfile() + ->GetHostContentSettingsMap() + ->GetContentSetting(url, GetEmbeddingOrigin(), + CONTENT_SETTINGS_TYPE_FULLSCREEN, std::string()); } bool FullscreenController::IsPrivilegedFullscreenForTab() const {
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.h b/chrome/browser/ui/exclusive_access/fullscreen_controller.h index 763591f..64202e3f 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_controller.h +++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.h
@@ -49,7 +49,7 @@ // This class implements fullscreen behaviour. class FullscreenController : public ExclusiveAccessControllerBase { public: - FullscreenController(ExclusiveAccessManager* manager, Browser* browser); + explicit FullscreenController(ExclusiveAccessManager* manager); ~FullscreenController() override; // Browser/User Fullscreen /////////////////////////////////////////////////// @@ -116,14 +116,14 @@ // Platform Fullscreen /////////////////////////////////////////////////////// +#if defined(OS_WIN) // Returns whether we are currently in a Metro snap view. bool IsInMetroSnapMode(); -#if defined(OS_WIN) // API that puts the window into a mode suitable for rendering when Chrome // is rendered in a 20% screen-width Metro snap view on Windows 8. void SetMetroSnapMode(bool enable); -#endif +#endif // OS_WIN // Overrde from ExclusiveAccessControllerBase. void OnTabDetachedFromView(content::WebContents* web_contents) override;
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.cc index 0a6fbc5..a8af8b3 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.cc +++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.cc
@@ -753,10 +753,13 @@ EXPECT_EQ(GetFullscreenController()->IsWindowFullscreenForTabOrPending(), !!fullscreen_for_tab) << GetAndClearDebugLog(); } + +#if defined(OS_WIN) if (in_metro_snap != IN_METRO_SNAP_NO_EXPECTATION) { EXPECT_EQ(GetFullscreenController()->IsInMetroSnapMode(), !!in_metro_snap) << GetAndClearDebugLog(); } +#endif // OS_WIN } FullscreenController* FullscreenControllerStateTest::GetFullscreenController() {
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc index 31ef2523..28e7c27 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc +++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc
@@ -6,6 +6,7 @@ #include "build/build_config.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_tabstrip.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -23,7 +24,8 @@ // A BrowserWindow used for testing FullscreenController. The behavior of this // mock is verfied manually by running FullscreenControllerStateInteractiveTest. -class FullscreenControllerTestWindow : public TestBrowserWindow { +class FullscreenControllerTestWindow : public TestBrowserWindow, + ExclusiveAccessContext { public: // Simulate the window state with an enumeration. enum WindowState { @@ -55,6 +57,16 @@ static const char* GetWindowStateString(WindowState state); WindowState state() const { return state_; } void set_browser(Browser* browser) { browser_ = browser; } + ExclusiveAccessContext* GetExclusiveAccessContext() override; + + // ExclusiveAccessContext Interface: + Profile* GetProfile() override; + content::WebContents* GetActiveWebContents() override; + void HideDownloadShelf() override; + void UnhideDownloadShelf() override; + void UpdateExclusiveAccessExitBubbleContent( + const GURL& url, + ExclusiveAccessBubbleType bubble_type) override; // Simulates the window changing state. void ChangeWindowFullscreenState(); @@ -205,6 +217,32 @@ mac_with_toolbar_mode_changed; } +ExclusiveAccessContext* +FullscreenControllerTestWindow::GetExclusiveAccessContext() { + return this; +} + +Profile* FullscreenControllerTestWindow::GetProfile() { + return browser_->profile(); +} + +content::WebContents* FullscreenControllerTestWindow::GetActiveWebContents() { + return browser_->tab_strip_model()->GetActiveWebContents(); +} + +void FullscreenControllerTestWindow::UnhideDownloadShelf() { + GetDownloadShelf()->Unhide(); +} + +void FullscreenControllerTestWindow::HideDownloadShelf() { + GetDownloadShelf()->Hide(); +} + +void FullscreenControllerTestWindow::UpdateExclusiveAccessExitBubbleContent( + const GURL& url, + ExclusiveAccessBubbleType bubble_type) { + TestBrowserWindow::UpdateExclusiveAccessExitBubbleContent(url, bubble_type); +} // FullscreenControllerStateUnitTest ------------------------------------------- @@ -229,7 +267,7 @@ FullscreenControllerTestWindow* window_; }; -FullscreenControllerStateUnitTest::FullscreenControllerStateUnitTest () +FullscreenControllerStateUnitTest::FullscreenControllerStateUnitTest() : window_(NULL) { } @@ -316,7 +354,6 @@ return BrowserWithTestWindowTest::browser(); } - // Soak tests ------------------------------------------------------------------ // Tests all states with all permutations of multiple events to detect lingering
diff --git a/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc b/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc index 01a986b9..8e3afb9 100644 --- a/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc +++ b/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc
@@ -7,6 +7,8 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "content/public/browser/notification_service.h" @@ -17,9 +19,8 @@ using content::RenderViewHost; using content::WebContents; -MouseLockController::MouseLockController(ExclusiveAccessManager* manager, - Browser* browser) - : ExclusiveAccessControllerBase(manager, browser), +MouseLockController::MouseLockController(ExclusiveAccessManager* manager) + : ExclusiveAccessControllerBase(manager), mouse_lock_state_(MOUSELOCK_NOT_REQUESTED) { } @@ -136,8 +137,10 @@ if (mouse_lock && !IsMouseLocked()) { DCHECK(IsMouseLockRequested()); - HostContentSettingsMap* settings_map = - profile()->GetHostContentSettingsMap(); + HostContentSettingsMap* settings_map = exclusive_access_manager() + ->context() + ->GetProfile() + ->GetHostContentSettingsMap(); GURL url = GetExclusiveAccessBubbleURL(); ContentSettingsPattern pattern = ContentSettingsPattern::FromURL(url); @@ -237,7 +240,10 @@ ->IsPrivilegedFullscreenForTab()) return CONTENT_SETTING_ALLOW; - HostContentSettingsMap* settings_map = profile()->GetHostContentSettingsMap(); + HostContentSettingsMap* settings_map = exclusive_access_manager() + ->context() + ->GetProfile() + ->GetHostContentSettingsMap(); return settings_map->GetContentSetting( url, url, CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string()); }
diff --git a/chrome/browser/ui/exclusive_access/mouse_lock_controller.h b/chrome/browser/ui/exclusive_access/mouse_lock_controller.h index 27cede2..43c89f2 100644 --- a/chrome/browser/ui/exclusive_access/mouse_lock_controller.h +++ b/chrome/browser/ui/exclusive_access/mouse_lock_controller.h
@@ -11,7 +11,7 @@ // This class implements mouselock behavior. class MouseLockController : public ExclusiveAccessControllerBase { public: - MouseLockController(ExclusiveAccessManager* manager, Browser* browser); + explicit MouseLockController(ExclusiveAccessManager* manager); ~MouseLockController() override; bool IsMouseLocked() const;
diff --git a/chrome/browser/ui/libgtk2ui/BUILD.gn b/chrome/browser/ui/libgtk2ui/BUILD.gn index a8455be..272f8bb 100644 --- a/chrome/browser/ui/libgtk2ui/BUILD.gn +++ b/chrome/browser/ui/libgtk2ui/BUILD.gn
@@ -5,21 +5,6 @@ assert(is_linux, "This file should only be referenced on Linux") import("//build/config/features.gni") -import("//build/config/linux/pkg_config.gni") - -pkg_config("gtk") { - # Gtk requires gmodule, but it does not list it as a dependency in some - # misconfigured systems. - packages = [ - "gmodule-2.0", - "gtk+-2.0", - "gthread-2.0", - ] -} - -pkg_config("gtkprint") { - packages = [ "gtk+-unix-print-2.0" ] -} component("libgtk2ui") { sources = [ @@ -79,8 +64,6 @@ defines = [ "LIBGTK2UI_IMPLEMENTATION" ] configs += [ - ":gtk", - ":gtkprint", "//build/config/linux:gconf", "//printing:cups", ] @@ -109,6 +92,8 @@ "//base", "//base/third_party/dynamic_annotations", "//base:i18n", + "//build/config/linux/gtk", + "//build/config/linux/gtk:gtkprint", "//chrome/app/theme:theme_resources", "//chrome:extra_resources", "//chrome:resources",
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index 19fb9969..5f7eb24 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -39,6 +39,7 @@ #include "content/public/browser/web_contents.h" #if defined(OS_ANDROID) +#include "chrome/browser/android/voice_search_tab_helper.h" #include "chrome/browser/android/webapps/single_tab_mode_tab_helper.h" #include "chrome/browser/enhanced_bookmarks/android/enhanced_bookmark_tab_helper.h" #include "chrome/browser/ui/android/context_menu_helper.h" @@ -161,6 +162,7 @@ ContextMenuHelper::CreateForWebContents(web_contents); EnhancedBookmarkTabHelper::CreateForWebContents(web_contents); SingleTabModeTabHelper::CreateForWebContents(web_contents); + VoiceSearchTabHelper::CreateForWebContents(web_contents); WindowAndroidHelper::CreateForWebContents(web_contents); #else extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
diff --git a/chrome/browser/ui/views/apps/chrome_apps_client_views.cc b/chrome/browser/ui/views/apps/chrome_app_window_client_views.cc similarity index 100% rename from chrome/browser/ui/views/apps/chrome_apps_client_views.cc rename to chrome/browser/ui/views/apps/chrome_app_window_client_views.cc
diff --git a/chrome/browser/ui/views/apps/chrome_app_window_client_views_mac.mm b/chrome/browser/ui/views/apps/chrome_app_window_client_views_mac.mm new file mode 100644 index 0000000..01b5229 --- /dev/null +++ b/chrome/browser/ui/views/apps/chrome_app_window_client_views_mac.mm
@@ -0,0 +1,16 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/apps/chrome_app_window_client.h" + +#include "chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h" + +// static +extensions::NativeAppWindow* ChromeAppWindowClient::CreateNativeAppWindowImpl( + extensions::AppWindow* app_window, + const extensions::AppWindow::CreateParams& params) { + ChromeNativeAppWindowViewsMac* window = new ChromeNativeAppWindowViewsMac; + window->Init(app_window, params); + return window; +}
diff --git a/chrome/browser/ui/views/apps/chrome_apps_client_views_win.cc b/chrome/browser/ui/views/apps/chrome_app_window_client_views_win.cc similarity index 100% rename from chrome/browser/ui/views/apps/chrome_apps_client_views_win.cc rename to chrome/browser/ui/views/apps/chrome_app_window_client_views_win.cc
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h new file mode 100644 index 0000000..96cc301 --- /dev/null +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h
@@ -0,0 +1,36 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_APPS_CHROME_NATIVE_APP_WINDOW_VIEWS_MAC_H_ +#define CHROME_BROWSER_UI_VIEWS_APPS_CHROME_NATIVE_APP_WINDOW_VIEWS_MAC_H_ + +#include "chrome/browser/ui/views/apps/chrome_native_app_window_views.h" + +// Mac-specific parts of ChromeNativeAppWindowViews. +class ChromeNativeAppWindowViewsMac : public ChromeNativeAppWindowViews { + public: + ChromeNativeAppWindowViewsMac(); + ~ChromeNativeAppWindowViewsMac() override; + + protected: + // ui::BaseWindow implementation. + void Show() override; + void ShowInactive() override; + + // NativeAppWindow implementation. + // 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 + // differentiate the reason a window was hidden. + void ShowWithApp() override; + void HideWithApp() override; + + private: + // Whether this window last became hidden due to a request to hide the entire + // app, e.g. via the dock menu or Cmd+H. This is set by Hide/ShowWithApp. + bool is_hidden_with_app_; + + DISALLOW_COPY_AND_ASSIGN(ChromeNativeAppWindowViewsMac); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_APPS_CHROME_NATIVE_APP_WINDOW_VIEWS_MAC_H_
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.mm b/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.mm new file mode 100644 index 0000000..4920ac7 --- /dev/null +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.mm
@@ -0,0 +1,45 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h" + +#include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h" + +ChromeNativeAppWindowViewsMac::ChromeNativeAppWindowViewsMac() + : is_hidden_with_app_(false) { +} + +ChromeNativeAppWindowViewsMac::~ChromeNativeAppWindowViewsMac() { +} + +void ChromeNativeAppWindowViewsMac::Show() { + if (is_hidden_with_app_) { + // If there is a shim to gently request attention, return here. Otherwise + // show the window as usual. + if (apps::ExtensionAppShimHandler::ActivateAndRequestUserAttentionForWindow( + app_window())) { + return; + } + } + + ChromeNativeAppWindowViews::Show(); +} + +void ChromeNativeAppWindowViewsMac::ShowInactive() { + if (is_hidden_with_app_) + return; + + ChromeNativeAppWindowViews::ShowInactive(); +} + +void ChromeNativeAppWindowViewsMac::ShowWithApp() { + is_hidden_with_app_ = false; + if (!app_window()->is_hidden()) + ShowInactive(); +} + +void ChromeNativeAppWindowViewsMac::HideWithApp() { + is_hidden_with_app_ = true; + ChromeNativeAppWindowViews::Hide(); +}
diff --git a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc index 83223c6..e5903371 100644 --- a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc +++ b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc
@@ -11,6 +11,9 @@ #include "chrome/browser/ui/views/autofill/decorated_textfield.h" #include "chrome/grit/generated_resources.h" #include "components/constrained_window/constrained_window_views.h" +#include "components/web_modal/web_contents_modal_dialog_host.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" #include "grit/theme_resources.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/l10n/l10n_util.h" @@ -70,29 +73,48 @@ Layout(); } - void GotVerificationResult(bool success) override { - if (success) { + void GotVerificationResult(const base::string16& error_message, + bool allow_retry) override { + if (!error_message.empty()) { progress_label_->SetText(base::ASCIIToUTF16("Success!")); base::MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&CardUnmaskPromptViews::ClosePrompt, base::Unretained(this)), base::TimeDelta::FromSeconds(1)); } else { - SetInputsEnabled(true); - SetInputsInvalid(true); + SetInputsEnabled(allow_retry); + + // If there is more than one input showing, don't mark anything as invalid + // since we don't know the location of the problem. + if (controller_->ShouldRequestExpirationDate()) + cvc_input_->SetInvalid(true); + // TODO(estade): it's somewhat jarring when the error comes back too // quickly. progress_overlay_->SetVisible(false); // TODO(estade): When do we hide |error_label_|? - error_label_->SetText( - base::ASCIIToUTF16("Verification error. Please try again.")); + error_label_->SetMultiLine(true); + error_label_->SetText(error_message); + + // Update the dialog's size, which may change depending on + // |error_message|. + if (GetWidget() && controller_->GetWebContents()) { + constrained_window::UpdateWebContentsModalDialogPosition( + GetWidget(), + web_modal::WebContentsModalDialogManager::FromWebContents( + controller_->GetWebContents()) + ->delegate() + ->GetWebContentsModalDialogHost()); + } GetDialogClientView()->UpdateDialogButtons(); } + Layout(); } void SetInputsEnabled(bool enabled) { cvc_input_->SetEnabled(enabled); + storage_checkbox_->SetEnabled(enabled); if (month_input_) month_input_->SetEnabled(enabled); @@ -100,15 +122,6 @@ year_input_->SetEnabled(enabled); } - void SetInputsInvalid(bool invalid) { - cvc_input_->SetInvalid(invalid); - - if (month_input_) - month_input_->SetInvalid(invalid); - if (year_input_) - year_input_->SetInvalid(invalid); - } - // views::DialogDelegateView View* GetContentsView() override { InitIfNecessary(); @@ -120,7 +133,7 @@ // Must hardcode a width so the label knows where to wrap. TODO(estade): // This can lead to a weird looking dialog if we end up getting allocated // more width than we ask for, e.g. if the title is super long. - const int kWidth = 250; + const int kWidth = 450; return gfx::Size(kWidth, GetHeightForWidth(kWidth)); } @@ -209,17 +222,13 @@ // views::TextfieldController void ContentsChanged(views::Textfield* sender, const base::string16& new_contents) override { - // Sets all inputs back to valid since we don't know which one was - // actually invalid to begin with. - SetInputsInvalid(false); + cvc_input_->SetInvalid(false); GetDialogClientView()->UpdateDialogButtons(); } // views::ComboboxListener void OnPerformAction(views::Combobox* combobox) override { - // Sets all inputs back to valid since we don't know which one was - // actually invalid to begin with. - SetInputsInvalid(false); + combobox->SetInvalid(false); GetDialogClientView()->UpdateDialogButtons(); } @@ -268,7 +277,7 @@ input_row->AddChildView(cvc_image); - // Reserve vertical space. + // Reserve vertical space for the error label, assuming it's one line. error_label_ = new views::Label(base::ASCIIToUTF16(" ")); error_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); error_label_->SetEnabledColor(kWarningColor);
diff --git a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc index 37b6391..3b20f0e 100644 --- a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc +++ b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
@@ -125,7 +125,7 @@ // ConstrainedWebDialogDelegate: web_modal::NativeWebContentsModalDialog GetNativeDialog() override { - return view_->GetWidget()->GetNativeView(); + return view_->GetWidget()->GetNativeWindow(); } private: @@ -246,7 +246,7 @@ web_modal::PopupManager* popup_manager = web_modal::PopupManager::FromWebContents( initiator_observer_.web_contents()); - popup_manager->ShowModalDialog(GetWidget()->GetNativeView(), + popup_manager->ShowModalDialog(GetWidget()->GetNativeWindow(), initiator_observer_.web_contents()); } }
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc index 457e4d49f..0502116 100644 --- a/chrome/browser/ui/views/download/download_item_view.cc +++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -274,6 +274,11 @@ void DownloadItemView::OnDownloadUpdated(DownloadItem* download_item) { DCHECK_EQ(download(), download_item); + if (!model_.ShouldShowInShelf()) { + shelf_->RemoveDownloadView(this); // This will delete us! + return; + } + if (IsShowingWarningDialog() && !model_.IsDangerous()) { // We have been approved. ClearWarningDialog(); @@ -1029,10 +1034,9 @@ weak_ptr_factory_.GetWeakPtr())); views::View::ConvertPointToScreen(this, &point); - if (!context_menu_.get()) { - context_menu_.reset( - new DownloadShelfContextMenuView(download(), shelf_->GetNavigator())); - } + if (!context_menu_.get()) + context_menu_.reset(new DownloadShelfContextMenuView(download())); + context_menu_->Run(GetWidget()->GetTopLevelWidget(), gfx::Rect(point, size), source_type); // We could be deleted now.
diff --git a/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc b/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc index 94b6f362..26cf968 100644 --- a/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc +++ b/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc
@@ -13,9 +13,8 @@ #include "ui/views/controls/menu/menu_runner.h" DownloadShelfContextMenuView::DownloadShelfContextMenuView( - content::DownloadItem* download_item, - content::PageNavigator* navigator) - : DownloadShelfContextMenu(download_item, navigator) { + content::DownloadItem* download_item) + : DownloadShelfContextMenu(download_item) { } DownloadShelfContextMenuView::~DownloadShelfContextMenuView() {}
diff --git a/chrome/browser/ui/views/download/download_shelf_context_menu_view.h b/chrome/browser/ui/views/download/download_shelf_context_menu_view.h index 98d7ab8..09c94a1d 100644 --- a/chrome/browser/ui/views/download/download_shelf_context_menu_view.h +++ b/chrome/browser/ui/views/download/download_shelf_context_menu_view.h
@@ -28,8 +28,7 @@ class DownloadShelfContextMenuView : public DownloadShelfContextMenu { public: - DownloadShelfContextMenuView(content::DownloadItem* download_item, - content::PageNavigator* navigator); + explicit DownloadShelfContextMenuView(content::DownloadItem* download_item); ~DownloadShelfContextMenuView() override; base::TimeTicks close_time() const { return close_time_; }
diff --git a/chrome/browser/ui/views/download/download_shelf_view.cc b/chrome/browser/ui/views/download/download_shelf_view.cc index 9f7d42c..4b6552b 100644 --- a/chrome/browser/ui/views/download/download_shelf_view.cc +++ b/chrome/browser/ui/views/download/download_shelf_view.cc
@@ -127,8 +127,7 @@ } void DownloadShelfView::DoAddDownload(DownloadItem* download) { - DownloadItemView* view = new DownloadItemView(download, this); - AddDownloadView(view); + AddDownloadView(new DownloadItemView(download, this)); } void DownloadShelfView::MouseMovedOutOfHost() {
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.cc b/chrome/browser/ui/views/exclusive_access_bubble_views.cc index 88035ff..0a0e4d8 100644 --- a/chrome/browser/ui/views/exclusive_access_bubble_views.cc +++ b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
@@ -10,7 +10,7 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" -#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/exclusive_access_bubble_views_context.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" #include "chrome/browser/ui/views/frame/top_container_view.h" #include "chrome/grit/generated_resources.h" @@ -57,7 +57,6 @@ private: views::LabelButton* accept_button_; views::LabelButton* deny_button_; - DISALLOW_COPY_AND_ASSIGN(ButtonView); }; @@ -208,7 +207,7 @@ void ExclusiveAccessBubbleViews::ExclusiveAccessView::LinkClicked( views::Link* link, int event_flags) { - bubble_->ToggleFullscreen(); + bubble_->ExitExclusiveAccess(); } void ExclusiveAccessBubbleViews::ExclusiveAccessView::UpdateContent( @@ -257,11 +256,13 @@ // ExclusiveAccessBubbleViews -------------------------------------------------- ExclusiveAccessBubbleViews::ExclusiveAccessBubbleViews( - BrowserView* browser_view, + ExclusiveAccessBubbleViewsContext* context, const GURL& url, ExclusiveAccessBubbleType bubble_type) - : ExclusiveAccessBubble(browser_view->browser(), url, bubble_type), - browser_view_(browser_view), + : ExclusiveAccessBubble(context->GetExclusiveAccessManager(), + url, + bubble_type), + bubble_view_context_(context), popup_(NULL), animation_(new gfx::SlideAnimation(this)), animated_attribute_(ANIMATED_ATTRIBUTE_BOUNDS) { @@ -270,7 +271,8 @@ // Create the contents view. ui::Accelerator accelerator(ui::VKEY_UNKNOWN, ui::EF_NONE); bool got_accelerator = - browser_view_->GetWidget()->GetAccelerator(IDC_FULLSCREEN, &accelerator); + bubble_view_context_->GetBubbleAssociatedWidget()->GetAccelerator( + IDC_FULLSCREEN, &accelerator); DCHECK(got_accelerator); view_ = new ExclusiveAccessView(this, accelerator.GetShortcutText(), url, bubble_type_); @@ -283,7 +285,8 @@ views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.parent = browser_view_->GetWidget()->GetNativeView(); + params.parent = + bubble_view_context_->GetBubbleAssociatedWidget()->GetNativeView(); params.bounds = GetPopupRect(false); popup_->Init(params); gfx::Size size = GetPopupRect(true).size(); @@ -298,11 +301,10 @@ popup_->AddObserver(this); - registrar_.Add( - this, chrome::NOTIFICATION_FULLSCREEN_CHANGED, - content::Source<FullscreenController>(browser_view_->browser() - ->exclusive_access_manager() - ->fullscreen_controller())); + registrar_.Add(this, chrome::NOTIFICATION_FULLSCREEN_CHANGED, + content::Source<FullscreenController>( + bubble_view_context_->GetExclusiveAccessManager() + ->fullscreen_controller())); UpdateForImmersiveState(); } @@ -371,7 +373,7 @@ void ExclusiveAccessBubbleViews::UpdateForImmersiveState() { AnimatedAttribute expected_animated_attribute = - browser_view_->immersive_mode_controller()->IsEnabled() + bubble_view_context_->IsImmersiveModeEnabled() ? ANIMATED_ATTRIBUTE_OPACITY : ANIMATED_ATTRIBUTE_BOUNDS; if (animated_attribute_ != expected_animated_attribute) { @@ -403,7 +405,7 @@ } views::View* ExclusiveAccessBubbleViews::GetBrowserRootView() const { - return browser_view_->GetWidget()->GetRootView(); + return bubble_view_context_->GetBubbleAssociatedWidget()->GetRootView(); } void ExclusiveAccessBubbleViews::AnimationProgressed( @@ -436,15 +438,16 @@ gfx::Size size(view_->GetPreferredSize()); // NOTE: don't use the bounds of the root_view_. On linux GTK changing window // size is async. Instead we use the size of the screen. - gfx::Screen* screen = - gfx::Screen::GetScreenFor(browser_view_->GetWidget()->GetNativeView()); + gfx::Screen* screen = gfx::Screen::GetScreenFor( + bubble_view_context_->GetBubbleAssociatedWidget()->GetNativeView()); gfx::Rect screen_bounds = screen->GetDisplayNearestWindow( - browser_view_->GetWidget()->GetNativeView()).bounds(); + bubble_view_context_->GetBubbleAssociatedWidget() + ->GetNativeView()).bounds(); int x = screen_bounds.x() + (screen_bounds.width() - size.width()) / 2; int top_container_bottom = screen_bounds.y(); - if (browser_view_->immersive_mode_controller()->IsEnabled()) { + if (bubble_view_context_->IsImmersiveModeEnabled()) { // Skip querying the top container height in non-immersive fullscreen // because: // - The top container height is always zero in non-immersive fullscreen. @@ -455,7 +458,7 @@ // revealed. When revealed, the top container has the same height as before // entering fullscreen. top_container_bottom = - browser_view_->top_container()->GetBoundsInScreen().bottom(); + bubble_view_context_->GetTopContainerBoundsInScreen().bottom(); } int y = top_container_bottom + kPopupTopPx; @@ -472,7 +475,8 @@ gfx::Point ExclusiveAccessBubbleViews::GetCursorScreenPoint() { gfx::Point cursor_pos = - gfx::Screen::GetScreenFor(browser_view_->GetWidget()->GetNativeView()) + gfx::Screen::GetScreenFor( + bubble_view_context_->GetBubbleAssociatedWidget()->GetNativeView()) ->GetCursorScreenPoint(); views::View::ConvertPointFromScreen(GetBrowserRootView(), &cursor_pos); return cursor_pos; @@ -483,7 +487,7 @@ } bool ExclusiveAccessBubbleViews::IsWindowActive() { - return browser_view_->GetWidget()->IsActive(); + return bubble_view_context_->GetBubbleAssociatedWidget()->IsActive(); } void ExclusiveAccessBubbleViews::Hide() { @@ -501,7 +505,7 @@ } bool ExclusiveAccessBubbleViews::CanMouseTriggerSlideIn() const { - return !browser_view_->immersive_mode_controller()->IsEnabled(); + return !bubble_view_context_->IsImmersiveModeEnabled(); } void ExclusiveAccessBubbleViews::Observe(
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.h b/chrome/browser/ui/views/exclusive_access_bubble_views.h index 5b187bd..9014616 100644 --- a/chrome/browser/ui/views/exclusive_access_bubble_views.h +++ b/chrome/browser/ui/views/exclusive_access_bubble_views.h
@@ -12,7 +12,7 @@ #include "content/public/browser/notification_registrar.h" #include "ui/views/widget/widget_observer.h" -class BrowserView; +class ExclusiveAccessBubbleViewsContext; class GURL; namespace gfx { class SlideAnimation; @@ -30,7 +30,7 @@ public content::NotificationObserver, public views::WidgetObserver { public: - ExclusiveAccessBubbleViews(BrowserView* browser, + ExclusiveAccessBubbleViews(ExclusiveAccessBubbleViewsContext* context, const GURL& url, ExclusiveAccessBubbleType bubble_type); ~ExclusiveAccessBubbleViews() override; @@ -82,7 +82,7 @@ // views::WidgetObserver override: void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override; - BrowserView* browser_view_; + ExclusiveAccessBubbleViewsContext* const bubble_view_context_; views::Widget* popup_;
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views_context.h b/chrome/browser/ui/views/exclusive_access_bubble_views_context.h new file mode 100644 index 0000000..5d0f3d45 --- /dev/null +++ b/chrome/browser/ui/views/exclusive_access_bubble_views_context.h
@@ -0,0 +1,35 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef CHROME_BROWSER_UI_VIEWS_EXCLUSIVE_ACCESS_BUBBLE_VIEWS_CONTEXT_H_ +#define CHROME_BROWSER_UI_VIEWS_EXCLUSIVE_ACCESS_BUBBLE_VIEWS_CONTEXT_H_ + +#include "ui/gfx/geometry/rect.h" + +class ExclusiveAccessManager; + +namespace views { +class Widget; +} + +// Context in which the exclusive access bubble view is initiated. +class ExclusiveAccessBubbleViewsContext { + public: + virtual ~ExclusiveAccessBubbleViewsContext() {} + + // Returns ExclusiveAccessManager controlling exclusive access for the given + // webview. + virtual ExclusiveAccessManager* GetExclusiveAccessManager() = 0; + + // Returns the Widget that hosts the view containing the exclusive access + // bubble. + virtual views::Widget* GetBubbleAssociatedWidget() = 0; + + // Returns true if immersive mode is enabled. + virtual bool IsImmersiveModeEnabled() = 0; + + // Returns the bounds of the top level View in screen coordinate system. + virtual gfx::Rect GetTopContainerBoundsInScreen() = 0; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_EXCLUSIVE_ACCESS_BUBBLE_VIEWS_CONTEXT_H_
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 33ee5a13..b86f397 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -946,7 +946,7 @@ EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE); } -void BrowserView::UpdateFullscreenExitBubbleContent( +void BrowserView::UpdateExclusiveAccessExitBubbleContent( const GURL& url, ExclusiveAccessBubbleType bubble_type) { // Immersive mode has no exit bubble because it has a visible strip at the @@ -2280,7 +2280,7 @@ if (fullscreen && !chrome::IsRunningInAppMode() && mode != METRO_SNAP_FULLSCREEN) { - UpdateFullscreenExitBubbleContent(url, bubble_type); + UpdateExclusiveAccessExitBubbleContent(url, bubble_type); } // Undo our anti-jankiness hacks and force a re-layout. We also need to @@ -2502,6 +2502,10 @@ toolbar_->ExecuteExtensionCommand(extension, command); } +ExclusiveAccessContext* BrowserView::GetExclusiveAccessContext() { + return this; +} + void BrowserView::DoCutCopyPaste(void (WebContents::*method)(), int command_id) { WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents(); @@ -2568,3 +2572,42 @@ } return top_arrow_height; } + +/////////////////////////////////////////////////////////////////////////////// +// BrowserView, ExclusiveAccessContext overrides +Profile* BrowserView::GetProfile() { + return browser_->profile(); +} + +WebContents* BrowserView::GetActiveWebContents() { + return browser_->tab_strip_model()->GetActiveWebContents(); +} + +void BrowserView::UnhideDownloadShelf() { + GetDownloadShelf()->Unhide(); +} + +void BrowserView::HideDownloadShelf() { + GetDownloadShelf()->Hide(); + StatusBubble* statusBubble = GetStatusBubble(); + if (statusBubble) + statusBubble->Hide(); +} + +/////////////////////////////////////////////////////////////////////////////// +// BrowserView, ExclusiveAccessBubbleViewsContext overrides +ExclusiveAccessManager* BrowserView::GetExclusiveAccessManager() { + return browser_->exclusive_access_manager(); +} + +bool BrowserView::IsImmersiveModeEnabled() { + return immersive_mode_controller()->IsEnabled(); +} + +views::Widget* BrowserView::GetBubbleAssociatedWidget() { + return GetWidget(); +} + +gfx::Rect BrowserView::GetTopContainerBoundsInScreen() { + return top_container_->GetBoundsInScreen(); +}
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h index a85e479b..de510a0 100644 --- a/chrome/browser/ui/views/frame/browser_view.h +++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -17,9 +17,11 @@ #include "chrome/browser/signin/signin_header_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" #include "chrome/browser/ui/infobar_container_delegate.h" #include "chrome/browser/ui/omnibox/omnibox_popup_model_observer.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" +#include "chrome/browser/ui/views/exclusive_access_bubble_views_context.h" #include "chrome/browser/ui/views/frame/browser_frame.h" #include "chrome/browser/ui/views/frame/contents_web_view.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" @@ -85,7 +87,9 @@ public views::ClientView, public InfoBarContainerDelegate, public LoadCompleteListener::Delegate, - public OmniboxPopupModelObserver { + public OmniboxPopupModelObserver, + public ExclusiveAccessContext, + public ExclusiveAccessBubbleViewsContext { public: // The browser view's class name. static const char kViewClassName[]; @@ -275,7 +279,7 @@ ExclusiveAccessBubbleType bubble_type, bool with_toolbar) override; void ExitFullscreen() override; - void UpdateFullscreenExitBubbleContent( + void UpdateExclusiveAccessExitBubbleContent( const GURL& url, ExclusiveAccessBubbleType bubble_type) override; bool ShouldHideUIForFullscreen() const override; @@ -285,9 +289,9 @@ void UpdateFullscreenWithToolbar(bool with_toolbar) override; bool IsFullscreenWithToolbar() const override; #if defined(OS_WIN) - virtual void SetMetroSnapMode(bool enable) override; - virtual bool IsInMetroSnapMode() const override; -#endif + void SetMetroSnapMode(bool enable) override; + bool IsInMetroSnapMode() const override; +#endif // defined(OS_WIN) LocationBar* GetLocationBar() const override; void SetFocusToLocationBar(bool select_all) override; void UpdateReloadStopState(bool is_loading, bool force) override; @@ -361,6 +365,7 @@ int GetRenderViewHeightInsetWithDetachedBookmarkBar() override; void ExecuteExtensionCommand(const extensions::Extension* extension, const extensions::Command& command) override; + ExclusiveAccessContext* GetExclusiveAccessContext() override; BookmarkBarView* GetBookmarkBarView() const; LocationBarView* GetLocationBarView() const; @@ -438,6 +443,18 @@ // OmniboxPopupModelObserver overrides void OnOmniboxPopupShownOrHidden() override; + // ExclusiveAccessContext overrides + Profile* GetProfile() override; + content::WebContents* GetActiveWebContents() override; + void HideDownloadShelf() override; + void UnhideDownloadShelf() override; + + // ExclusiveAccessBubbleViewsContext overrides + ExclusiveAccessManager* GetExclusiveAccessManager() override; + bool IsImmersiveModeEnabled() override; + views::Widget* GetBubbleAssociatedWidget() override; + gfx::Rect GetTopContainerBoundsInScreen() override; + // Testing interface: views::View* GetContentsContainerForTest() { return contents_container_; } views::WebView* GetContentsWebViewForTest() { return contents_web_view_; }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc index fe711579..6bbacf87 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc
@@ -11,84 +11,13 @@ #include "chrome/browser/ui/views/toolbar/toolbar_action_view.h" #include "chrome/test/base/testing_profile.h" #include "content/public/test/test_browser_thread.h" -#include "content/public/test/test_renderer_host.h" -#include "content/public/test/web_contents_tester.h" +#include "content/public/test/test_web_contents_factory.h" #include "ui/accessibility/ax_view_state.h" #include "ui/events/test/event_generator.h" #include "ui/views/test/views_test_base.h" -#if defined(USE_AURA) -#include "ui/aura/env.h" -#endif - 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? ;) -// 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: - // |init_aura| initializes the aura environment (and cleans it up at - // shutdown, which is necessary for web contents. Since this method should - // only be called once, this should only be true if no other part of the test - // has initialized the environment. - explicit TestWebContentsFactory(bool init_aura); - ~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_; - - // True if the factory initialized aura (and should thus tear it down). - bool init_aura_; - - DISALLOW_COPY_AND_ASSIGN(TestWebContentsFactory); -}; - -TestWebContentsFactory::TestWebContentsFactory(bool init_aura) - : rvh_enabler_(new content::RenderViewHostTestEnabler()), - init_aura_(init_aura) { -#if defined(USE_AURA) - if (init_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) - if (init_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(); -} - // A test delegate for a toolbar action view. class TestToolbarActionViewDelegate : public ToolbarActionView::Delegate { public: @@ -181,7 +110,7 @@ TestingProfile profile; // ViewsTestBase initializees the aura environment, so the factory shouldn't. - TestWebContentsFactory web_contents_factory(false); + content::TestWebContentsFactory web_contents_factory; TestToolbarActionViewController controller("fake controller"); TestToolbarActionViewDelegate action_view_delegate;
diff --git a/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc b/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc index 1664dfa..f2e6930 100644 --- a/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc +++ b/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc
@@ -220,7 +220,7 @@ #endif // Will cause this object to be deleted. - native_delegate_->WillClose(widget->GetNativeView()); + native_delegate_->WillClose(widget->GetNativeWindow()); } SingleWebContentsDialogManagerDelegate* native_delegate_;
diff --git a/chrome/browser/ui/webui/app_list/start_page_browsertest.js b/chrome/browser/ui/webui/app_list/start_page_browsertest.js index 5a0511d..84869c4 100644 --- a/chrome/browser/ui/webui/app_list/start_page_browsertest.js +++ b/chrome/browser/ui/webui/app_list/start_page_browsertest.js
@@ -159,58 +159,3 @@ 'http://example.com/'); assertEquals(null, $('doodle')); }); - -TEST_F('AppListStartPageWebUITest', 'SpeechRecognitionState', function() { - this.mockHandler.expects(once()).setSpeechRecognitionState('READY'); - appList.startPage.onAppListShown(false, true); - this.mockHandler.expects(once()).setSpeechRecognitionState('RECOGNIZING'); - appList.startPage.toggleSpeechRecognition(); - Mock4JS.verifyAllMocks(); - Mock4JS.clearMocksToVerify(); - - this.mockHandler.expects(once()).setSpeechRecognitionState('READY'); - for (var i = 0; i < this.audioTrackMocks.length; ++i) { - this.audioTrackMocks[i].expects(once()).stop(); - } - appList.startPage.toggleSpeechRecognition(); - Mock4JS.verifyAllMocks(); - Mock4JS.clearMocksToVerify(); - - this.mockHandler.expects(once()).setSpeechRecognitionState('RECOGNIZING'); - appList.startPage.toggleSpeechRecognition(); - Mock4JS.verifyAllMocks(); - Mock4JS.clearMocksToVerify(); - - this.mockHandler.expects(once()).setSpeechRecognitionState('STOPPING'); - this.mockHandler.expects(once()).setSpeechRecognitionState('READY'); - for (var i = 0; i < this.audioTrackMocks.length; ++i) { - this.audioTrackMocks[i].expects(once()).stop(); - } - appList.startPage.onAppListHidden(); -}); - -TEST_F('AppListStartPageWebUITest', 'SpeechRecognition', function() { - this.mockHandler.expects(once()).setSpeechRecognitionState('READY'); - appList.startPage.onAppListShown(false, true); - this.mockHandler.expects(once()).setSpeechRecognitionState('RECOGNIZING'); - appList.startPage.toggleSpeechRecognition(); - Mock4JS.verifyAllMocks(); - Mock4JS.clearMocksToVerify(); - - this.mockHandler.expects(once()).setSpeechRecognitionState('IN_SPEECH'); - this.speechRecognizer.onspeechstart(); - Mock4JS.verifyAllMocks(); - Mock4JS.clearMocksToVerify(); - - this.mockHandler.expects(once()).speechResult('test,false'); - this.sendSpeechResult('test', false); - Mock4JS.verifyAllMocks(); - Mock4JS.clearMocksToVerify(); - - this.mockHandler.expects(once()).speechResult('test,true'); - this.mockHandler.expects(once()).setSpeechRecognitionState('READY'); - for (var i = 0; i < this.audioTrackMocks.length; ++i) { - this.audioTrackMocks[i].expects(once()).stop(); - } - this.sendSpeechResult('test', true); -});
diff --git a/chrome/browser/ui/webui/app_list/start_page_handler.cc b/chrome/browser/ui/webui/app_list/start_page_handler.cc index 7868d7d..d8234cc 100644 --- a/chrome/browser/ui/webui/app_list/start_page_handler.cc +++ b/chrome/browser/ui/webui/app_list/start_page_handler.cc
@@ -127,7 +127,7 @@ StartPageService* service = StartPageService::Get(profile); web_ui()->CallJavascriptFunction( "appList.startPage.setHotwordEnabled", - base::FundamentalValue(service->HotwordEnabled())); + base::FundamentalValue(service && service->HotwordEnabled())); } } #endif
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index 0bbbcce..4cb13b9 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -71,6 +71,7 @@ #include "content/public/common/content_client.h" #include "content/public/common/url_utils.h" #include "ui/gfx/favicon_size.h" +#include "ui/oobe/oobe_md_ui.h" #include "ui/web_dialogs/web_dialog_ui.h" #include "url/gurl.h" @@ -108,6 +109,7 @@ #endif #if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/oobe/oobe.h" #include "chrome/browser/ui/webui/chromeos/bluetooth_pairing_ui.h" #include "chrome/browser/ui/webui/chromeos/certificate_manager_dialog_ui.h" #include "chrome/browser/ui/webui/chromeos/choose_mobile_network_ui.h" @@ -206,6 +208,12 @@ WebUIController* NewWebUI<chromeos::OobeUI>(WebUI* web_ui, const GURL& url) { return new chromeos::OobeUI(web_ui, url); } + +template <> +WebUIController* NewWebUI<OobeMdUI>(WebUI* web_ui, const GURL& url) { + chromeos::Oobe::Register(); + return new OobeMdUI(web_ui, url.host()); +} #endif // Special cases for DOM distiller. @@ -428,6 +436,8 @@ return &NewWebUI<chromeos::NfcDebugUI>; if (url.host() == chrome::kChromeUIOobeHost) return &NewWebUI<chromeos::OobeUI>; + if (url.host() == chrome::kChromeUIOobeMdHost) + return &NewWebUI<OobeMdUI>; if (url.host() == chrome::kChromeUIProvidedFileSystemsHost) return &NewWebUI<chromeos::ProvidedFileSystemsUI>; if (url.host() == chrome::kChromeUIProxySettingsHost)
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc index ace8995..b5e8a5c 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -246,10 +246,12 @@ } } - if (StartupUtils::IsWebviewSigninEnabled()) { + if (!command_line->HasSwitch(::switches::kGaiaUrl) && + StartupUtils::IsWebviewSigninEnabled()) { // We can't use switch --gaia-url in this case cause we need get // auth_code from staging gaia and make all the other auths against prod // gaia so user could use all the google services. + // TODO(dpolukhin): crbug.com/462204 const GURL gaia_url = GURL(kStagingGaiaUrl); params.SetString("gaiaUrl", gaia_url.spec()); } else {
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc index 5efc7ee..4b95d6e4 100644 --- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc +++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -74,8 +74,7 @@ OobeUI::kLoginDisplay, OobeUI::kLockDisplay, OobeUI::kUserAddingDisplay, - OobeUI::kAppLaunchSplashDisplay, - OobeUI::kNewOobeDisplay + OobeUI::kAppLaunchSplashDisplay }; const char kStringsJSPath[] = "strings.js"; @@ -90,24 +89,10 @@ const char kEnrollmentCSSPath[] = "enrollment.css"; const char kEnrollmentJSPath[] = "enrollment.js"; -content::WebUIDataSource* CreateNewOobeUIDataSource( - const base::DictionaryValue& localized_strings) { - content::WebUIDataSource* source = - content::WebUIDataSource::Create(chrome::kChromeUIOobeHost); - source->AddLocalizedStrings(localized_strings); - source->SetJsonPath(kStringsJSPath); - source->SetDefaultResource(IDR_NEW_OOBE_HTML); - source->AddResourcePath(kOobeJSPath, IDR_NEW_OOBE_JS); - return source; -} - // Creates a WebUIDataSource for chrome://oobe content::WebUIDataSource* CreateOobeUIDataSource( const base::DictionaryValue& localized_strings, const std::string& display_type) { - if (display_type == OobeUI::kNewOobeDisplay) { - return CreateNewOobeUIDataSource(localized_strings); - } content::WebUIDataSource* source = content::WebUIDataSource::Create(chrome::kChromeUIOobeHost); source->AddLocalizedStrings(localized_strings); @@ -168,7 +153,6 @@ const char OobeUI::kLockDisplay[] = "lock"; const char OobeUI::kUserAddingDisplay[] = "user-adding"; const char OobeUI::kAppLaunchSplashDisplay[] = "app-launch-splash"; -const char OobeUI::kNewOobeDisplay[] = "new-oobe"; // static const char OobeUI::kScreenOobeHIDDetection[] = "hid-detection"; @@ -243,7 +227,7 @@ AddScreenHandler(update_screen_handler_); network_dropdown_handler_->AddObserver(update_screen_handler_); - if (display_type_ == kOobeDisplay || display_type_ == kNewOobeDisplay) { + if (display_type_ == kOobeDisplay) { NetworkScreenHandler* network_screen_handler = new NetworkScreenHandler(core_handler_); network_view_ = network_screen_handler;
diff --git a/chrome/browser/ui/webui/downloads_dom_handler.cc b/chrome/browser/ui/webui/downloads_dom_handler.cc index 83c753e..1a1dbc90 100644 --- a/chrome/browser/ui/webui/downloads_dom_handler.cc +++ b/chrome/browser/ui/webui/downloads_dom_handler.cc
@@ -77,35 +77,6 @@ DOWNLOADS_DOM_EVENT_MAX }; -static const char kKey[] = "DownloadsDOMHandlerData"; - -class DownloadsDOMHandlerData : public base::SupportsUserData::Data { - public: - static DownloadsDOMHandlerData* Get(content::DownloadItem* item) { - return static_cast<DownloadsDOMHandlerData*>(item->GetUserData(kKey)); - } - - static const DownloadsDOMHandlerData* Get(const content::DownloadItem* item) { - return static_cast<DownloadsDOMHandlerData*>(item->GetUserData(kKey)); - } - - static void Set(content::DownloadItem* item, DownloadsDOMHandlerData* data) { - item->SetUserData(kKey, data); - } - - static DownloadsDOMHandlerData* Create(content::DownloadItem* item) { - DownloadsDOMHandlerData* data = new DownloadsDOMHandlerData; - item->SetUserData(kKey, data); - return data; - } - - void set_is_removed(bool is_removed) { is_removed_ = is_removed; } - bool is_removed() const { return is_removed_; } - - private: - bool is_removed_; -}; - void CountDownloadsDOMEvents(DownloadsDOMEvent event) { UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent", event, @@ -267,18 +238,14 @@ return file_value; } -bool IsRemoved(const content::DownloadItem& item) { - const DownloadsDOMHandlerData* data = DownloadsDOMHandlerData::Get(&item); - return data && data->is_removed(); -} - // Filters out extension downloads and downloads that don't have a filename yet. bool IsDownloadDisplayable(const content::DownloadItem& item) { return !download_crx_util::IsExtensionDownload(item) && !item.IsTemporary() && !item.GetFileNameToReportUser().empty() && !item.GetTargetFilePath().empty() && - !IsRemoved(item); + DownloadItemModel( + const_cast<content::DownloadItem*>(&item)).ShouldShowInShelf(); } } // namespace @@ -299,16 +266,7 @@ } DownloadsDOMHandler::~DownloadsDOMHandler() { - while (!removes_.empty()) { - const std::set<uint32> remove = removes_.back(); - removes_.pop_back(); - - for (const auto id : remove) { - content::DownloadItem* download = GetDownloadById(id); - if (download) - download->Remove(); - } - } + FinalizeRemovals(); } // DownloadsDOMHandler, public: ----------------------------------------------- @@ -398,7 +356,7 @@ void DownloadsDOMHandler::OnDownloadRemoved( content::DownloadManager* manager, content::DownloadItem* download_item) { - if (IsRemoved(*download_item)) + if (!DownloadItemModel(download_item).ShouldShowInShelf()) return; // This relies on |download_item| being removed from DownloadManager in this @@ -503,17 +461,17 @@ void DownloadsDOMHandler::HandleUndo(const base::ListValue* args) { // TODO(dbeam): handle more than removed downloads someday? - if (removes_.empty()) + if (removals_.empty()) return; - const std::set<uint32> last_removed_ids = removes_.back(); - removes_.pop_back(); + const std::set<uint32> last_removed_ids = removals_.back(); + removals_.pop_back(); for (auto id : last_removed_ids) { content::DownloadItem* download = GetDownloadById(id); if (!download) continue; - DownloadsDOMHandlerData::Set(download, nullptr); + DownloadItemModel(download).SetShouldShowInShelf(true); download->UpdateObservers(); } } @@ -543,16 +501,18 @@ const std::vector<content::DownloadItem*>& to_remove) { std::set<uint32> ids; for (auto* download : to_remove) { - if (IsRemoved(*download) || + DownloadItemModel item_model(download); + if (!item_model.ShouldShowInShelf() || download->GetState() == content::DownloadItem::IN_PROGRESS) { continue; } - DownloadsDOMHandlerData::Create(download)->set_is_removed(true); + item_model.SetShouldShowInShelf(false); ids.insert(download->GetId()); download->UpdateObservers(); } - removes_.push_back(ids); + if (!ids.empty()) + removals_.push_back(ids); } void DownloadsDOMHandler::HandleOpenDownloadsFolder( @@ -585,6 +545,19 @@ return main_notifier_.GetManager(); } +void DownloadsDOMHandler::FinalizeRemovals() { + while (!removals_.empty()) { + const std::set<uint32> remove = removals_.back(); + removals_.pop_back(); + + for (const auto id : remove) { + content::DownloadItem* download = GetDownloadById(id); + if (download) + download->Remove(); + } + } +} + void DownloadsDOMHandler::SendCurrentDownloads() { update_scheduled_ = false; content::DownloadManager::DownloadVector all_items, filtered_items; @@ -670,8 +643,8 @@ content::DownloadItem* DownloadsDOMHandler::GetDownloadById(uint32 id) { content::DownloadItem* item = NULL; - if (main_notifier_.GetManager()) - item = main_notifier_.GetManager()->GetDownload(id); + if (GetMainNotifierManager()) + item = GetMainNotifierManager()->GetDownload(id); if (!item && original_notifier_.get() && original_notifier_->GetManager()) item = original_notifier_->GetManager()->GetDownload(id); return item;
diff --git a/chrome/browser/ui/webui/downloads_dom_handler.h b/chrome/browser/ui/webui/downloads_dom_handler.h index 06890acd..85fdbd8a 100644 --- a/chrome/browser/ui/webui/downloads_dom_handler.h +++ b/chrome/browser/ui/webui/downloads_dom_handler.h
@@ -106,6 +106,9 @@ // Protected for testing. virtual content::DownloadManager* GetMainNotifierManager(); + // Actually remove downloads with an ID in |removals_|. This cannot be undone. + void FinalizeRemovals(); + private: // Shorthand for |observing_items_|, which tracks all items that this is // observing so that RemoveObserver will be called for all of them. @@ -150,7 +153,7 @@ scoped_ptr<AllDownloadItemNotifier> original_notifier_; // IDs of downloads to remove when this handler gets deleted. - std::vector<std::set<uint32>> removes_; + std::vector<std::set<uint32>> removals_; // Whether a call to SendCurrentDownloads() is currently scheduled. bool update_scheduled_;
diff --git a/chrome/browser/ui/webui/downloads_dom_handler_browsertest.cc b/chrome/browser/ui/webui/downloads_dom_handler_browsertest.cc index 4d8c060..ed0193a 100644 --- a/chrome/browser/ui/webui/downloads_dom_handler_browsertest.cc +++ b/chrome/browser/ui/webui/downloads_dom_handler_browsertest.cc
@@ -7,6 +7,7 @@ #include "base/json/json_reader.h" #include "base/prefs/pref_service.h" #include "base/values.h" +#include "chrome/browser/download/download_item_model.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/webui/downloads_dom_handler.h" @@ -85,6 +86,8 @@ void set_manager(content::DownloadManager* manager) { manager_ = manager; } + using DownloadsDOMHandler::FinalizeRemovals; + protected: content::WebContents* GetWebUIWebContents() override { return NULL; } @@ -247,6 +250,7 @@ testing::SetArgPointee<0>(items)); mock_handler_->HandleClearAll(NULL); + EXPECT_TRUE(DownloadItemModel(&item).ShouldShowInShelf()); } // Tests that DownloadsDOMHandler detects new downloads and relays them to the @@ -270,6 +274,34 @@ EXPECT_EQ(0, static_cast<int>(mock_handler_->downloads_list()->GetSize())); } +// Tests that DownloadsDOMHandler actually calls DownloadItem::Remove() when +// it's closed (and removals can no longer be undone). +IN_PROC_BROWSER_TEST_F(DownloadsDOMHandlerTest, RemoveCalledOnPageClose) { + content::MockDownloadManager manager; + mock_handler_->set_manager(&manager); + + content::MockDownloadItem item; + EXPECT_CALL(item, GetId()).WillRepeatedly(testing::Return(1)); + EXPECT_CALL(item, GetState()).WillRepeatedly( + testing::Return(content::DownloadItem::COMPLETE)); + + DownloadItemModel model(&item); + EXPECT_TRUE(model.ShouldShowInShelf()); + + EXPECT_CALL(manager, GetDownload(1)).WillRepeatedly(testing::Return(&item)); + + base::ListValue remove; + remove.AppendString("1"); + EXPECT_CALL(item, UpdateObservers()).Times(1); + mock_handler_->HandleRemove(&remove); + EXPECT_FALSE(model.ShouldShowInShelf()); + + EXPECT_CALL(item, Remove()).Times(1); + // Call |mock_handler_->FinalizeRemovals()| instead of |mock_handler_.reset()| + // because the vtable is affected during destruction and the fake manager + // rigging doesn't work. + mock_handler_->FinalizeRemovals(); +} // TODO(benjhayden): Test the extension downloads filter for both // mock_handler_.downloads_list() and mock_handler_.download_updated().
diff --git a/chrome/browser/ui/webui/extensions/extension_loader_handler.cc b/chrome/browser/ui/webui/extensions/extension_loader_handler.cc index ccf7045f..05584e4 100644 --- a/chrome/browser/ui/webui/extensions/extension_loader_handler.cc +++ b/chrome/browser/ui/webui/extensions/extension_loader_handler.cc
@@ -14,12 +14,9 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/extensions/path_util.h" #include "chrome/browser/extensions/unpacked_installer.h" -#include "chrome/browser/extensions/zipfile_installer.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/chrome_select_file_policy.h" #include "chrome/grit/generated_resources.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/user_metrics.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" @@ -30,7 +27,6 @@ #include "extensions/common/manifest_constants.h" #include "third_party/re2/re2/re2.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/shell_dialogs/select_file_dialog.h" namespace extensions { @@ -47,96 +43,8 @@ } // namespace -class ExtensionLoaderHandler::FileHelper - : public ui::SelectFileDialog::Listener { - public: - explicit FileHelper(ExtensionLoaderHandler* loader_handler); - ~FileHelper() override; - - // Create a FileDialog for the user to select the unpacked extension - // directory. - void ChooseFile(); - - private: - // ui::SelectFileDialog::Listener implementation. - void FileSelected(const base::FilePath& path, - int index, - void* params) override; - void MultiFilesSelected(const std::vector<base::FilePath>& files, - void* params) override; - - // The associated ExtensionLoaderHandler. Weak, but guaranteed to be alive, - // as it owns this object. - ExtensionLoaderHandler* loader_handler_; - - // The dialog used to pick a directory when loading an unpacked extension. - scoped_refptr<ui::SelectFileDialog> load_extension_dialog_; - - // The last selected directory, so we can start in the same spot. - base::FilePath last_unpacked_directory_; - - // The title of the dialog. - base::string16 title_; - - DISALLOW_COPY_AND_ASSIGN(FileHelper); -}; - -ExtensionLoaderHandler::FileHelper::FileHelper( - ExtensionLoaderHandler* loader_handler) - : loader_handler_(loader_handler), - title_(l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY)) { -} - -ExtensionLoaderHandler::FileHelper::~FileHelper() { - // There may be a pending file dialog; inform it the listener is destroyed so - // it doesn't try and call back. - if (load_extension_dialog_.get()) - load_extension_dialog_->ListenerDestroyed(); -} - -void ExtensionLoaderHandler::FileHelper::ChooseFile() { - static const int kFileTypeIndex = 0; // No file type information to index. - static const ui::SelectFileDialog::Type kSelectType = - ui::SelectFileDialog::SELECT_FOLDER; - - gfx::NativeWindow parent_window = - loader_handler_->web_ui()->GetWebContents()->GetTopLevelNativeWindow(); - if (!load_extension_dialog_.get()) { - load_extension_dialog_ = ui::SelectFileDialog::Create( - this, - new ChromeSelectFilePolicy( - loader_handler_->web_ui()->GetWebContents())); - } else if (load_extension_dialog_->IsRunning(parent_window)) { - // File chooser dialog is already running; ignore the click. - return; - } - - load_extension_dialog_->SelectFile( - kSelectType, - title_, - last_unpacked_directory_, - NULL, - kFileTypeIndex, - base::FilePath::StringType(), - parent_window, - NULL); - - content::RecordComputedAction("Options_LoadUnpackedExtension"); -} - -void ExtensionLoaderHandler::FileHelper::FileSelected( - const base::FilePath& path, int index, void* params) { - loader_handler_->LoadUnpackedExtensionImpl(path); -} - -void ExtensionLoaderHandler::FileHelper::MultiFilesSelected( - const std::vector<base::FilePath>& files, void* params) { - NOTREACHED(); -} - ExtensionLoaderHandler::ExtensionLoaderHandler(Profile* profile) : profile_(profile), - file_helper_(new FileHelper(this)), extension_error_reporter_observer_(this), ui_ready_(false), weak_ptr_factory_(this) { @@ -177,10 +85,6 @@ content::WebContentsObserver::Observe(web_ui()->GetWebContents()); web_ui()->RegisterMessageCallback( - "extensionLoaderLoadUnpacked", - base::Bind(&ExtensionLoaderHandler::HandleLoadUnpacked, - weak_ptr_factory_.GetWeakPtr())); - web_ui()->RegisterMessageCallback( "extensionLoaderRetry", base::Bind(&ExtensionLoaderHandler::HandleRetry, weak_ptr_factory_.GetWeakPtr())); @@ -194,16 +98,11 @@ weak_ptr_factory_.GetWeakPtr())); } -void ExtensionLoaderHandler::HandleLoadUnpacked(const base::ListValue* args) { - DCHECK(args->empty()); - file_helper_->ChooseFile(); -} - void ExtensionLoaderHandler::HandleRetry(const base::ListValue* args) { DCHECK(args->empty()); const base::FilePath file_path = failed_paths_.back(); failed_paths_.pop_back(); - LoadUnpackedExtensionImpl(file_path); + LoadUnpackedExtension(file_path); } void ExtensionLoaderHandler::HandleIgnoreFailure(const base::ListValue* args) { @@ -222,8 +121,8 @@ NotifyFrontendOfFailure(); } -void ExtensionLoaderHandler::LoadUnpackedExtensionImpl( - const base::FilePath& file_path) { +void ExtensionLoaderHandler::LoadUnpackedExtension( + const base::FilePath& file_path) { scoped_refptr<UnpackedInstaller> installer = UnpackedInstaller::Create( ExtensionSystem::Get(profile_)->extension_service());
diff --git a/chrome/browser/ui/webui/extensions/extension_loader_handler.h b/chrome/browser/ui/webui/extensions/extension_loader_handler.h index 15989a60..02415d0 100644 --- a/chrome/browser/ui/webui/extensions/extension_loader_handler.h +++ b/chrome/browser/ui/webui/extensions/extension_loader_handler.h
@@ -45,11 +45,6 @@ void RegisterMessages() override; private: - class FileHelper; - - // Handle the 'extensionLoaderLoadUnpacked' message. - void HandleLoadUnpacked(const base::ListValue* args); - // Handle the 'extensionLoaderRetry' message. void HandleRetry(const base::ListValue* args); @@ -60,7 +55,7 @@ void HandleDisplayFailures(const base::ListValue* args); // Try to load an unpacked extension from the given |file_path|. - void LoadUnpackedExtensionImpl(const base::FilePath& file_path); + void LoadUnpackedExtension(const base::FilePath& file_path); // ExtensionErrorReporter::Observer: void OnLoadFailure(content::BrowserContext* browser_context, @@ -86,9 +81,6 @@ // The profile with which this Handler is associated. Profile* profile_; - // A helper to manage file picking. - scoped_ptr<FileHelper> file_helper_; - // Holds information about all unpacked extension install failures that // were reported while the extensions page was loading. base::ListValue failures_;
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc index b7ea12f..c21555f 100644 --- a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc +++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
@@ -636,6 +636,30 @@ // uber extensions. source->AddString("extensionUninstall", l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL)); + + // Pack Extension Overlay: + source->AddString("packExtensionOverlay", + l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_TITLE)); + source->AddString("packExtensionHeading", + l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_HEADING)); + source->AddString("packExtensionCommit", + l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_BUTTON)); + source->AddString("ok", l10n_util::GetStringUTF16(IDS_OK)); + source->AddString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL)); + source->AddString("packExtensionRootDir", + l10n_util::GetStringUTF16( + IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL)); + source->AddString("packExtensionPrivateKey", + l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL)); + source->AddString("packExtensionBrowseButton", + l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_BROWSE)); + source->AddString("packExtensionProceedAnyway", + l10n_util::GetStringUTF16(IDS_EXTENSION_PROCEED_ANYWAY)); + source->AddString("packExtensionWarningTitle", + l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_WARNING_TITLE)); + source->AddString("packExtensionErrorTitle", + l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_ERROR_TITLE)); + } void ExtensionSettingsHandler::RenderViewDeleted(
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc index d99e809..88252e0 100644 --- a/chrome/browser/ui/webui/extensions/extensions_ui.cc +++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -10,7 +10,6 @@ #include "chrome/browser/ui/webui/extensions/extension_loader_handler.h" #include "chrome/browser/ui/webui/extensions/extension_settings_handler.h" #include "chrome/browser/ui/webui/extensions/install_extension_handler.h" -#include "chrome/browser/ui/webui/extensions/pack_extension_handler.h" #include "chrome/browser/ui/webui/metrics_handler.h" #include "chrome/common/url_constants.h" #include "content/public/browser/web_ui.h" @@ -51,10 +50,6 @@ handler->GetLocalizedValues(source); web_ui->AddMessageHandler(handler); - PackExtensionHandler* pack_handler = new PackExtensionHandler(); - pack_handler->GetLocalizedValues(source); - web_ui->AddMessageHandler(pack_handler); - CommandHandler* commands_handler = new CommandHandler(profile); commands_handler->GetLocalizedValues(source); web_ui->AddMessageHandler(commands_handler);
diff --git a/chrome/browser/ui/webui/extensions/pack_extension_handler.cc b/chrome/browser/ui/webui/extensions/pack_extension_handler.cc deleted file mode 100644 index 12a4c07..0000000 --- a/chrome/browser/ui/webui/extensions/pack_extension_handler.cc +++ /dev/null
@@ -1,207 +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. - -#include "chrome/browser/ui/webui/extensions/pack_extension_handler.h" - -#include "base/bind.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/extensions/extension_creator.h" -#include "chrome/browser/ui/chrome_select_file_policy.h" -#include "chrome/grit/generated_resources.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_ui.h" -#include "content/public/browser/web_ui_data_source.h" -#include "ui/base/l10n/l10n_util.h" - -namespace extensions { - -PackExtensionHandler::PackExtensionHandler() { -} - -PackExtensionHandler::~PackExtensionHandler() { - // There may be pending file dialogs, we need to tell them that we've gone - // away so they don't try and call back to us. - if (load_extension_dialog_.get()) - load_extension_dialog_->ListenerDestroyed(); - - if (pack_job_.get()) - pack_job_->ClearClient(); -} - -void PackExtensionHandler::GetLocalizedValues( - content::WebUIDataSource* source) { - source->AddString("packExtensionOverlay", - l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_TITLE)); - source->AddString("packExtensionHeading", - l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_HEADING)); - source->AddString("packExtensionCommit", - l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_BUTTON)); - source->AddString("ok", l10n_util::GetStringUTF16(IDS_OK)); - source->AddString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL)); - source->AddString("packExtensionRootDir", - l10n_util::GetStringUTF16( - IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL)); - source->AddString("packExtensionPrivateKey", - l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL)); - source->AddString("packExtensionBrowseButton", - l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_BROWSE)); - source->AddString("packExtensionProceedAnyway", - l10n_util::GetStringUTF16(IDS_EXTENSION_PROCEED_ANYWAY)); - source->AddString("packExtensionWarningTitle", - l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_WARNING_TITLE)); - source->AddString("packExtensionErrorTitle", - l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_ERROR_TITLE)); -} - -void PackExtensionHandler::RegisterMessages() { - web_ui()->RegisterMessageCallback( - "pack", - base::Bind(&PackExtensionHandler::HandlePackMessage, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "packExtensionSelectFilePath", - base::Bind(&PackExtensionHandler::HandleSelectFilePathMessage, - base::Unretained(this))); -} - -void PackExtensionHandler::OnPackSuccess(const base::FilePath& crx_file, - const base::FilePath& pem_file) { - base::ListValue arguments; - arguments.Append(new base::StringValue(base::UTF16ToUTF8( - PackExtensionJob::StandardSuccessMessage(crx_file, pem_file)))); - web_ui()->CallJavascriptFunction( - "extensions.PackExtensionOverlay.showSuccessMessage", arguments); -} - -void PackExtensionHandler::OnPackFailure(const std::string& error, - ExtensionCreator::ErrorType type) { - if (type == ExtensionCreator::kCRXExists) { - base::StringValue error_str(error); - base::StringValue extension_path_str(extension_path_.value()); - base::StringValue key_path_str(private_key_path_.value()); - base::FundamentalValue overwrite_flag(ExtensionCreator::kOverwriteCRX); - - web_ui()->CallJavascriptFunction( - "extensions.ExtensionSettings.askToOverrideWarning", - error_str, extension_path_str, key_path_str, overwrite_flag); - } else { - ShowAlert(error); - } -} - -void PackExtensionHandler::FileSelected(const base::FilePath& path, int index, - void* params) { - base::ListValue results; - results.Append(new base::StringValue(path.value())); - web_ui()->CallJavascriptFunction("window.handleFilePathSelected", results); -} - -void PackExtensionHandler::MultiFilesSelected( - const std::vector<base::FilePath>& files, void* params) { - NOTREACHED(); -} - -void PackExtensionHandler::HandlePackMessage(const base::ListValue* args) { - DCHECK_EQ(3U, args->GetSize()); - - double flags_double = 0.0; - base::FilePath::StringType extension_path_str; - base::FilePath::StringType private_key_path_str; - if (!args->GetString(0, &extension_path_str) || - !args->GetString(1, &private_key_path_str) || - !args->GetDouble(2, &flags_double)) { - NOTREACHED(); - return; - } - - extension_path_ = base::FilePath(extension_path_str); - private_key_path_ = base::FilePath(private_key_path_str); - - int run_flags = static_cast<int>(flags_double); - - base::FilePath root_directory = extension_path_; - base::FilePath key_file = private_key_path_; - last_used_path_ = extension_path_; - - if (root_directory.empty()) { - if (extension_path_.empty()) { - ShowAlert(l10n_util::GetStringUTF8( - IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED)); - } else { - ShowAlert(l10n_util::GetStringUTF8( - IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID)); - } - - return; - } - - if (!private_key_path_.empty() && key_file.empty()) { - ShowAlert(l10n_util::GetStringUTF8( - IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID)); - return; - } - - pack_job_ = new PackExtensionJob(this, root_directory, key_file, run_flags); - pack_job_->Start(); -} - -void PackExtensionHandler::HandleSelectFilePathMessage( - const base::ListValue* args) { - DCHECK_EQ(2U, args->GetSize()); - - std::string select_type; - if (!args->GetString(0, &select_type)) - NOTREACHED(); - - std::string operation; - if (!args->GetString(1, &operation)) - NOTREACHED(); - - ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER; - ui::SelectFileDialog::FileTypeInfo info; - int file_type_index = 0; - base::FilePath path_to_use = last_used_path_; - if (select_type == "file") { - type = ui::SelectFileDialog::SELECT_OPEN_FILE; - path_to_use = base::FilePath(); - } - - base::string16 select_title; - if (operation == "load") { - select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); - } else if (operation == "pem") { - select_title = l10n_util::GetStringUTF16( - IDS_EXTENSION_PACK_DIALOG_SELECT_KEY); - info.extensions.push_back(std::vector<base::FilePath::StringType>()); - info.extensions.front().push_back(FILE_PATH_LITERAL("pem")); - info.extension_description_overrides.push_back( - l10n_util::GetStringUTF16( - IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION)); - info.include_all_files = true; - file_type_index = 1; - } else { - NOTREACHED(); - } - - load_extension_dialog_ = ui::SelectFileDialog::Create( - this, new ChromeSelectFilePolicy(web_ui()->GetWebContents())); - load_extension_dialog_->SelectFile( - type, - select_title, - path_to_use, - &info, - file_type_index, - base::FilePath::StringType(), - web_ui()->GetWebContents()->GetTopLevelNativeWindow(), - NULL); -} - -void PackExtensionHandler::ShowAlert(const std::string& message) { - base::ListValue arguments; - arguments.Append(new base::StringValue(message)); - web_ui()->CallJavascriptFunction( - "extensions.PackExtensionOverlay.showError", arguments); -} - -} // namespace extensions
diff --git a/chrome/browser/ui/webui/extensions/pack_extension_handler.h b/chrome/browser/ui/webui/extensions/pack_extension_handler.h deleted file mode 100644 index 36a27b3..0000000 --- a/chrome/browser/ui/webui/extensions/pack_extension_handler.h +++ /dev/null
@@ -1,86 +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. - -#ifndef CHROME_BROWSER_UI_WEBUI_EXTENSIONS_PACK_EXTENSION_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_EXTENSIONS_PACK_EXTENSION_HANDLER_H_ - -#include <string> - -#include "base/files/file_path.h" -#include "chrome/browser/browsing_data/browsing_data_remover.h" -#include "chrome/browser/extensions/pack_extension_job.h" -#include "chrome/browser/plugins/plugin_data_remover_helper.h" -#include "content/public/browser/web_ui_message_handler.h" -#include "ui/shell_dialogs/select_file_dialog.h" - -namespace content { -class WebUIDataSource; -} - -namespace extensions { - -// Clear browser data handler page UI handler. -class PackExtensionHandler : public content::WebUIMessageHandler, - public ui::SelectFileDialog::Listener, - public PackExtensionJob::Client { - public: - PackExtensionHandler(); - ~PackExtensionHandler() override; - - void GetLocalizedValues(content::WebUIDataSource* source); - - // WebUIMessageHandler implementation. - void RegisterMessages() override; - - // ExtensionPackJob::Client implementation. - void OnPackSuccess(const base::FilePath& crx_file, - const base::FilePath& key_file) override; - - void OnPackFailure(const std::string& error, - ExtensionCreator::ErrorType) override; - - private: - // SelectFileDialog::Listener implementation. - void FileSelected(const base::FilePath& path, - int index, - void* params) override; - void MultiFilesSelected(const std::vector<base::FilePath>& files, - void* params) override; - void FileSelectionCanceled(void* params) override {} - - // JavaScript callback to start packing an extension. - void HandlePackMessage(const base::ListValue* args); - - // JavaScript callback to show a file browse dialog. - // |args[0]| must be a string that specifies the file dialog type: file or - // folder. - // |args[1]| must be a string that specifies the operation to perform: load - // or pem. - void HandleSelectFilePathMessage(const base::ListValue* args); - - // A function to ask the page to show an alert. - void ShowAlert(const std::string& message); - - // Used to package the extension. - scoped_refptr<PackExtensionJob> pack_job_; - - // Returned by the SelectFileDialog machinery. Used to initiate the selection - // dialog. - scoped_refptr<ui::SelectFileDialog> load_extension_dialog_; - - // Path to root directory of extension. - base::FilePath extension_path_; - - // Path to private key file, or null if none specified. - base::FilePath private_key_path_; - - // Path to the last used folder to load an extension. - base::FilePath last_used_path_; - - DISALLOW_COPY_AND_ASSIGN(PackExtensionHandler); -}; - -} // namespace extensions - -#endif // CHROME_BROWSER_UI_WEBUI_EXTENSIONS_PACK_EXTENSION_HANDLER_H_
diff --git a/chrome/browser/ui/webui/nacl_ui.cc b/chrome/browser/ui/webui/nacl_ui.cc index d844a40..26482c7 100644 --- a/chrome/browser/ui/webui/nacl_ui.cc +++ b/chrome/browser/ui/webui/nacl_ui.cc
@@ -328,9 +328,9 @@ void CheckVersion(const base::FilePath& pnacl_path, std::string* version) { base::FilePath pnacl_json_path = pnacl_path.AppendASCII("pnacl_public_pnacl_json"); - JSONFileValueSerializer serializer(pnacl_json_path); + JSONFileValueDeserializer deserializer(pnacl_json_path); std::string error; - scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error)); + scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, &error)); if (!root || !root->IsType(base::Value::TYPE_DICTIONARY)) return;
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc index 2a844a4b..258c8cb 100644 --- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc +++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
@@ -76,9 +76,9 @@ // The URL for the the Learn More page shown on incognito new tab. const char kLearnMoreIncognitoUrl[] = #if defined(OS_CHROMEOS) - "https://www.google.com/support/chromeos/bin/answer.py?answer=95464"; + "https://support.google.com/chromebook/?p=incognito"; #else - "https://www.google.com/support/chrome/bin/answer.py?answer=95464"; + "https://support.google.com/chrome/?p=incognito"; #endif // The URL for the Learn More page shown on guest session new tab. @@ -174,6 +174,13 @@ registrar_.Add(this, chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED, content::NotificationService::AllSources()); + PromoResourceService* promo_service = + g_browser_process->promo_resource_service(); + if (promo_service) { + promo_resource_subscription_ = promo_service->RegisterStateChangedCallback( + base::Bind(&NTPResourceCache::Invalidate, base::Unretained(this))); + } + base::Closure callback = base::Bind(&NTPResourceCache::OnPreferenceChanged, base::Unretained(this)); @@ -275,10 +282,7 @@ // Invalidate the cache. if (chrome::NOTIFICATION_BROWSER_THEME_CHANGED == type || chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED == type) { - new_tab_incognito_html_ = NULL; - new_tab_html_ = NULL; - new_tab_incognito_css_ = NULL; - new_tab_css_ = NULL; + Invalidate(); } else { NOTREACHED(); } @@ -292,6 +296,14 @@ new_tab_css_ = NULL; } +void NTPResourceCache::Invalidate() { + new_tab_incognito_html_ = nullptr; + new_tab_html_ = nullptr; + new_tab_incognito_css_ = nullptr; + // TODO(dbeam): Check if it is necessary to clear the CSS on promo changes. + new_tab_css_ = nullptr; +} + void NTPResourceCache::CreateNewTabIncognitoHTML() { base::DictionaryValue localized_strings; localized_strings.SetString("title",
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.h b/chrome/browser/ui/webui/ntp/ntp_resource_cache.h index 749e0a9..8f6da67 100644 --- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.h +++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.h
@@ -10,6 +10,7 @@ #include "base/memory/ref_counted.h" #include "base/prefs/pref_change_registrar.h" #include "base/strings/string16.h" +#include "chrome/browser/web_resource/promo_resource_service.h" #include "components/keyed_service/core/keyed_service.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -67,6 +68,9 @@ void CreateNewTabHTML(); + // Invalidates the NTPResourceCache. + void Invalidate(); + // Helper to determine if the resource cache should be invalidated. // This is called on every page load, and can be used to check values that // don't generate a notification when changed (e.g., system preferences). @@ -96,6 +100,8 @@ content::NotificationRegistrar registrar_; PrefChangeRegistrar profile_pref_change_registrar_; PrefChangeRegistrar local_state_pref_change_registrar_; + scoped_ptr<PromoResourceService::StateChangedSubscription> + promo_resource_subscription_; // Set based on platform_util::IsSwipeTrackingFromScrollEventsEnabled. bool is_swipe_tracking_from_scroll_events_enabled_;
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index e3d05b1..2ce6804 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -495,6 +495,10 @@ { "cloudPrintEnableNotificationsLabel", IDS_LOCAL_DISCOVERY_NOTIFICATIONS_ENABLE_CHECKBOX_LABEL }, #endif // defined(ENABLE_SERVICE_DISCOVERY) +#if defined(OS_CHROMEOS) + { "captivePortalBypassProxy", + IDS_OPTIONS_CAPTIVE_PORTAL_BYPASS_PROXY_LABEL }, +#endif }; #if defined(ENABLE_SETTINGS_APP) @@ -658,6 +662,11 @@ RegisterTitle(values, "thirdPartyImeConfirmOverlay", IDS_OPTIONS_SETTINGS_LANGUAGES_THIRD_PARTY_WARNING_TITLE); + + values->SetBoolean( + "enableCaptivePortalBypassProxyOption", + base::CommandLine::ForCurrentProcess()->HasSwitch( + chromeos::switches::kEnableCaptivePortalBypassProxyOption)); #endif values->SetBoolean("showSetDefault", ShouldShowSetDefaultBrowser()); @@ -681,6 +690,9 @@ values->SetBoolean("enableTimeZoneTrackingOption", !have_disable_time_zone_tracking_option_switch && !chromeos::system::HasSystemTimezonePolicy()); + values->SetBoolean("resolveTimezoneByGeolocationInitialValue", + Profile::FromWebUI(web_ui())->GetPrefs()->GetBoolean( + prefs::kResolveTimezoneByGeolocation)); #endif }
diff --git a/chrome/browser/ui/webui/options/chromeos/date_time_options_browsertest.js b/chrome/browser/ui/webui/options/chromeos/date_time_options_browsertest.js index 937af8b..4033599 100644 --- a/chrome/browser/ui/webui/options/chromeos/date_time_options_browsertest.js +++ b/chrome/browser/ui/webui/options/chromeos/date_time_options_browsertest.js
@@ -26,14 +26,12 @@ TEST_F('DateTimeOptionsWebUITest', 'testShowSetTimeButton', function() { assertEquals(this.browsePreload, document.location.href); - // Hide label and show button. + // Show button. BrowserOptions.setCanSetTime(true); - expectTrue($('time-synced-explanation').hidden); expectFalse($('set-time').hidden); - // Show label and hide button. + // Hide button. BrowserOptions.setCanSetTime(false); - expectFalse($('time-synced-explanation').hidden); expectTrue($('set-time').hidden); });
diff --git a/chrome/browser/ui/webui/options/chromeos/date_time_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/date_time_options_handler.cc index ef55e5f..bbb4b0c 100644 --- a/chrome/browser/ui/webui/options/chromeos/date_time_options_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/date_time_options_handler.cc
@@ -33,9 +33,6 @@ localized_strings->SetString( "setTimeButton", l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SET_TIME_BUTTON)); - localized_strings->SetString( - "timeSyncedExplanation", - l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_TIME_SYNCED_EXPLANATION)); } void DateTimeOptionsHandler::InitializeHandler() {
diff --git a/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc b/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc index df7f7d1..d51fd41 100644 --- a/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc +++ b/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc
@@ -118,11 +118,17 @@ browser->tab_strip_model()->GetActiveWebContents(); for (size_t i = 0; i < sizeof(kPrefTests) / sizeof(kPrefTests[0]); i++) { - CheckPreference(contents, - kPrefTests[i].pref_name, - !is_owner && kPrefTests[i].owner_only, - !is_owner && kPrefTests[i].indicator ? "owner" : - std::string()); + bool disabled = !is_owner && kPrefTests[i].owner_only; + if (strcmp(kPrefTests[i].pref_name, kSystemTimezone) == 0) { + disabled = ProfileHelper::Get() + ->GetProfileByUserUnsafe(user) + ->GetPrefs() + ->GetBoolean(prefs::kResolveTimezoneByGeolocation); + } + + CheckPreference( + contents, kPrefTests[i].pref_name, disabled, + !is_owner && kPrefTests[i].indicator ? "owner" : std::string()); } CheckBanner(contents, is_primary); CheckSharedSections(contents, is_primary);
diff --git a/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc b/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc index 7fb2c96..785b2a6 100644 --- a/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc +++ b/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc
@@ -165,7 +165,7 @@ scoped_ptr<base::ListValue> GetJSONAsListValue(const std::string& json, std::string* error) { scoped_ptr<base::Value> deserialized( - JSONStringValueSerializer(json).Deserialize(NULL, error)); + JSONStringValueDeserializer(json).Deserialize(NULL, error)); if (!deserialized) return scoped_ptr<base::ListValue>(); base::ListValue* list = nullptr; @@ -182,7 +182,7 @@ const std::string& json, std::string* error) { scoped_ptr<base::Value> deserialized( - JSONStringValueSerializer(json).Deserialize(NULL, error)); + JSONStringValueDeserializer(json).Deserialize(NULL, error)); if (!deserialized) return scoped_ptr<base::DictionaryValue>(); base::DictionaryValue* dictionary;
diff --git a/chrome/browser/web_resource/promo_resource_service.cc b/chrome/browser/web_resource/promo_resource_service.cc index db05e93c..140dff0 100644 --- a/chrome/browser/web_resource/promo_resource_service.cc +++ b/chrome/browser/web_resource/promo_resource_service.cc
@@ -12,12 +12,10 @@ #include "base/threading/thread_restrictions.h" #include "base/values.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/web_resource/notification_promo.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/web_resource/web_resource_pref_names.h" #include "components/web_resource/web_resource_switches.h" -#include "content/public/browser/notification_service.h" #include "url/gurl.h" namespace { @@ -100,6 +98,12 @@ PromoResourceService::~PromoResourceService() { } +scoped_ptr<PromoResourceService::StateChangedSubscription> +PromoResourceService::RegisterStateChangedCallback( + const base::Closure& closure) { + return callback_list_.Add(closure); +} + void PromoResourceService::ScheduleNotification( const NotificationPromo& notification_promo) { const double promo_start = notification_promo.StartTimeForGroup(); @@ -161,11 +165,7 @@ } void PromoResourceService::PromoResourceStateChange() { - content::NotificationService* service = - content::NotificationService::current(); - service->Notify(chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED, - content::Source<WebResourceService>(this), - content::NotificationService::NoDetails()); + callback_list_.Notify(); } void PromoResourceService::Unpack(const base::DictionaryValue& parsed_json) {
diff --git a/chrome/browser/web_resource/promo_resource_service.h b/chrome/browser/web_resource/promo_resource_service.h index 1ad7fe7..3af62261 100644 --- a/chrome/browser/web_resource/promo_resource_service.h +++ b/chrome/browser/web_resource/promo_resource_service.h
@@ -7,6 +7,8 @@ #include <string> +#include "base/callback_forward.h" +#include "base/callback_list.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/web_resource/chrome_web_resource_service.h" @@ -28,6 +30,9 @@ // promotional messages to certain groups of Chrome users. class PromoResourceService : public ChromeWebResourceService { public: + using StateChangedCallbackList = base::CallbackList<void()>; + using StateChangedSubscription = StateChangedCallbackList::Subscription; + static void RegisterPrefs(PrefRegistrySimple* registry); static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); static void MigrateUserPrefs(PrefService* user_prefs); @@ -35,6 +40,11 @@ PromoResourceService(); ~PromoResourceService() override; + // Registers a callback called when the state of a web resource has been + // changed. A resource may have been added, removed, or altered. + scoped_ptr<StateChangedSubscription> RegisterStateChangedCallback( + const base::Closure& closure); + private: // Schedule a notification that a web resource is either going to become // available or be no longer valid. @@ -57,6 +67,9 @@ // WebResourceService override to process the parsed information. void Unpack(const base::DictionaryValue& parsed_json) override; + // List of callbacks called when the state of a web resource has changed. + StateChangedCallbackList callback_list_; + // Allows the creation of tasks to send a notification. // This allows the PromoResourceService to notify the New Tab Page immediately // when a new web resource should be shown or removed.
diff --git a/chrome/browser/web_resource/promo_resource_service_unittest.cc b/chrome/browser/web_resource/promo_resource_service_unittest.cc index 9b987d08..96b6a08 100644 --- a/chrome/browser/web_resource/promo_resource_service_unittest.cc +++ b/chrome/browser/web_resource/promo_resource_service_unittest.cc
@@ -14,7 +14,6 @@ #include "base/time/time.h" #include "base/values.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/web_resource/notification_promo.h" #include "chrome/browser/web_resource/promo_resource_service.h" @@ -22,8 +21,6 @@ #include "chrome/common/url_constants.h" #include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/testing_browser_process.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/notification_service.h" #include "net/url_request/test_url_fetcher_factory.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/icu/source/i18n/unicode/smpdtfmt.h"
diff --git a/chrome/browser_tests.isolate b/chrome/browser_tests.isolate index ee822a2b..75a51b7 100644 --- a/chrome/browser_tests.isolate +++ b/chrome/browser_tests.isolate
@@ -59,6 +59,9 @@ '<(PRODUCT_DIR)/peerconnection_server<(EXECUTABLE_SUFFIX)', '<(PRODUCT_DIR)/pseudo_locales/', '<(PRODUCT_DIR)/pyproto/', + # TODO(jam): above is directory for GYP. GN uses: + #'<(SHARED_INTERMEDIATE_DIR)/google/', + #'<(SHARED_INTERMEDIATE_DIR)/policy/proto/', '<(PRODUCT_DIR)/remoting/unittests/', '<(PRODUCT_DIR)/test_case.html', '<(PRODUCT_DIR)/test_case.html.mock-http-headers',
diff --git a/chrome/chrome_android.gypi b/chrome/chrome_android.gypi index 3c62104a9..734cda9 100644 --- a/chrome/chrome_android.gypi +++ b/chrome/chrome_android.gypi
@@ -32,7 +32,7 @@ # is upstreamed. '../components/components.gyp:enhanced_bookmarks', '../content/content.gyp:content', - '../content/content.gyp:content_app_browser', + '../content/content.gyp:content_app_both', ], 'include_dirs': [ '..', @@ -42,6 +42,7 @@ 'app/android/chrome_android_initializer.cc', 'app/android/chrome_android_initializer.h', 'app/android/chrome_jni_onload.cc', + 'app/android/chrome_jni_onload.h', 'app/android/chrome_main_delegate_android.cc', 'app/android/chrome_main_delegate_android.h', 'app/chrome_main_delegate.cc',
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 501a602..11c2643 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi
@@ -78,8 +78,14 @@ 'browser/android/dev_tools_server.h', 'browser/android/dom_distiller/feedback_reporter_android.cc', 'browser/android/dom_distiller/feedback_reporter_android.h', + 'browser/android/download/android_download_manager_overwrite_infobar_delegate.cc', + 'browser/android/download/android_download_manager_overwrite_infobar_delegate.h', 'browser/android/download/chrome_download_delegate.cc', 'browser/android/download/chrome_download_delegate.h', + 'browser/android/download/chrome_download_manager_overwrite_infobar_delegate.cc', + 'browser/android/download/chrome_download_manager_overwrite_infobar_delegate.h', + 'browser/android/download/download_overwrite_infobar_delegate.cc', + 'browser/android/download/download_overwrite_infobar_delegate.h', 'browser/android/favicon_helper.cc', 'browser/android/favicon_helper.h', 'browser/android/feature_utilities.cc', @@ -101,6 +107,12 @@ 'browser/android/logo_service.h', 'browser/android/manifest_icon_selector.cc', 'browser/android/manifest_icon_selector.h', + 'browser/android/metrics/uma_bridge.cc', + 'browser/android/metrics/uma_bridge.h', + 'browser/android/metrics/uma_session_stats.cc', + 'browser/android/metrics/uma_session_stats.h', + 'browser/android/metrics/uma_utils.cc', + 'browser/android/metrics/uma_utils.h', 'browser/android/most_visited_sites.cc', 'browser/android/most_visited_sites.h', 'browser/android/new_tab_page_prefs.cc', @@ -154,10 +166,6 @@ 'browser/android/thumbnail/thumbnail.h', 'browser/android/thumbnail/thumbnail_store.cc', 'browser/android/thumbnail/thumbnail_store.h', - 'browser/android/uma_bridge.cc', - 'browser/android/uma_bridge.h', - 'browser/android/uma_utils.cc', - 'browser/android/uma_utils.h', 'browser/android/url_utilities.cc', 'browser/android/url_utilities.h', 'browser/android/voice_search_tab_helper.cc', @@ -567,6 +575,18 @@ 'browser/process_info_snapshot_mac.cc', 'browser/process_singleton.h', 'browser/process_singleton_win.cc', + 'browser/push_messaging/push_messaging_application_id.cc', + 'browser/push_messaging/push_messaging_application_id.h', + 'browser/push_messaging/push_messaging_constants.cc', + 'browser/push_messaging/push_messaging_constants.h', + 'browser/push_messaging/push_messaging_permission_context.cc', + 'browser/push_messaging/push_messaging_permission_context.h', + 'browser/push_messaging/push_messaging_permission_context_factory.cc', + 'browser/push_messaging/push_messaging_permission_context_factory.h', + 'browser/push_messaging/push_messaging_service_impl.cc', + 'browser/push_messaging/push_messaging_service_impl.h', + 'browser/push_messaging/push_messaging_service_factory.h', + 'browser/push_messaging/push_messaging_service_factory.cc', 'browser/renderer_context_menu/context_menu_content_type_factory.cc', 'browser/renderer_context_menu/context_menu_content_type_factory.h', 'browser/renderer_context_menu/context_menu_content_type_panel.cc', @@ -860,6 +880,8 @@ 'browser/diagnostics/recon_diagnostics.h', 'browser/diagnostics/sqlite_diagnostics.cc', 'browser/diagnostics/sqlite_diagnostics.h', + 'browser/download/download_commands.cc', + 'browser/download/download_commands.h', 'browser/download/download_crx_util.cc', 'browser/download/download_crx_util.h', 'browser/download/download_danger_prompt.cc', @@ -868,6 +890,10 @@ 'browser/download/download_shelf.h', 'browser/download/download_shelf_context_menu.cc', 'browser/download/download_shelf_context_menu.h', + 'browser/download/notification/download_notification_item.h', + 'browser/download/notification/download_notification_item.cc', + 'browser/download/notification/download_notification_manager.h', + 'browser/download/notification/download_notification_manager.cc', 'browser/external_protocol/external_protocol_observer.cc', 'browser/external_protocol/external_protocol_observer.h', 'browser/feedback/feedback_profile_observer.cc', @@ -1541,6 +1567,8 @@ 'browser/history/history_service_factory.h', 'browser/history/history_tab_helper.cc', 'browser/history/history_tab_helper.h', + 'browser/history/history_utils.cc', + 'browser/history/history_utils.h', 'browser/history/in_memory_history_backend.cc', 'browser/history/in_memory_history_backend.h', 'browser/history/in_memory_url_index.cc', @@ -1599,8 +1627,12 @@ 'android/java/src/org/chromium/chrome/browser/NewTabPagePrefs.java', 'android/java/src/org/chromium/chrome/browser/IntentHelper.java', 'android/java/src/org/chromium/chrome/browser/JavascriptAppModalDialog.java', + 'android/java/src/org/chromium/chrome/browser/metrics/UmaBridge.java', + 'android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java', + 'android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.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/infobar/DownloadOverwriteInfoBar.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', @@ -1631,11 +1663,8 @@ 'android/java/src/org/chromium/chrome/browser/Tab.java', 'android/java/src/org/chromium/chrome/browser/TabState.java', 'android/java/src/org/chromium/chrome/browser/TtsPlatformImpl.java', - 'android/java/src/org/chromium/chrome/browser/UmaBridge.java', - 'android/java/src/org/chromium/chrome/browser/UmaUtils.java', 'android/java/src/org/chromium/chrome/browser/UrlUtilities.java', 'android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java', - 'android/java/src/org/chromium/chrome/browser/VoiceSearchTabHelper.java', 'android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java', 'android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBar.java', 'android/java/src/org/chromium/chrome/browser/infobar/AccountChooserInfoBar.java', @@ -2461,16 +2490,6 @@ 'browser/services/gcm/gcm_profile_service.h', 'browser/services/gcm/gcm_profile_service_factory.cc', 'browser/services/gcm/gcm_profile_service_factory.h', - 'browser/services/gcm/push_messaging_application_id.cc', - 'browser/services/gcm/push_messaging_application_id.h', - 'browser/services/gcm/push_messaging_constants.cc', - 'browser/services/gcm/push_messaging_constants.h', - 'browser/services/gcm/push_messaging_permission_context.cc', - 'browser/services/gcm/push_messaging_permission_context.h', - 'browser/services/gcm/push_messaging_permission_context_factory.cc', - 'browser/services/gcm/push_messaging_permission_context_factory.h', - 'browser/services/gcm/push_messaging_service_impl.cc', - 'browser/services/gcm/push_messaging_service_impl.h', ], 'chrome_browser_session_sources': [ 'browser/sessions/base_session_service_delegate.h', @@ -2576,6 +2595,8 @@ 'browser/ssl/ssl_error_info.h', ], 'chrome_browser_supervised_user_sources': [ + 'browser/content_settings/content_settings_supervised_provider.cc', + 'browser/content_settings/content_settings_supervised_provider.h', 'browser/supervised_user/child_accounts/child_account_feedback_reporter_android.cc', 'browser/supervised_user/child_accounts/child_account_feedback_reporter_android.h', 'browser/supervised_user/child_accounts/child_account_service.cc', @@ -2896,6 +2917,7 @@ '../components/components.gyp:enhanced_bookmarks', '../components/components.gyp:favicon_base', '../components/components.gyp:favicon_core', + '../components/components.gyp:feedback_component', '../components/components.gyp:gcm_driver', '../components/components.gyp:google_core_browser', '../components/components.gyp:handoff', @@ -2998,6 +3020,7 @@ '../third_party/re2/re2.gyp:re2', '../cc/cc.gyp:cc', '../components/components.gyp:autofill_content_browser', + '../components/components.gyp:data_reduction_proxy_content_browser', '../components/components.gyp:dom_distiller_content', '../components/components.gyp:history_content_browser', '../components/components.gyp:keyed_service_content', @@ -3366,7 +3389,6 @@ }, { # OS!="android" and OS!="ios" 'sources': [ '<@(chrome_browser_non_mobile_sources)' ], 'dependencies': [ - '../components/components.gyp:feedback_component', '../device/core/core.gyp:device_core', '../device/usb/usb.gyp:device_usb', ] @@ -3383,6 +3405,7 @@ 'chrome_browser_jni_headers', ], 'dependencies!': [ + '../components/components.gyp:feedback_component', '../components/components.gyp:storage_monitor', '../components/components.gyp:web_modal', '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput',
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index 11d50ac..4183ace 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi
@@ -85,7 +85,6 @@ 'browser/chromeos/dbus/screen_lock_service_provider.h', 'browser/chromeos/device/input_service_proxy.cc', 'browser/chromeos/device/input_service_proxy.h', - 'browser/chromeos/device_hierarchy_observer.h', 'browser/chromeos/device_uma.cc', 'browser/chromeos/device_uma.h', 'browser/chromeos/display/display_configuration_observer.cc', @@ -421,8 +420,6 @@ 'browser/chromeos/login/auth/chrome_login_performer.h', 'browser/chromeos/login/chrome_restart_request.cc', 'browser/chromeos/login/chrome_restart_request.h', - 'browser/chromeos/login/default_pinned_apps_field_trial.cc', - 'browser/chromeos/login/default_pinned_apps_field_trial.h', 'browser/chromeos/login/demo_mode/demo_app_launcher.cc', 'browser/chromeos/login/demo_mode/demo_app_launcher.h', 'browser/chromeos/login/easy_unlock/easy_unlock_create_keys_operation.cc', @@ -711,6 +708,8 @@ 'browser/chromeos/net/wake_on_wifi_manager.h', 'browser/chromeos/offline/offline_load_page.cc', 'browser/chromeos/offline/offline_load_page.h', + 'browser/chromeos/oobe/oobe.cc', + 'browser/chromeos/oobe/oobe.h', 'browser/chromeos/options/cert_library.cc', 'browser/chromeos/options/cert_library.h', 'browser/chromeos/options/network_config_view.cc', @@ -1120,6 +1119,7 @@ '../components/components.gyp:variations', '../components/components.gyp:variations_http_provider', '../components/components.gyp:wallpaper', + '../components/components.gyp:webui_generator', '../components/components.gyp:wifi_sync', '../components/components_strings.gyp:components_strings', '../content/app/resources/content_resources.gyp:content_resources', @@ -1161,6 +1161,8 @@ '../ui/events/platform/events_platform.gyp:events_platform', '../ui/chromeos/ui_chromeos.gyp:ui_chromeos_resources', '../ui/chromeos/ui_chromeos.gyp:ui_chromeos_strings', + '../ui/oobe/oobe.gyp:oobe', + '../ui/oobe/oobe.gyp:oobe_wug_generated', '../ui/resources/ui_resources.gyp:ui_resources', '../ui/strings/ui_strings.gyp:ui_strings', '../ui/surface/surface.gyp:surface',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 28e210e4..435420d 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi
@@ -39,6 +39,8 @@ 'browser/ui/android/infobars/confirm_infobar.h', 'browser/ui/android/infobars/data_reduction_proxy_infobar.cc', 'browser/ui/android/infobars/data_reduction_proxy_infobar.h', + 'browser/ui/android/infobars/download_overwrite_infobar.cc', + 'browser/ui/android/infobars/download_overwrite_infobar.h', 'browser/ui/android/infobars/infobar_android.cc', 'browser/ui/android/infobars/infobar_android.h', 'browser/ui/android/infobars/infobar_container_android.cc', @@ -599,6 +601,10 @@ 'browser/ui/cocoa/panels/panel_utils_cocoa.mm', 'browser/ui/cocoa/panels/panel_window_controller_cocoa.h', 'browser/ui/cocoa/panels/panel_window_controller_cocoa.mm', + 'browser/ui/cocoa/passwords/account_avatar_fetcher_manager.h', + 'browser/ui/cocoa/passwords/account_avatar_fetcher_manager.mm', + 'browser/ui/cocoa/passwords/credential_item_view.h', + 'browser/ui/cocoa/passwords/credential_item_view.mm', 'browser/ui/cocoa/passwords/manage_password_item_view_controller.h', 'browser/ui/cocoa/passwords/manage_password_item_view_controller.mm', 'browser/ui/cocoa/passwords/manage_passwords_bubble_blacklist_view_controller.h', @@ -651,6 +657,8 @@ 'browser/ui/cocoa/screen_capture_notification_ui_cocoa.h', 'browser/ui/cocoa/screen_capture_notification_ui_cocoa.mm', 'browser/ui/cocoa/simple_message_box_mac.mm', + 'browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h', + 'browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.mm', 'browser/ui/cocoa/sprite_view.h', 'browser/ui/cocoa/sprite_view.mm', 'browser/ui/cocoa/ssl_client_certificate_selector_cocoa.h', @@ -731,7 +739,6 @@ 'browser/ui/cocoa/view_id_util.h', 'browser/ui/cocoa/view_id_util.mm', 'browser/ui/cocoa/view_resizer.h', - 'browser/ui/cocoa/web_contents_modal_dialog_manager_cocoa.mm', 'browser/ui/cocoa/web_dialog_window_controller.h', 'browser/ui/cocoa/web_dialog_window_controller.mm', 'browser/ui/cocoa/website_settings/permission_bubble_cocoa.h', @@ -1344,8 +1351,7 @@ # Counts desktop Linux and ChromeOS. '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/apps/chrome_app_window_client_views.cc', 'browser/ui/webui/certificate_viewer_ui.cc', 'browser/ui/webui/certificate_viewer_ui.h', 'browser/ui/webui/certificate_viewer_webui.cc', @@ -1446,6 +1452,8 @@ 'browser/ui/exclusive_access/exclusive_access_bubble.h', 'browser/ui/exclusive_access/exclusive_access_bubble_type.cc', 'browser/ui/exclusive_access/exclusive_access_bubble_type.h', + 'browser/ui/exclusive_access/exclusive_access_context.cc', + 'browser/ui/exclusive_access/exclusive_access_context.h', 'browser/ui/exclusive_access/exclusive_access_controller_base.cc', 'browser/ui/exclusive_access/exclusive_access_controller_base.h', 'browser/ui/exclusive_access/exclusive_access_manager.cc', @@ -1841,6 +1849,12 @@ 'browser/ui/app_list/app_list_service_views.h', 'browser/ui/app_list/app_list_shower_views.cc', 'browser/ui/app_list/app_list_shower_views.h', + 'browser/ui/views/apps/chrome_native_app_window_views.cc', + 'browser/ui/views/apps/chrome_native_app_window_views.h', + 'browser/ui/views/apps/desktop_keyboard_capture.cc', + 'browser/ui/views/apps/desktop_keyboard_capture.h', + 'browser/ui/views/apps/keyboard_hook_handler.cc', + 'browser/ui/views/apps/keyboard_hook_handler.h', 'browser/ui/views/chrome_browser_main_extra_parts_views.cc', 'browser/ui/views/chrome_browser_main_extra_parts_views.h', 'browser/ui/views/chrome_constrained_window_views_client.cc', @@ -1851,10 +1865,14 @@ 'browser/ui/views/collected_cookies_views.h', 'browser/ui/views/cookie_info_view.cc', 'browser/ui/views/cookie_info_view.h', + 'browser/ui/views/extensions/extension_keybinding_registry_views.cc', + 'browser/ui/views/extensions/extension_keybinding_registry_views.h', 'browser/ui/views/find_bar_host.cc', 'browser/ui/views/find_bar_host.h', 'browser/ui/views/find_bar_view.cc', 'browser/ui/views/find_bar_view.h', + 'browser/ui/views/frame/taskbar_decorator.cc', + 'browser/ui/views/frame/taskbar_decorator.h', 'browser/ui/views/hung_renderer_view.cc', 'browser/ui/views/hung_renderer_view.h', 'browser/ui/views/infobars/confirm_infobar.cc', @@ -1953,18 +1971,13 @@ 'browser/ui/views/apps/app_window_desktop_native_widget_aura_win.h', 'browser/ui/views/apps/app_window_desktop_window_tree_host_win.cc', 'browser/ui/views/apps/app_window_desktop_window_tree_host_win.h', - 'browser/ui/views/apps/chrome_apps_client_views_win.cc', - 'browser/ui/views/apps/chrome_native_app_window_views.cc', - 'browser/ui/views/apps/chrome_native_app_window_views.h', + 'browser/ui/views/apps/chrome_app_window_client_views_win.cc', 'browser/ui/views/apps/chrome_native_app_window_views_aura.cc', 'browser/ui/views/apps/chrome_native_app_window_views_aura.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', @@ -2062,6 +2075,7 @@ 'browser/ui/views/elevation_icon_setter.h', 'browser/ui/views/exclusive_access_bubble_views.cc', 'browser/ui/views/exclusive_access_bubble_views.h', + 'browser/ui/views/exclusive_access_bubble_views_context.h', 'browser/ui/views/extensions/bookmark_app_bubble_view.cc', 'browser/ui/views/extensions/bookmark_app_bubble_view.h', 'browser/ui/views/extensions/browser_action_drag_data.cc', @@ -2078,8 +2092,6 @@ 'browser/ui/views/extensions/extension_install_dialog_view.cc', 'browser/ui/views/extensions/extension_installed_bubble_view.cc', 'browser/ui/views/extensions/extension_installed_bubble_view.h', - 'browser/ui/views/extensions/extension_keybinding_registry_views.cc', - 'browser/ui/views/extensions/extension_keybinding_registry_views.h', 'browser/ui/views/extensions/extension_message_bubble_view.cc', 'browser/ui/views/extensions/extension_message_bubble_view.h', 'browser/ui/views/extensions/extension_popup.cc', @@ -2147,8 +2159,6 @@ 'browser/ui/views/frame/system_menu_model_builder.h', 'browser/ui/views/frame/system_menu_model_delegate.cc', 'browser/ui/views/frame/system_menu_model_delegate.h', - 'browser/ui/views/frame/taskbar_decorator.cc', - 'browser/ui/views/frame/taskbar_decorator.h', 'browser/ui/views/frame/taskbar_decorator_win.cc', 'browser/ui/views/frame/top_container_view.cc', 'browser/ui/views/frame/top_container_view.h', @@ -2303,6 +2313,14 @@ 'browser/ui/views/website_settings/website_settings_popup_view.cc', 'browser/ui/views/website_settings/website_settings_popup_view.h', ], + # MacViews sources that we still want to keep behind a compile-time flag. + # TODO(jackhou): Move items to chrome_browser_ui_views_sources when they + # migrate from mac_views_browser to a chrome://flag. + 'chrome_browser_ui_views_mac_experimental_sources': [ + 'browser/ui/views/apps/chrome_app_window_client_views_mac.mm', + 'browser/ui/views/apps/chrome_native_app_window_views_mac.h', + 'browser/ui/views/apps/chrome_native_app_window_views_mac.mm', + ], # Windows-only. Assume ash/aura/views. 'chrome_browser_ui_win_sources': [ 'browser/ui/network_profile_bubble.cc', @@ -2504,8 +2522,6 @@ 'browser/ui/webui/extensions/extension_error_ui_util.h', 'browser/ui/webui/extensions/extension_icon_source.cc', 'browser/ui/webui/extensions/extension_icon_source.h', - 'browser/ui/webui/extensions/pack_extension_handler.cc', - 'browser/ui/webui/extensions/pack_extension_handler.h', 'browser/ui/webui/voice_search_ui.cc', 'browser/ui/webui/voice_search_ui.h', ], @@ -2668,6 +2684,7 @@ '../components/components.gyp:device_event_log_component', '../components/components.gyp:dom_distiller_core', '../components/components.gyp:dom_distiller_webui', + '../components/components.gyp:feedback_proto', '../components/components.gyp:history_core_browser_proto', '../components/components.gyp:invalidation', '../components/components.gyp:onc_component', @@ -2852,16 +2869,33 @@ ['OS=="mac"', { 'conditions': [ ['mac_views_browser==1', { + 'sources': [ + '<@(chrome_browser_ui_views_mac_experimental_sources)', + ], 'sources!': [ + 'browser/ui/cocoa/apps/chrome_app_window_client_cocoa.mm', 'browser/ui/cocoa/bookmarks/bookmark_drag_drop_cocoa.mm', 'browser/ui/cocoa/browser_window_factory_cocoa.mm', 'browser/ui/cocoa/infobars/confirm_infobar_controller.mm', 'browser/ui/cocoa/tab_dialogs_cocoa.mm', ], + 'dependencies': [ + '<(DEPTH)/extensions/components/extensions_components.gyp:native_app_window', + ], }, { 'sources!': [ + 'browser/ui/views/apps/chrome_native_app_window_views.cc', + 'browser/ui/views/apps/chrome_native_app_window_views.h', + 'browser/ui/views/apps/desktop_keyboard_capture.cc', + 'browser/ui/views/apps/desktop_keyboard_capture.h', + 'browser/ui/views/apps/keyboard_hook_handler.cc', + 'browser/ui/views/apps/keyboard_hook_handler.h', 'browser/ui/views/bookmarks/bookmark_drag_drop_views.cc', + 'browser/ui/views/extensions/extension_keybinding_registry_views.cc', + 'browser/ui/views/extensions/extension_keybinding_registry_views.h', 'browser/ui/views/frame/browser_window_factory.cc', + 'browser/ui/views/frame/taskbar_decorator.cc', + 'browser/ui/views/frame/taskbar_decorator.h', 'browser/ui/views/infobar/confirm_infobar.cc' 'browser/ui/views/tab_dialogs_views.cc', ], @@ -2928,6 +2962,7 @@ 'chrome_browser_jni_headers', ], 'dependencies!': [ + '../components/components.gyp:feedback_proto', '../ui/events/events.gyp:events', 'chrome_browser_ui_views.gyp:browser_ui_views', ], @@ -3001,6 +3036,7 @@ ], 'sources': [ '<@(chrome_browser_ui_win_sources)' ], 'sources!': [ + 'browser/ui/views/apps/keyboard_hook_handler.cc', 'browser/ui/views/frame/taskbar_decorator.cc' ], 'conditions': [ @@ -3124,7 +3160,6 @@ }], ['OS!="android" and OS!="ios"', { 'dependencies': [ - '../components/components.gyp:feedback_proto', '../device/bluetooth/bluetooth.gyp:device_bluetooth', '../third_party/libusb/libusb.gyp:libusb', ],
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index 0ecfd4f4..6a80c5b 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi
@@ -51,6 +51,8 @@ 'common/custom_handlers/protocol_handler.cc', 'common/custom_handlers/protocol_handler.h', 'common/descriptors_android.h', + 'common/favicon/fallback_icon_url_parser.cc', + 'common/favicon/fallback_icon_url_parser.h', 'common/favicon/favicon_url_parser.cc', 'common/favicon/favicon_url_parser.h', 'common/icon_with_badge_image_source.cc', @@ -317,6 +319,7 @@ '<(DEPTH)/crypto/crypto.gyp:crypto', '<(DEPTH)/net/net.gyp:net', '<(DEPTH)/skia/skia.gyp:skia', + '<(DEPTH)/skia/skia.gyp:skia_library', '<(DEPTH)/third_party/icu/icu.gyp:icui18n', '<(DEPTH)/third_party/icu/icu.gyp:icuuc', '<(DEPTH)/third_party/libxml/libxml.gyp:libxml',
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index bd748de..65878f6 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi
@@ -258,7 +258,7 @@ '../third_party/re2/re2.gyp:re2', '../components/components.gyp:autofill_content_renderer', '../components/components.gyp:cdm_renderer', - '../components/components.gyp:data_reduction_proxy_core_common', + '../components/components.gyp:data_reduction_proxy_content_common', '../components/components.gyp:network_hints_renderer', '../components/components.gyp:error_page_renderer', '../components/components.gyp:startup_metric_utils',
diff --git a/chrome/chrome_repack_resources.gypi b/chrome/chrome_repack_resources.gypi index 667d7152..079364734 100644 --- a/chrome/chrome_repack_resources.gypi +++ b/chrome/chrome_repack_resources.gypi
@@ -24,6 +24,7 @@ ['chromeos==1', { 'pak_inputs': [ '<(SHARED_INTERMEDIATE_DIR)/ui/file_manager/file_manager_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/ui/oobe/oobe_resources.pak', ], }], ['OS != "ios"', {
diff --git a/chrome/chrome_shell.gypi b/chrome/chrome_shell.gypi index e7b9e4e..ea368a0 100644 --- a/chrome/chrome_shell.gypi +++ b/chrome/chrome_shell.gypi
@@ -19,7 +19,7 @@ '../base/base.gyp:base', 'chrome_android_core', 'chrome.gyp:browser_ui', - '../content/content.gyp:content_app_browser', + '../content/content.gyp:content_app_both', ], 'direct_dependent_settings': { 'ldflags': [ @@ -48,6 +48,7 @@ 'target_name': 'libchromeshell', 'type': 'shared_library', 'sources': [ + 'android/shell/chrome_shell_entry_point.cc', 'android/shell/chrome_main_delegate_chrome_shell_android.cc', 'android/shell/chrome_main_delegate_chrome_shell_android.h', ], @@ -65,6 +66,7 @@ 'target_name': 'libchromesyncshell', 'type': 'shared_library', 'sources': [ + 'android/shell/chrome_shell_entry_point.cc', 'android/sync_shell/chrome_main_delegate_chrome_sync_shell_android.cc', 'android/sync_shell/chrome_main_delegate_chrome_sync_shell_android.h', ],
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 015a219a..15e19d75 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi
@@ -365,6 +365,7 @@ 'browser/profiles/profile_list_desktop_browsertest.cc', 'browser/profiles/profile_manager_browsertest.cc', 'browser/profiles/profile_window_browsertest.cc', + 'browser/push_messaging/push_messaging_browsertest.cc', 'browser/referrer_policy_browsertest.cc', 'browser/renderer_context_menu/render_view_context_menu_browsertest.cc', 'browser/renderer_context_menu/render_view_context_menu_browsertest_util.cc', @@ -382,7 +383,6 @@ 'browser/service_process/service_process_control_browsertest.cc', 'browser/services/gcm/fake_gcm_profile_service.cc', 'browser/services/gcm/fake_gcm_profile_service.h', - 'browser/services/gcm/push_messaging_browsertest.cc', 'browser/sessions/better_session_restore_browsertest.cc', 'browser/sessions/persistent_tab_restore_service_browsertest.cc', 'browser/sessions/session_restore_browsertest.cc', @@ -657,6 +657,7 @@ 'browser/chromeos/login/enrollment/mock_enrollment_screen.cc', 'browser/chromeos/login/enrollment/mock_enrollment_screen.h', 'browser/chromeos/login/existing_user_controller_browsertest.cc', + 'browser/chromeos/login/hid_detection_browsertest.cc', 'browser/chromeos/login/kiosk_browsertest.cc', 'browser/chromeos/login/lock/screen_locker_tester.cc', 'browser/chromeos/login/lock/screen_locker_tester.h',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index e49743e..35588589 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi
@@ -208,6 +208,8 @@ 'browser/profiles/profile_info_cache_unittest.h', 'browser/profiles/profile_manager_unittest.cc', 'browser/profiles/profile_shortcut_manager_unittest_win.cc', + 'browser/push_messaging/push_messaging_application_id_unittest.cc', + 'browser/push_messaging/push_messaging_permission_context_unittest.cc', 'browser/renderer_context_menu/render_view_context_menu_test_util.cc', 'browser/renderer_context_menu/render_view_context_menu_test_util.h', 'browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_unit_test.mm', @@ -240,8 +242,6 @@ 'browser/services/gcm/fake_signin_manager.cc', 'browser/services/gcm/fake_signin_manager.h', 'browser/services/gcm/gcm_account_tracker_unittest.cc', - 'browser/services/gcm/push_messaging_application_id_unittest.cc', - 'browser/services/gcm/push_messaging_permission_context_unittest.cc', 'browser/shell_integration_win_unittest.cc', 'browser/signin/account_reconcilor_unittest.cc', 'browser/signin/account_service_flag_fetcher_unittest.cc', @@ -459,6 +459,7 @@ 'browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm', 'browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm', 'browser/ui/cocoa/panels/panel_cocoa_unittest.mm', + 'browser/ui/cocoa/passwords/credential_item_view_unittest.mm', 'browser/ui/cocoa/passwords/manage_password_item_view_controller_unittest.mm', 'browser/ui/cocoa/passwords/manage_passwords_bubble_blacklist_view_controller_unittest.mm', 'browser/ui/cocoa/passwords/manage_passwords_bubble_cocoa_unittest.mm', @@ -541,6 +542,7 @@ 'common/chrome_paths_unittest.cc', 'common/cloud_print/cloud_print_helpers_unittest.cc', 'common/crash_keys_unittest.cc', + 'common/favicon/fallback_icon_url_parser_unittest.cc', 'common/favicon/favicon_url_parser_unittest.cc', 'common/ini_parser_unittest.cc', 'common/instant_types_unittest.cc', @@ -1292,6 +1294,7 @@ 'browser/chromeos/system/device_disabling_manager_unittest.cc', 'browser/chromeos/ui/accessibility_focus_ring_controller_unittest.cc', 'browser/chromeos/ui/idle_app_name_notification_view_unittest.cc', + 'browser/download/notification/download_notification_item_unittest.cc', 'browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc', 'browser/extensions/api/log_private/syslog_parser_unittest.cc', 'browser/extensions/updater/local_extension_cache_unittest.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index b992b224..0508a62e 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc
@@ -408,10 +408,13 @@ "enable-device-discovery-notifications"; // Enables the DOM distiller. -const char kEnableDomDistiller[] = "enable-dom-distiller"; +const char kEnableDomDistiller[] = "enable-dom-distiller"; // Enables Domain Reliability Monitoring. -const char kEnableDomainReliability[] = "enable-domain-reliability"; +const char kEnableDomainReliability[] = "enable-domain-reliability"; + +// Enables Download Notification. +const char kEnableDownloadNotification[] = "enable-download-notification"; // Enable Enhanced Bookmarks. const char kEnhancedBookmarksExperiment[] = "enhanced-bookmarks-experiment";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 87f1e06..789aace 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h
@@ -123,6 +123,7 @@ extern const char kEnableDomDistiller[]; extern const char kEnhancedBookmarksExperiment[]; extern const char kEnableDomainReliability[]; +extern const char kEnableDownloadNotification[]; extern const char kEnableEphemeralAppsInWebstore[]; extern const char kDisableExperimentalHotwording[]; extern const char kEnableExperimentalHotwordHardware[];
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json index 8403c66..5526be9 100644 --- a/chrome/common/extensions/api/_api_features.json +++ b/chrome/common/extensions/api/_api_features.json
@@ -75,6 +75,11 @@ "contexts": ["blessed_extension", "unblessed_extension", "content_script"], "matches": [] }, + "appviewTag": { + "internal": true, + "dependencies": ["permission:appview"], + "contexts": ["blessed_extension"] + }, "audioModem": { "dependencies": ["permission:audioModem"], "contexts": ["blessed_extension"] @@ -157,6 +162,10 @@ "dependencies": ["permission:cast.streaming"], "contexts": ["blessed_extension"] }, + "cast.streaming.receiverSession": { + "dependencies": ["permission:cast.streaming"], + "contexts": ["blessed_extension"] + }, "cast.streaming.session": { "dependencies": ["permission:cast.streaming"], "contexts": ["blessed_extension"] @@ -528,7 +537,7 @@ "mimeHandlerViewGuestInternal": { "internal": true, "contexts": "all", - "channel": "dev", + "channel": "stable", "matches": ["<all_urls>"] }, "musicManagerPrivate": {
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index c08ea657..7313dc44 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json
@@ -96,20 +96,10 @@ "extension_types": ["extension", "legacy_packaged_app", "platform_app"], "location": "component" }, - "browser": [ - { - "channel": "dev", - "extension_types": ["platform_app"] - }, - { - "channel": "stable", - "extension_types": ["platform_app"], - "whitelist": [ - // hotword_audio_verification - "B6356EFF4047BC5F868C7D91868B6F5C01951A8A" - ] - } - ], + "browser": { + "channel": "stable", + "extension_types": ["platform_app"] + }, "browsingData": { "channel": "stable", "extension_types": ["extension", "legacy_packaged_app"] @@ -989,8 +979,7 @@ "extension_types": ["extension", "legacy_packaged_app", "hosted_app"], "whitelist": [ "B44D08FD98F1523ED5837D78D0A606EA9D6206E5", // Web Store - "2653F6F6C39BC6EEBD36A09AFB92A19782FF7EB4", // Enterprise Web Store - "2779FA8B45841D61A37207CCFAC9CB393964FE5B" // Login Proxy (prototype) + "2653F6F6C39BC6EEBD36A09AFB92A19782FF7EB4" // Enterprise Web Store ] } }
diff --git a/chrome/common/extensions/api/appview_tag.idl b/chrome/common/extensions/api/appview_tag.idl new file mode 100644 index 0000000..2d8119c --- /dev/null +++ b/chrome/common/extensions/api/appview_tag.idl
@@ -0,0 +1,46 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Use the <code>appview</code> tag to embed other Chrome Apps within your +// Chrome App. (see <a href=#usage>Usage</a>). +[documentation_title="<appview> Tag", + documentation_namespace="<appview>", + documented_in="tags/appview"] +namespace appviewTag { + // This object specifies details and operations to perform on the embedding + // request. The app to be embedded can make a decision on whether or not to + // allow the embedding and what to embed based on the embedder making the + // request. + dictionary EmbedRequest { + // Optional developer specified data that the app to be embedded can use + // when making an embedding decision. + object data; + + // Allows the embedding request. + // + // |url| : Specifies the content to be embedded. + static void allow(DOMString url); + + // Prevents the embedding request. + static void deny(); + }; + + // An optional function that's called after the embedding request is + // completed. + // + // |success| : True if the embedding request succeded. + callback EmbeddingCallback = void (boolean success); + + interface Functions { + // Requests another app to be embedded. + // + // |app| : The extension id of the app to be embedded. + // |data| : Optional developer specified data that the app to be embedded + // can use when making an embedding decision. + // |callback| : An optional function that's called after the embedding + // request is completed. + static void connect(DOMString app, optional any data, + optional EmbeddingCallback callback); + }; +};
diff --git a/chrome/common/extensions/api/cast_streaming_receiver_session.idl b/chrome/common/extensions/api/cast_streaming_receiver_session.idl new file mode 100644 index 0000000..15a7f0a7 --- /dev/null +++ b/chrome/common/extensions/api/cast_streaming_receiver_session.idl
@@ -0,0 +1,70 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// The <code>chrome.cast.streaming.receiverSession</code> API creates a Cast +// receiver session and adds the resulting audio and video tracks to a +// MediaStream. +namespace cast.streaming.receiverSession { + // The UDP socket address and port. + dictionary IPEndPoint { + DOMString address; + long port; + }; + + // RTP receiver parameters. + dictionary RtpReceiverParams { + // Maximum latency in milliseconds. This parameter controls the logic + // of flow control. Implementation can adjust latency adaptively and + // tries to keep it under this threshold. A larger value allows smoother + // playback at the cost of higher latency. + long maxLatency; + + DOMString codecName; + + // Synchronization source identifier for incoming data. + long senderSsrc; + + // The SSRC used to send RTCP reports back to the sender. + long receiverSsrc; + + // RTP time units per second, defaults to 48000 for audio + // and 90000 for video. + long? rtpTimebase; + + // 32 bytes hex-encoded AES key. + DOMString? aesKey; + + // 32 bytes hex-encoded AES IV (Initialization vector) mask. + DOMString? aesIvMask; + }; + + callback ErrorCallback = void (DOMString error); + + interface Functions { + // Creates a Cast receiver session which receives data from a UDP + // socket. The receiver will decode the incoming data into an audio + // and a video track which will be added to the provided media stream. + // The |audioParams| and |videoParams| are generally provided by the + // sender through some other messaging channel. + // + // |audioParams| : Audio stream parameters. + // |videoParams| : Video stream parameters. + // |localEndpoint| : Local IP and port to bind to. + // |height| : Video height. + // |width| : Video width. + // |maxFrameRate| : Max video frame rate. + // |mediaStreamURL| : URL of MediaStream to add the audio and video to. + // |transport_options| : Optional transport settings. + [nocompile] static void createAndBind( + RtpReceiverParams audioParams, + RtpReceiverParams videoParams, + IPEndPoint localEndpoint, + long maxWidth, + long maxHeight, + double maxFrameRate, + DOMString mediaStreamURL, + ErrorCallback error_callback, + optional object transport_options); + }; +};
diff --git a/chrome/common/extensions/api/developer_private.idl b/chrome/common/extensions/api/developer_private.idl index af512349..0d61886e 100644 --- a/chrome/common/extensions/api/developer_private.idl +++ b/chrome/common/extensions/api/developer_private.idl
@@ -78,7 +78,13 @@ dictionary ReloadOptions { // If false, an alert dialog will show in the event of a reload error. // Defaults to false. - boolean failQuietly; + boolean? failQuietly; + }; + + dictionary LoadUnpackedOptions { + // If false, an alert dialog will show in the event of a reload error. + // Defaults to false. + boolean? failQuietly; }; enum PackStatus { @@ -247,7 +253,9 @@ optional VoidCallback callback); // Loads a user-selected unpacked item. - static void loadUnpacked(optional VoidCallback callback); + // |options| : Additional configuration parameters. + static void loadUnpacked(optional LoadUnpackedOptions options, + optional VoidCallback callback); // Loads an extension / app. // |directory| : The directory to load the extension from.
diff --git a/chrome/common/extensions/api/schemas.gypi b/chrome/common/extensions/api/schemas.gypi index f29dbc62..46e2711 100644 --- a/chrome/common/extensions/api/schemas.gypi +++ b/chrome/common/extensions/api/schemas.gypi
@@ -120,6 +120,7 @@ ], 'webrtc_schema_files': [ + 'cast_streaming_receiver_session.idl', 'cast_streaming_rtp_stream.idl', 'cast_streaming_session.idl', 'cast_streaming_udp_transport.idl',
diff --git a/chrome/common/extensions/docs/examples/api/contentSettings/popup.html b/chrome/common/extensions/docs/examples/api/contentSettings/popup.html index dc3c9f0..bbc62c52 100644 --- a/chrome/common/extensions/docs/examples/api/contentSettings/popup.html +++ b/chrome/common/extensions/docs/examples/api/contentSettings/popup.html
@@ -2,34 +2,27 @@ <html> <head> <title>Popup</title> + <style> + dt { white-space: nowrap } + </style> <script src="popup.js"></script> </head> <body> <fieldset> <dl> <dt><label for="cookies">Cookies: </label></dt> - <dd><select id="cookies"> + <dd><select id="cookies" disabled> <option value="allow">Allow</option> <option value="session_only">Session only</option> <option value="block">Block</option> </select></dd> <dt><label for="images">Images: </label></dt> - <dd><select id="images"> + <dd><select id="images" disabled> <option value="allow">Allow</option> <option value="block">Block</option> </select> <dt><label for="javascript">Javascript: </label></dt> - <dd><select id="javascript"> - <option value="allow">Allow</option> - <option value="block">Block</option> - </select></dd> - <dt><label for="plugins">Plug-ins: </label></dt> - <dd><select id="plugins"> - <option value="allow">Allow</option> - <option value="block">Block</option> - </select></dd> - <dt><label for="popups">Pop-ups: </label></dt> - <dd><select id="popups"> + <dd><select id="javascript" disabled> <option value="allow">Allow</option> <option value="block">Block</option> </select></dd> @@ -39,8 +32,53 @@ <option value="ask">Ask</option> <option value="block">Block</option> </select></dd> + <dt><label for="plugins">Plug-ins: </label></dt> + <dd><select id="plugins" disabled> + <option value="allow">Allow</option> + <option value="block">Block</option> + </select></dd> + <dt><label for="popups">Pop-ups: </label></dt> + <dd><select id="popups" disabled> + <option value="allow">Allow</option> + <option value="block">Block</option> + </select></dd> <dt><label for="notifications">Notifications: </label></dt> - <dd><select id="notifications"> + <dd><select id="notifications" disabled> + <option value="allow">Allow</option> + <option value="ask">Ask</option> + <option value="block">Block</option> + </select></dd> + <dt><label for="fullscreen">Fullscreen: </label></dt> + <dd><select id="fullscreen" disabled> + <option value="allow">Allow</option> + <option value="ask">Ask</option> + </select></dd> + <dt><label for="mouselock">Mouse cursor: </label></dt> + <dd><select id="mouselock" disabled> + <option value="allow">Allow</option> + <option value="ask">Ask</option> + <option value="block">Block</option> + </select></dd> + <dt><label for="microphone">Microphone: </label></dt> + <dd><select id="microphone" disabled> + <option value="allow">Allow</option> + <option value="ask">Ask</option> + <option value="block">Block</option> + </select></dd> + <dt><label for="camera">Camera: </label></dt> + <dd><select id="camera" disabled> + <option value="allow">Allow</option> + <option value="ask">Ask</option> + <option value="block">Block</option> + </select></dd> + <dt><label for="unsandboxedPlugins">Unsandboxed plug-in access: </label></dt> + <dd><select id="unsandboxedPlugins" disabled> + <option value="allow">Allow</option> + <option value="ask">Ask</option> + <option value="block">Block</option> + </select></dd> + <dt><label for="automaticDownloads">Automatic Downloads: </label></dt> + <dd><select id="automaticDownloads" disabled> <option value="allow">Allow</option> <option value="ask">Ask</option> <option value="block">Block</option>
diff --git a/chrome/common/extensions/docs/examples/api/contentSettings/popup.js b/chrome/common/extensions/docs/examples/api/contentSettings/popup.js index ed2dfc7..74ef60d 100644 --- a/chrome/common/extensions/docs/examples/api/contentSettings/popup.js +++ b/chrome/common/extensions/docs/examples/api/contentSettings/popup.js
@@ -25,17 +25,20 @@ var current = tabs[0]; incognito = current.incognito; url = current.url; - var types = ['cookies', 'images', 'javascript', 'plugins', 'popups', - 'notifications']; + var types = ['cookies', 'images', 'javascript', 'location', 'plugins', + 'popups', 'notifications', 'fullscreen', 'mouselock', + 'microphone', 'camera', 'unsandboxedPlugins', + 'automaticDownloads']; types.forEach(function(type) { // HACK: [type] is not recognised by the docserver's sample crawler, so // mention an explicit // type: chrome.contentSettings.cookies.get - See http://crbug.com/299634 - chrome.contentSettings[type].get({ + chrome.contentSettings[type] && chrome.contentSettings[type].get({ 'primaryUrl': url, 'incognito': incognito }, function(details) { + document.getElementById(type).disabled = false; document.getElementById(type).value = details.setting; }); });
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml index 9b6da0f9..ac922a7 100644 --- a/chrome/common/extensions/docs/server2/app.yaml +++ b/chrome/common/extensions/docs/server2/app.yaml
@@ -1,5 +1,5 @@ application: chrome-apps-doc -version: 3-47-4 +version: 3-48-0 runtime: python27 api_version: 1 threadsafe: false
diff --git a/chrome/common/extensions/docs/server2/cron.yaml b/chrome/common/extensions/docs/server2/cron.yaml index 145a3700..7c8d833 100644 --- a/chrome/common/extensions/docs/server2/cron.yaml +++ b/chrome/common/extensions/docs/server2/cron.yaml
@@ -1,5 +1,5 @@ cron: - description: Repopulates all cached data. url: /_cron - schedule: every 60 minutes - target: 3-47-4 + schedule: every 180 minutes + target: 3-48-0
diff --git a/chrome/common/extensions/docs/templates/intros/appview_tag.html b/chrome/common/extensions/docs/templates/intros/appview_tag.html new file mode 100644 index 0000000..18b47676 --- /dev/null +++ b/chrome/common/extensions/docs/templates/intros/appview_tag.html
@@ -0,0 +1,47 @@ +<h2 id="usage">Usage</h2> + +<p> +Use the <code>appview</code> tag to embed other Chrome Apps within your Chrome +App. +</p> + +<p> +The <code>appview</code> runs in a separate process from your app, it doesn't +inherit the same permissions and is only allowed to interact with your app +through asynchronous APIs. +Not all apps can be embedded; apps have to explicitly allow themselves to be +embedded. +</p> + +<h2 id="embedder">Preparing your app to be embedded</h2> + +<p> +To allow your app to be embedded into another app, you need to add a listener +to your app's background page: +</p> + +<pre data-filename="background.js"> +chrome.app.runtime.onEmbedRequested.addListener(function(request) { + // Allows the embedder to embed foo.html. + request.allow("foo.html"); +}); +</pre> + +<h2 id="embedded">Embedding another app</h2> + +<p> +To embed another Chrome App in your app, add the <code>appview</code> tag to +your app's embedder page (this is the app page that will display the +embedded app) and use the connect API to request the embedding of the other +app. +</p> + +<pre data-filename="background.js"> +// Creates an <appview> element. +var appview = document.createElement("appview"); +// Appends the element to the document body. +document.body.appendChild(appview); +// Connects the appview to appToEmbed. +// appToEmbed is the id of the app you are trying to embed. +appview.connect(appToEmbed); +</pre>
diff --git a/chrome/common/extensions/docs/templates/json/chrome_sidenav.json b/chrome/common/extensions/docs/templates/json/chrome_sidenav.json index e91adbe..5dffe01a 100644 --- a/chrome/common/extensions/docs/templates/json/chrome_sidenav.json +++ b/chrome/common/extensions/docs/templates/json/chrome_sidenav.json
@@ -497,6 +497,10 @@ "href": "/apps/tags/webview" }, { + "title": "Appview Tag", + "href": "/apps/tags/appview" + }, + { "title": "Web APIs", "href": "/apps/api_other" },
diff --git a/chrome/common/extensions/docs/templates/public/apps/browser.html b/chrome/common/extensions/docs/templates/public/apps/browser.html new file mode 100644 index 0000000..10c2f07 --- /dev/null +++ b/chrome/common/extensions/docs/templates/public/apps/browser.html
@@ -0,0 +1 @@ +{{+partials.standard_apps_api api:apis.apps.browser/}}
diff --git a/chrome/common/extensions/extension_test_util.cc b/chrome/common/extensions/extension_test_util.cc index e30dd15a..ec223f6 100644 --- a/chrome/common/extensions/extension_test_util.cc +++ b/chrome/common/extensions/extension_test_util.cc
@@ -30,8 +30,8 @@ .AppendASCII(dir) .AppendASCII(test_file); - JSONFileValueSerializer serializer(path); - scoped_ptr<base::Value> result(serializer.Deserialize(NULL, error)); + JSONFileValueDeserializer deserializer(path); + scoped_ptr<base::Value> result(deserializer.Deserialize(NULL, error)); if (!result) return NULL; const base::DictionaryValue* dict;
diff --git a/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc b/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc index 9d60a63..82bda5a 100644 --- a/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc +++ b/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc
@@ -74,7 +74,7 @@ TEST_F(OverrideSettingsTest, ParseManifest) { std::string manifest(kManifest); - JSONStringValueSerializer json(&manifest); + JSONStringValueDeserializer json(manifest); std::string error; scoped_ptr<base::Value> root(json.Deserialize(NULL, &error)); ASSERT_TRUE(root); @@ -117,7 +117,7 @@ TEST_F(OverrideSettingsTest, ParsePrepopulatedId) { std::string manifest(kPrepopulatedManifest); - JSONStringValueSerializer json(&manifest); + JSONStringValueDeserializer json(manifest); std::string error; scoped_ptr<base::Value> root(json.Deserialize(NULL, &error)); ASSERT_TRUE(root); @@ -150,7 +150,7 @@ TEST_F(OverrideSettingsTest, ParseBrokenManifest) { std::string manifest(kBrokenManifest); - JSONStringValueSerializer json(&manifest); + JSONStringValueDeserializer json(manifest); std::string error; scoped_ptr<base::Value> root(json.Deserialize(NULL, &error)); ASSERT_TRUE(root);
diff --git a/chrome/common/extensions/manifest_handlers/ui_overrides_handler_unittest.cc b/chrome/common/extensions/manifest_handlers/ui_overrides_handler_unittest.cc index 007d102b..75a6857 100644 --- a/chrome/common/extensions/manifest_handlers/ui_overrides_handler_unittest.cc +++ b/chrome/common/extensions/manifest_handlers/ui_overrides_handler_unittest.cc
@@ -50,7 +50,7 @@ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( "--enable-override-bookmarks-ui", "1"); std::string manifest(kManifest); - JSONStringValueSerializer json(&manifest); + JSONStringValueDeserializer json(manifest); std::string error; scoped_ptr<base::Value> root(json.Deserialize(NULL, &error)); ASSERT_TRUE(root); @@ -78,7 +78,7 @@ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( "--enable-override-bookmarks-ui", "1"); std::string manifest(kBrokenManifest); - JSONStringValueSerializer json(&manifest); + JSONStringValueDeserializer json(manifest); std::string error; scoped_ptr<base::Value> root(json.Deserialize(NULL, &error)); ASSERT_TRUE(root);
diff --git a/chrome/common/favicon/fallback_icon_url_parser.cc b/chrome/common/favicon/fallback_icon_url_parser.cc new file mode 100644 index 0000000..418617f --- /dev/null +++ b/chrome/common/favicon/fallback_icon_url_parser.cc
@@ -0,0 +1,84 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/favicon/fallback_icon_url_parser.h" + +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "third_party/skia/include/utils/SkParse.h" +#include "ui/gfx/favicon_size.h" + +namespace chrome { + +ParsedFallbackIconPath::ParsedFallbackIconPath() + : size_in_pixels_(gfx::kFaviconSize) { +} + +ParsedFallbackIconPath::~ParsedFallbackIconPath() { +} + +bool ParsedFallbackIconPath::Parse(const std::string& path) { + if (path.empty()) + return false; + + size_t slash = path.find("/", 0); + if (slash == std::string::npos) + return false; + std::string spec_str = path.substr(0, slash); + if (!ParseSpecs(spec_str, &size_in_pixels_, &style_)) + return false; // Parse failed. + + // Extract URL, which may be empty (if first slash appears at the end). + std::string url_str = path.substr(slash + 1); + url_ = GURL(url_str); + return url_str.empty() || url_.is_valid(); // Allow empty URL. +} + +// static +bool ParsedFallbackIconPath::ParseSpecs( + const std::string& specs_str, + int *size, + favicon_base::FallbackIconStyle* style) { + DCHECK(size); + DCHECK(style); + + std::vector<std::string> tokens; + base::SplitStringDontTrim(specs_str, ',', &tokens); + if (tokens.size() != 5) // Force "," for empty fields. + return false; + + *size = gfx::kFaviconSize; + if (!tokens[0].empty() && !base::StringToInt(tokens[0], size)) + return false; + if (*size <= 0) + return false; + + if (!tokens[1].empty() && !ParseColor(tokens[1], &style->background_color)) + return false; + + if (tokens[2].empty()) + favicon_base::MatchFallbackIconTextColorAgainstBackgroundColor(style); + else if (!ParseColor(tokens[2], &style->text_color)) + return false; + + if (!tokens[3].empty() && + !base::StringToDouble(tokens[3], &style->font_size_ratio)) + return false; + + if (!tokens[4].empty() && !base::StringToDouble(tokens[4], &style->roundness)) + return false; + + return favicon_base::ValidateFallbackIconStyle(*style); +} + +// static +bool ParsedFallbackIconPath::ParseColor(const std::string& color_str, + SkColor* color) { + const char* end = SkParse::FindColor(color_str.c_str(), color); + // Return true if FindColor() succeeds and |color_str| is entirely consumed. + return end && !*end; +} + +} // namespace chrome
diff --git a/chrome/common/favicon/fallback_icon_url_parser.h b/chrome/common/favicon/fallback_icon_url_parser.h new file mode 100644 index 0000000..12a068f4 --- /dev/null +++ b/chrome/common/favicon/fallback_icon_url_parser.h
@@ -0,0 +1,67 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_COMMON_FAVICON_FALLBACK_ICON_URL_PARSER_H_ +#define CHROME_COMMON_FAVICON_FALLBACK_ICON_URL_PARSER_H_ + +#include <string> + +#include "base/gtest_prod_util.h" +#include "base/macros.h" +#include "components/favicon_base/fallback_icon_style.h" +#include "third_party/skia/include/core/SkColor.h" +#include "url/gurl.h" + +namespace chrome { + +class ParsedFallbackIconPath { + public: + ParsedFallbackIconPath(); + ~ParsedFallbackIconPath(); + + const GURL& url() const { return url_; } + + int size_in_pixels() const { return size_in_pixels_; } + + const favicon_base::FallbackIconStyle& style() const { return style_; } + + // Parses |path|, which should be in the format described at the top of the + // file "chrome/browser/ui/webui/fallback_icon_source.h". + bool Parse(const std::string& path); + + private: + // Parses |specs_str|, which should be the comma-separated value portion + // in the format described at the top of the file + // "chrome/browser/ui/webui/fallback_icon_source.h". + static bool ParseSpecs(const std::string& specs_str, + int *size, + favicon_base::FallbackIconStyle* style); + + // Helper to parse color string (e.g., "red", "#f00", "#fF0000"). Returns true + // on success. + static bool ParseColor(const std::string& color_str, SkColor* color); + + friend class FallbackIconUrlParserTest; + FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseColorSuccess); + FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseColorFailure); + FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseSpecsEmpty); + FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseSpecsPartial); + FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseSpecsFull); + FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseSpecsFailure); + + // The page URL the fallback icon is requested for. + GURL url_; + + // The size of the requested fallback icon in pixels. + int size_in_pixels_; + + // Styling specifications of fallback icon. + favicon_base::FallbackIconStyle style_; + + DISALLOW_COPY_AND_ASSIGN(ParsedFallbackIconPath); +}; + +} // namespace chrome + +#endif // CHROME_COMMON_FAVICON_FALLBACK_ICON_URL_PARSER_H_
diff --git a/chrome/common/favicon/fallback_icon_url_parser_unittest.cc b/chrome/common/favicon/fallback_icon_url_parser_unittest.cc new file mode 100644 index 0000000..76a761c0 --- /dev/null +++ b/chrome/common/favicon/fallback_icon_url_parser_unittest.cc
@@ -0,0 +1,267 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/favicon/fallback_icon_url_parser.h" + +#include "base/memory/scoped_ptr.h" +#include "components/favicon_base/fallback_icon_style.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/favicon_size.h" +#include "url/gurl.h" + +using chrome::ParsedFallbackIconPath; +using favicon_base::FallbackIconStyle; + +namespace chrome { + +namespace { + +// Default values for FallbackIconStyle, from +// /components/favicon_base/fallback_icon_style.h +SkColor kDefaultBackgroundColor = SkColorSetRGB(0x80, 0x80, 0x80); +SkColor kDefaultTextColorDark = SK_ColorBLACK; +SkColor kDefaultTextColorLight = SK_ColorWHITE; +double kDefaultFontSizeRatio = 0.8; +double kDefaultRoundness = 0.125; // 1 / 8. + +const char kTestUrlStr[] = "https://www.google.ca/imghp?hl=en&tab=wi"; + +} // namespace + +class FallbackIconUrlParserTest : public testing::Test { + public: + FallbackIconUrlParserTest() { + } + + bool ParseSpecs(const std::string& specs_str, + int *size, + favicon_base::FallbackIconStyle* style) { + return ParsedFallbackIconPath::ParseSpecs(specs_str, size, style); + } + + bool ParseColor(const std::string& color_str, SkColor* color) { + int size_dummy; + favicon_base::FallbackIconStyle style; + std::string spec_str = "16," + color_str + ",,,"; + if (!ParseSpecs(spec_str, &size_dummy, &style)) + return false; + *color = style.background_color; + return true; + } + + private: + DISALLOW_COPY_AND_ASSIGN(FallbackIconUrlParserTest); +}; + +TEST_F(FallbackIconUrlParserTest, ParseColorSuccess) { + SkColor c; + EXPECT_TRUE(ParseColor("#01aBf0f4", &c)); + EXPECT_EQ(SkColorSetARGB(0x01, 0xAB, 0xF0, 0xF4), c); + EXPECT_TRUE(ParseColor("#01aBf0", &c)); + EXPECT_EQ(SkColorSetRGB(0x01, 0xAB, 0xF0), c); + EXPECT_TRUE(ParseColor("#01a", &c)); + EXPECT_EQ(SkColorSetRGB(0x00, 0x11, 0xAA), c); + EXPECT_TRUE(ParseColor("#000000", &c)); + EXPECT_EQ(SkColorSetARGB(0xFF, 0x00, 0x00, 0x00), c); + EXPECT_TRUE(ParseColor("red", &c)); + EXPECT_EQ(SkColorSetARGB(0xFF, 0xFF, 0x00, 0x00), c); +} + +TEST_F(FallbackIconUrlParserTest, ParseColorFailure) { + const char* test_cases[] = { + "#00000", + "#000000000", + " #000000", + "#ABCDEFG", + "000000", + "#000000 ", + }; + for (size_t i = 0; i < arraysize(test_cases); ++i) { + SkColor c; + EXPECT_FALSE(ParseColor(test_cases[i], &c)) + << "test_cases[" << i << "]"; + } +} + +TEST_F(FallbackIconUrlParserTest, ParseSpecsEmpty) { + int size; + FallbackIconStyle style; + EXPECT_TRUE(ParseSpecs(",,,,", &size, &style)); + EXPECT_EQ(16, size); + EXPECT_EQ(kDefaultBackgroundColor, style.background_color); + EXPECT_EQ(kDefaultTextColorLight, style.text_color); + EXPECT_EQ(kDefaultFontSizeRatio, style.font_size_ratio); + EXPECT_EQ(kDefaultRoundness, style.roundness); +} + +TEST_F(FallbackIconUrlParserTest, ParseSpecsPartial) { + int size; + FallbackIconStyle style; + EXPECT_TRUE(ParseSpecs(",,#aCE,,0.1", &size, &style)); + EXPECT_EQ(16, size); + EXPECT_EQ(kDefaultBackgroundColor, style.background_color); + EXPECT_EQ(SkColorSetRGB(0xAA, 0xCC, 0xEE), style.text_color); + EXPECT_EQ(kDefaultFontSizeRatio, style.font_size_ratio); + EXPECT_EQ(0.1, style.roundness); +} + +TEST_F(FallbackIconUrlParserTest, ParseSpecsFull) { + int size; + + { + FallbackIconStyle style; + EXPECT_TRUE(ParseSpecs("16,#000,#f01,0.75,0.25", &size, &style)); + EXPECT_EQ(16, size); + EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color); + EXPECT_EQ(SkColorSetRGB(0xff, 0x00, 0x11), style.text_color); + EXPECT_EQ(0.75, style.font_size_ratio); + EXPECT_EQ(0.25, style.roundness); + } + + { + FallbackIconStyle style; + EXPECT_TRUE(ParseSpecs("48,black,#123456,0.5,0.3", &size, &style)); + EXPECT_EQ(48, size); + EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color); + EXPECT_EQ(SkColorSetRGB(0x12, 0x34, 0x56), style.text_color); + EXPECT_EQ(0.5, style.font_size_ratio); + EXPECT_EQ(0.3, style.roundness); + } + + { + FallbackIconStyle style; + EXPECT_TRUE(ParseSpecs("1,#000,red,0,0", &size, &style)); + EXPECT_EQ(1, size); + EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color); + EXPECT_EQ(SkColorSetRGB(0xFF, 0x00, 0x00), style.text_color); + EXPECT_EQ(0, style.font_size_ratio); + EXPECT_EQ(0, style.roundness); + } +} + +TEST_F(FallbackIconUrlParserTest, ParseSpecsDefaultTextColor) { + int size; + + { + // Dark background -> Light text. + FallbackIconStyle style; + EXPECT_TRUE(ParseSpecs(",#000,,,", &size, &style)); + EXPECT_EQ(kDefaultTextColorLight, style.text_color); + } + + { + // Light background -> Dark text. + FallbackIconStyle style; + EXPECT_TRUE(ParseSpecs(",#fff,,,", &size, &style)); + EXPECT_EQ(kDefaultTextColorDark, style.text_color); + } + + { + // Light background -> Dark text, more params don't matter. + FallbackIconStyle style; + EXPECT_TRUE(ParseSpecs("107,#fff,,0.3,0.5", &size, &style)); + EXPECT_EQ(kDefaultTextColorDark, style.text_color); + } +} + +TEST_F(FallbackIconUrlParserTest, ParseSpecsFailure) { + const char* test_cases[] = { + // Need exactly 5 params. + "", + "16", + "16,black", + "16,black,#fff", + "16,black,#fff,0.75", + ",,," + ",,,,,", + "16,black,#fff,0.75,0.25,junk", + // Don't allow any space. + "16,black,#fff, 0.75,0.25", + "16,black ,#fff,0.75,0.25", + "16,black,#fff,0.75,0.25 ", + // Adding junk text. + "16,black,#fff,0.75,0.25junk", + "junk,black,#fff,0.75,0.25", + "16,#junk,#fff,0.75,0.25", + "16,black,#junk,0.75,0.25", + "16,black,#fff,junk,0.25", + "16,black,#fff,0.75,junk", + // Out of bound. + "0,black,#fff,0.75,0.25", // size. + "4294967296,black,#fff,0.75,0.25", // size. + "-1,black,#fff,0.75,0.25", // size. + "16,black,#fff,-0.1,0.25", // font_size_ratio. + "16,black,#fff,1.1,0.25", // font_size_ratio. + "16,black,#fff,0.75,-0.1", // roundness. + "16,black,#fff,0.75,1.1", // roundness. + }; + for (size_t i = 0; i < arraysize(test_cases); ++i) { + int size; + FallbackIconStyle style; + EXPECT_FALSE(ParseSpecs(test_cases[i], &size, &style)) + << "test_cases[" << i << "]"; + + } +} + +TEST_F(FallbackIconUrlParserTest, ParseFallbackIconPathSuccess) { + const std::string specs = "31,black,#fff,0.75,0.25"; + + // Everything populated. + { + chrome::ParsedFallbackIconPath parsed; + EXPECT_TRUE(parsed.Parse(specs + "/" + kTestUrlStr)); + EXPECT_EQ(GURL(kTestUrlStr), parsed.url()); + EXPECT_EQ(31, parsed.size_in_pixels()); + const favicon_base::FallbackIconStyle& style = parsed.style(); + EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color); + EXPECT_EQ(SkColorSetRGB(0xFF, 0xFF, 0xFF), style.text_color); + EXPECT_EQ(0.75, style.font_size_ratio); + EXPECT_EQ(0.25, style.roundness); + } + + // Empty URL. + { + chrome::ParsedFallbackIconPath parsed; + EXPECT_TRUE(parsed.Parse(specs + "/")); + EXPECT_EQ(GURL(), parsed.url()); + EXPECT_EQ(31, parsed.size_in_pixels()); + const favicon_base::FallbackIconStyle& style = parsed.style(); + EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color); + EXPECT_EQ(SkColorSetRGB(0xFF, 0xFF, 0xFF), style.text_color); + EXPECT_EQ(0.75, style.font_size_ratio); + EXPECT_EQ(0.25, style.roundness); + } + + // Size and style are default. + { + chrome::ParsedFallbackIconPath parsed; + EXPECT_TRUE(parsed.Parse(std::string(",,,,/") + kTestUrlStr)); + EXPECT_EQ(GURL(kTestUrlStr), parsed.url()); + EXPECT_EQ(gfx::kFaviconSize, parsed.size_in_pixels()); + const favicon_base::FallbackIconStyle& style = parsed.style(); + EXPECT_EQ(kDefaultBackgroundColor, style.background_color); + EXPECT_EQ(kDefaultTextColorLight, style.text_color); + EXPECT_EQ(kDefaultFontSizeRatio, style.font_size_ratio); + EXPECT_EQ(kDefaultRoundness, style.roundness); + } +} + +TEST_F(FallbackIconUrlParserTest, ParseFallbackIconPathFailure) { + const char* test_cases[] = { + // Bad size. + "-1,#000,#fff,0.75,0.25/http://www.google.com/", + // Bad specs. + "32,#junk,#fff,0.75,0.25/http://www.google.com/", + // Bad URL. + "32,#000,#fff,0.75,0.25/NOT A VALID URL", + }; + for (size_t i = 0; i < arraysize(test_cases); ++i) { + chrome::ParsedFallbackIconPath parsed; + EXPECT_FALSE(parsed.Parse(test_cases[i])) << "test_cases[" << i << "]"; + } +} + +} // namespace chrome
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 518c0ae3..e49fdc35 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -361,14 +361,6 @@ // window when the user is attempting to quit. Mac only. const char kConfirmToQuitEnabled[] = "browser.confirm_to_quit"; -// OBSOLETE. Enum that specifies whether to enforce a third-party cookie -// blocking policy. This has been superseded by kDefaultContentSettings + -// kBlockThirdPartyCookies. -// 0 - allow all cookies. -// 1 - block third-party cookies -// 2 - block all cookies -const char kCookieBehavior[] = "security.cookie_behavior"; - // Boolean which specifies whether we should ask the user if we should download // a file (true) or just download it automatically. const char kPromptForDownload[] = "download.prompt_for_download"; @@ -376,18 +368,10 @@ // A boolean pref set to true if we're using Link Doctor error pages. const char kAlternateErrorPagesEnabled[] = "alternate_error_pages.enabled"; -// OBSOLETE: new pref now stored with user prefs instead of profile, as -// kDnsPrefetchingStartupList. -const char kDnsStartupPrefetchList[] = "StartupDNSPrefetchList"; - // An adaptively identified list of domain names to be pre-fetched during the // next startup, based on what was actually needed during this startup. const char kDnsPrefetchingStartupList[] = "dns_prefetching.startup_list"; -// OBSOLETE: new pref now stored with user prefs instead of profile, as -// kDnsPrefetchingHostReferralList. -const char kDnsHostReferralList[] = "HostReferralList"; - // A list of host names used to fetch web pages, and their commonly used // sub-resource hostnames (and expected latency benefits from pre-resolving, or // preconnecting to, such sub-resource hostnames). @@ -421,16 +405,6 @@ const char kInstantUIZeroSuggestUrlPrefix[] = "instant_ui.zero_suggest_url_prefix"; -// Used to migrate preferences from local state to user preferences to -// enable multiple profiles. -// BITMASK with possible values (see browser_prefs.cc for enum): -// 0: No preferences migrated. -// 1: DNS preferences migrated: kDnsPrefetchingStartupList and HostReferralList -// 2: Browser window preferences migrated: kDevToolsSplitLocation and -// kBrowserWindowPlacement -const char kMultipleProfilePrefMigration[] = - "local_state.multiple_profile_prefs_version"; - // A boolean pref set to true if prediction of network actions is allowed. // Actions include DNS prefetching, TCP and SSL preconnection, prerendering // of web pages, and resource prefetching. @@ -832,6 +806,12 @@ // A boolean pref that controls whether wake on SSID is enabled. const char kWakeOnWifiSsid[] = "settings.internet.wake_on_wifi_ssid"; +// This is the policy CaptivePortalAuthenticationIgnoresProxy that allows to +// open captive portal authentication pages in a separate window under +// a temporary incognito profile ("signin profile" is used for this purpose), +// which allows to bypass the user's proxy for captive portal authentication. +const char kCaptivePortalAuthenticationIgnoresProxy[] = + "proxy.captive_portal_ignores_proxy"; #endif // defined(OS_CHROMEOS) // The disabled messages in IPC logging.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 29875f2..4e462cf 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -149,12 +149,9 @@ extern const char kContextualSearchEnabled[]; #endif extern const char kConfirmToQuitEnabled[]; -extern const char kCookieBehavior[]; // OBSOLETE extern const char kPromptForDownload[]; extern const char kAlternateErrorPagesEnabled[]; -extern const char kDnsStartupPrefetchList[]; // OBSOLETE extern const char kDnsPrefetchingStartupList[]; -extern const char kDnsHostReferralList[]; // OBSOLETE extern const char kDnsPrefetchingHostReferralList[]; extern const char kDisableSpdy[]; extern const char kHttpServerProperties[]; @@ -165,7 +162,6 @@ extern const char kLastPolicyCheckTime[]; #endif extern const char kInstantUIZeroSuggestUrlPrefix[]; -extern const char kMultipleProfilePrefMigration[]; extern const char kNetworkPredictionEnabled[]; extern const char kNetworkPredictionOptions[]; extern const char kDefaultAppsInstallState[]; @@ -272,6 +268,7 @@ extern const char kFileSystemProviderMounted[]; extern const char kTouchVirtualKeyboardEnabled[]; extern const char kWakeOnWifiSsid[]; +extern const char kCaptivePortalAuthenticationIgnoresProxy[]; #endif // defined(OS_CHROMEOS) extern const char kIpcDisabledMessages[]; extern const char kShowHomeButton[];
diff --git a/chrome/common/safe_browsing/csd.proto b/chrome/common/safe_browsing/csd.proto index 2739f41..cf487918 100644 --- a/chrome/common/safe_browsing/csd.proto +++ b/chrome/common/safe_browsing/csd.proto
@@ -433,6 +433,7 @@ optional uint64 base_address = 2; optional uint32 length = 3; repeated Feature feature = 4; + optional ClientDownloadRequest.ImageHeaders image_headers = 5; } repeated Dll dll = 9; repeated string blacklisted_dll = 10;
diff --git a/chrome/common/service_process_util_linux.cc b/chrome/common/service_process_util_linux.cc index 0ce4927..e2bcb656 100644 --- a/chrome/common/service_process_util_linux.cc +++ b/chrome/common/service_process_util_linux.cc
@@ -66,8 +66,8 @@ } bool ServiceProcessState::TakeSingletonLock() { - state_->initializing_lock_.reset(TakeServiceInitializingLock(true)); - return state_->initializing_lock_.get(); + state_->initializing_lock.reset(TakeServiceInitializingLock(true)); + return state_->initializing_lock.get(); } bool ServiceProcessState::AddToAutoRun() {
diff --git a/chrome/common/service_process_util_mac.mm b/chrome/common/service_process_util_mac.mm index eab7d4e..bf68feb 100644 --- a/chrome/common/service_process_util_mac.mm +++ b/chrome/common/service_process_util_mac.mm
@@ -180,13 +180,13 @@ CFRelease(err); return false; } - state_->launchd_conf_.reset(dict); + state_->launchd_conf.reset(dict); return true; } IPC::ChannelHandle ServiceProcessState::GetServiceProcessChannel() { DCHECK(state_); - NSDictionary *ns_launchd_conf = base::mac::CFToNSCast(state_->launchd_conf_); + NSDictionary *ns_launchd_conf = base::mac::CFToNSCast(state_->launchd_conf); NSDictionary* socket_dict = [ns_launchd_conf objectForKey:@ LAUNCH_JOBKEY_SOCKETS]; NSArray* sockets = @@ -301,7 +301,7 @@ bool ServiceProcessState::StateData::WatchExecutable() { base::mac::ScopedNSAutoreleasePool pool; - NSDictionary* ns_launchd_conf = base::mac::CFToNSCast(launchd_conf_); + NSDictionary* ns_launchd_conf = base::mac::CFToNSCast(launchd_conf); NSString* exe_path = [ns_launchd_conf objectForKey:@ LAUNCH_JOBKEY_PROGRAM]; if (!exe_path) { DLOG(ERROR) << "No " LAUNCH_JOBKEY_PROGRAM; @@ -313,15 +313,15 @@ scoped_ptr<ExecFilePathWatcherCallback> callback( new ExecFilePathWatcherCallback); if (!callback->Init(executable_path)) { - DLOG(ERROR) << "executable_watcher_.Init " << executable_path.value(); + DLOG(ERROR) << "executable_watcher.Init " << executable_path.value(); return false; } - if (!executable_watcher_.Watch( + if (!executable_watcher.Watch( executable_path, false, base::Bind(&ExecFilePathWatcherCallback::NotifyPathChanged, base::Owned(callback.release())))) { - DLOG(ERROR) << "executable_watcher_.watch " << executable_path.value(); + DLOG(ERROR) << "executable_watcher.watch " << executable_path.value(); return false; } return true;
diff --git a/chrome/common/service_process_util_posix.cc b/chrome/common/service_process_util_posix.cc index 92b79b5..6a655ca 100644 --- a/chrome/common/service_process_util_posix.cc +++ b/chrome/common/service_process_util_posix.cc
@@ -77,9 +77,9 @@ } } -ServiceProcessState::StateData::StateData() : set_action_(false) { - memset(sockets_, -1, sizeof(sockets_)); - memset(&old_action_, 0, sizeof(old_action_)); +ServiceProcessState::StateData::StateData() : set_action(false) { + memset(sockets, -1, sizeof(sockets)); + memset(&old_action, 0, sizeof(old_action)); } void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal, @@ -87,17 +87,17 @@ DCHECK_EQ(g_signal_socket, -1); DCHECK(!signal->IsSignaled()); *success = base::MessageLoopForIO::current()->WatchFileDescriptor( - sockets_[0], + sockets[0], true, base::MessageLoopForIO::WATCH_READ, - &watcher_, - terminate_monitor_.get()); + &watcher, + terminate_monitor.get()); if (!*success) { DLOG(ERROR) << "WatchFileDescriptor"; signal->Signal(); return; } - g_signal_socket = sockets_[1]; + g_signal_socket = sockets[1]; // Set up signal handler for SIGTERM. struct sigaction action; @@ -105,7 +105,7 @@ action.sa_sigaction = SigTermHandler; sigemptyset(&action.sa_mask); action.sa_flags = SA_SIGINFO; - *success = sigaction(SIGTERM, &action, &old_action_) == 0; + *success = sigaction(SIGTERM, &action, &old_action) == 0; if (!*success) { DPLOG(ERROR) << "sigaction"; signal->Signal(); @@ -115,8 +115,8 @@ // If the old_action is not default, somebody else has installed a // a competing handler. Our handler is going to override it so it // won't be called. If this occurs it needs to be fixed. - DCHECK_EQ(old_action_.sa_handler, SIG_DFL); - set_action_ = true; + DCHECK_EQ(old_action.sa_handler, SIG_DFL); + set_action = true; #if defined(OS_MACOSX) *success = WatchExecutable(); @@ -126,24 +126,24 @@ return; } #elif defined(OS_POSIX) - initializing_lock_.reset(); + initializing_lock.reset(); #endif // OS_POSIX signal->Signal(); } ServiceProcessState::StateData::~StateData() { - if (sockets_[0] != -1) { - if (IGNORE_EINTR(close(sockets_[0]))) { + if (sockets[0] != -1) { + if (IGNORE_EINTR(close(sockets[0]))) { DPLOG(ERROR) << "close"; } } - if (sockets_[1] != -1) { - if (IGNORE_EINTR(close(sockets_[1]))) { + if (sockets[1] != -1) { + if (IGNORE_EINTR(close(sockets[1]))) { DPLOG(ERROR) << "close"; } } - if (set_action_) { - if (sigaction(SIGTERM, &old_action_, NULL) < 0) { + if (set_action) { + if (sigaction(SIGTERM, &old_action, NULL) < 0) { DPLOG(ERROR) << "sigaction"; } } @@ -167,14 +167,14 @@ DCHECK(state_); #if defined(OS_POSIX) && !defined(OS_MACOSX) - state_->running_lock_.reset(TakeServiceRunningLock(true)); - if (state_->running_lock_.get() == NULL) { + state_->running_lock.reset(TakeServiceRunningLock(true)); + if (state_->running_lock.get() == NULL) { return false; } #endif - state_->terminate_monitor_.reset( + state_->terminate_monitor.reset( new ServiceProcessTerminateMonitor(terminate_task)); - if (pipe(state_->sockets_) < 0) { + if (pipe(state_->sockets) < 0) { DPLOG(ERROR) << "pipe"; return false; }
diff --git a/chrome/common/service_process_util_posix.h b/chrome/common/service_process_util_posix.h index 1164374..16031e6 100644 --- a/chrome/common/service_process_util_posix.h +++ b/chrome/common/service_process_util_posix.h
@@ -64,25 +64,21 @@ // to be monitoring it. void SignalReady(base::WaitableEvent* signal, bool* success); - - // TODO(jhawkins): Either make this a class or rename these public member - // variables to remove the trailing underscore. - #if defined(OS_MACOSX) bool WatchExecutable(); - base::ScopedCFTypeRef<CFDictionaryRef> launchd_conf_; - base::FilePathWatcher executable_watcher_; + base::ScopedCFTypeRef<CFDictionaryRef> launchd_conf; + base::FilePathWatcher executable_watcher; #endif // OS_MACOSX #if defined(OS_POSIX) && !defined(OS_MACOSX) - scoped_ptr<MultiProcessLock> initializing_lock_; - scoped_ptr<MultiProcessLock> running_lock_; + scoped_ptr<MultiProcessLock> initializing_lock; + scoped_ptr<MultiProcessLock> running_lock; #endif - scoped_ptr<ServiceProcessTerminateMonitor> terminate_monitor_; - base::MessageLoopForIO::FileDescriptorWatcher watcher_; - int sockets_[2]; - struct sigaction old_action_; - bool set_action_; + scoped_ptr<ServiceProcessTerminateMonitor> terminate_monitor; + base::MessageLoopForIO::FileDescriptorWatcher watcher; + int sockets[2]; + struct sigaction old_action; + bool set_action; protected: friend class base::RefCountedThreadSafe<ServiceProcessState::StateData>;
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index fa1e0a6f..3dc3a47 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc
@@ -288,6 +288,7 @@ const char kChromeUINfcDebugHost[] = "nfc-debug"; const char kChromeUINetworkHost[] = "network"; const char kChromeUIOobeHost[] = "oobe"; +const char kChromeUIOobeMdHost[] = "oobe-md"; const char kChromeUIOSCreditsHost[] = "os-credits"; const char kChromeUIPowerHost[] = "power"; const char kChromeUIProvidedFileSystemsHost[] = "provided-file-systems"; @@ -651,6 +652,7 @@ kChromeUILoginHost, kChromeUINetworkHost, kChromeUIOobeHost, + kChromeUIOobeMdHost, kChromeUIOSCreditsHost, kChromeUIPowerHost, kChromeUIProxySettingsHost,
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index 7bcf524..a161d58 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h
@@ -281,6 +281,7 @@ extern const char kChromeUINetworkHost[]; extern const char kChromeUINfcDebugHost[]; extern const char kChromeUIOobeHost[]; +extern const char kChromeUIOobeMdHost[]; extern const char kChromeUIOSCreditsHost[]; extern const char kChromeUIPowerHost[]; extern const char kChromeUIProxySettingsHost[];
diff --git a/chrome/installer/util/master_preferences.cc b/chrome/installer/util/master_preferences.cc index bcb6b8bc..ec71d23a32 100644 --- a/chrome/installer/util/master_preferences.cc +++ b/chrome/installer/util/master_preferences.cc
@@ -51,7 +51,7 @@ base::DictionaryValue* ParseDistributionPreferences( const std::string& json_data) { - JSONStringValueSerializer json(json_data); + JSONStringValueDeserializer json(json_data); std::string error; scoped_ptr<base::Value> root(json.Deserialize(NULL, &error)); if (!root.get()) {
diff --git a/chrome/installer/util/uninstall_metrics.cc b/chrome/installer/util/uninstall_metrics.cc index da8ca03..fe2ee436 100644 --- a/chrome/installer/util/uninstall_metrics.cc +++ b/chrome/installer/util/uninstall_metrics.cc
@@ -74,10 +74,10 @@ bool ExtractUninstallMetricsFromFile(const base::FilePath& file_path, base::string16* uninstall_metrics_string) { - JSONFileValueSerializer json_serializer(file_path); + JSONFileValueDeserializer json_deserializer(file_path); std::string json_error_string; - scoped_ptr<base::Value> root(json_serializer.Deserialize(NULL, NULL)); + scoped_ptr<base::Value> root(json_deserializer.Deserialize(NULL, NULL)); if (!root.get()) return false;
diff --git a/chrome/installer/util/uninstall_metrics_unittest.cc b/chrome/installer/util/uninstall_metrics_unittest.cc index 621b0dbb..aa0ff15c 100644 --- a/chrome/installer/util/uninstall_metrics_unittest.cc +++ b/chrome/installer/util/uninstall_metrics_unittest.cc
@@ -43,7 +43,7 @@ L"&launch_count=11&page_load_count=68" L"&uptime_sec=809"); - JSONStringValueSerializer json_deserializer(pref_string); + JSONStringValueDeserializer json_deserializer(pref_string); std::string error_message; scoped_ptr<base::Value> root(
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn index 35637e09..2e47170 100644 --- a/chrome/renderer/BUILD.gn +++ b/chrome/renderer/BUILD.gn
@@ -37,7 +37,7 @@ "//chrome:strings", "//components/autofill/content/renderer", "//components/cdm/renderer", - "//components/data_reduction_proxy/core/common", + "//components/data_reduction_proxy/content/common", "//components/network_hints/renderer", "//components/error_page/renderer", "//components/password_manager/content/renderer",
diff --git a/chrome/renderer/DEPS b/chrome/renderer/DEPS index c81f7f8..a2a6e27 100644 --- a/chrome/renderer/DEPS +++ b/chrome/renderer/DEPS
@@ -7,7 +7,7 @@ "+components/cdm/renderer", "+components/content_settings/core/common", "+components/crx_file", - "+components/data_reduction_proxy/core/common", + "+components/data_reduction_proxy/content/common", "+components/dom_distiller/core", "+components/nacl/common", "+components/nacl/renderer",
diff --git a/chrome/renderer/autofill/autofill_renderer_browsertest.cc b/chrome/renderer/autofill/autofill_renderer_browsertest.cc index 26840bb..49a83665 100644 --- a/chrome/renderer/autofill/autofill_renderer_browsertest.cc +++ b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
@@ -250,7 +250,7 @@ // Shouldn't crash. } -TEST_F(AutofillRendererTest, DISABLED_DynamicallyAddedUnownedFormElements) { +TEST_F(AutofillRendererTest, DynamicallyAddedUnownedFormElements) { std::string html_data; base::FilePath test_path = ui_test_utils::GetTestFilePath( base::FilePath(FILE_PATH_LITERAL("autofill")),
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc index a447229..24b5f05c 100644 --- a/chrome/renderer/autofill/form_autofill_browsertest.cc +++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -2393,7 +2393,7 @@ false); } -TEST_F(FormAutofillTest, DISABLED_FindFormForInputElementForUnownedForm) { +TEST_F(FormAutofillTest, FindFormForInputElementForUnownedForm) { TestFindFormForInputElement( "<INPUT type='text' id='firstname' value='John'/>" "<INPUT type='text' id='lastname' value='Smith'/>" @@ -2420,7 +2420,7 @@ false); } -TEST_F(FormAutofillTest, DISABLED_FindFormForTextAreaElementForUnownedForm) { +TEST_F(FormAutofillTest, FindFormForTextAreaElementForUnownedForm) { TestFindFormForTextAreaElement( "<INPUT type='text' id='firstname' value='John'/>" "<INPUT type='text' id='lastname' value='Smith'/>" @@ -2439,7 +2439,7 @@ TestFillForm(kFormHtml, false); } -TEST_F(FormAutofillTest, DISABLED_FillFormForUnownedForm) { +TEST_F(FormAutofillTest, FillFormForUnownedForm) { TestFillForm(kUnownedFormHtml, true); } @@ -2531,7 +2531,7 @@ TestPreviewForm(kFormHtml, false); } -TEST_F(FormAutofillTest, DISABLED_PreviewFormForUnownedForm) { +TEST_F(FormAutofillTest, PreviewFormForUnownedForm) { TestPreviewForm(kUnownedFormHtml, true); } @@ -3406,7 +3406,7 @@ false); } -TEST_F(FormAutofillTest, DISABLED_FillFormMaxLengthForUnownedForm) { +TEST_F(FormAutofillTest, FillFormMaxLengthForUnownedForm) { TestFillFormMaxLength( "<INPUT type='text' id='firstname' maxlength='5'/>" "<INPUT type='text' id='lastname' maxlength='7'/>" @@ -3429,7 +3429,7 @@ false); } -TEST_F(FormAutofillTest, DISABLED_FillFormNegativeMaxLengthForUnownedForm) { +TEST_F(FormAutofillTest, FillFormNegativeMaxLengthForUnownedForm) { TestFillFormNegativeMaxLength( "<INPUT type='text' id='firstname' maxlength='-1'/>" "<INPUT type='text' id='lastname' maxlength='-10'/>" @@ -3449,7 +3449,7 @@ false); } -TEST_F(FormAutofillTest, DISABLED_FillFormEmptyNameForUnownedForm) { +TEST_F(FormAutofillTest, FillFormEmptyNameForUnownedForm) { TestFillFormEmptyName( "<INPUT type='text' id='firstname'/>" "<INPUT type='text' id='lastname'/>" @@ -3475,7 +3475,7 @@ false); } -TEST_F(FormAutofillTest, DISABLED_FillFormEmptyFormNamesForUnownedForm) { +TEST_F(FormAutofillTest, FillFormEmptyFormNamesForUnownedForm) { TestFillFormEmptyFormNames( "<INPUT type='text' id='firstname'/>" "<INPUT type='text' id='middlename'/>" @@ -3631,7 +3631,7 @@ false); } -TEST_F(FormAutofillTest, DISABLED_FillFormNonEmptyFieldForUnownedForm) { +TEST_F(FormAutofillTest, FillFormNonEmptyFieldForUnownedForm) { TestFillFormNonEmptyField("<INPUT type='text' id='firstname'/>" "<INPUT type='text' id='lastname'/>" "<INPUT type='text' id='email'/>" @@ -3659,7 +3659,7 @@ false); } -TEST_F(FormAutofillTest, DISABLED_ClearFormWithNodeForUnownedForm) { +TEST_F(FormAutofillTest, ClearFormWithNodeForUnownedForm) { TestClearFormWithNode( " <!-- Indented on purpose //-->" " <INPUT type='text' id='firstname' value='Wyatt'/>" @@ -3694,8 +3694,7 @@ false); } -TEST_F(FormAutofillTest, - DISABLED_ClearFormWithNodeContainingSelectOneForUnownedForm) { +TEST_F(FormAutofillTest, ClearFormWithNodeContainingSelectOneForUnownedForm) { TestClearFormWithNodeContainingSelectOne( "<INPUT type='text' id='firstname' value='Wyatt'/>" "<INPUT type='text' id='lastname' value='Earp'/>" @@ -3721,7 +3720,7 @@ "</FORM>"); } -TEST_F(FormAutofillTest, DISABLED_ClearPreviewedFormWithElementForUnownedForm) { +TEST_F(FormAutofillTest, ClearPreviewedFormWithElementForUnownedForm) { TestClearPreviewedFormWithElement( "<INPUT type='text' id='firstname' value='Wyatt'/>" "<INPUT type='text' id='lastname'/>" @@ -3744,7 +3743,7 @@ } TEST_F(FormAutofillTest, - DISABLED_ClearPreviewedFormWithNonEmptyInitiatingNodeForUnownedForm) { + ClearPreviewedFormWithNonEmptyInitiatingNodeForUnownedForm) { TestClearPreviewedFormWithNonEmptyInitiatingNode( "<INPUT type='text' id='firstname' value='W'/>" "<INPUT type='text' id='lastname'/>" @@ -3767,7 +3766,7 @@ } TEST_F(FormAutofillTest, - DISABLED_ClearPreviewedFormWithAutofilledInitiatingNodeForUnownedForm) { + ClearPreviewedFormWithAutofilledInitiatingNodeForUnownedForm) { TestClearPreviewedFormWithAutofilledInitiatingNode( "<INPUT type='text' id='firstname' value='W'/>" "<INPUT type='text' id='lastname'/>" @@ -3789,7 +3788,7 @@ "</FORM>"); } -TEST_F(FormAutofillTest, DISABLED_ClearOnlyAutofilledFieldsForUnownedForm) { +TEST_F(FormAutofillTest, ClearOnlyAutofilledFieldsForUnownedForm) { TestClearOnlyAutofilledFields( "<INPUT type='text' id='firstname' value='Wyatt'/>" "<INPUT type='text' id='lastname' value='Earp'/>" @@ -3948,7 +3947,7 @@ } TEST_F(FormAutofillTest, - DISABLED_UnownedFormElementsAndFieldSetsToFormDataFieldsets) { + UnownedFormElementsAndFieldSetsToFormDataFieldsets) { std::vector<WebElement> fieldsets; std::vector<WebFormControlElement> control_elements; @@ -4010,7 +4009,7 @@ } TEST_F(FormAutofillTest, - DISABLED_UnownedFormElementsAndFieldSetsToFormDataControlOutsideOfFieldset) { + UnownedFormElementsAndFieldSetsToFormDataControlOutsideOfFieldset) { std::vector<WebElement> fieldsets; std::vector<WebFormControlElement> control_elements; @@ -4069,8 +4068,7 @@ EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]); } -TEST_F(FormAutofillTest, - DISABLED_UnownedFormElementsAndFieldSetsToFormDataWithForm) { +TEST_F(FormAutofillTest, UnownedFormElementsAndFieldSetsToFormDataWithForm) { std::vector<WebElement> fieldsets; std::vector<WebFormControlElement> control_elements;
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 077274d1..f7a40cb 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -328,6 +328,12 @@ } #endif +#if defined(ENABLE_EXTENSIONS) +bool IsStandaloneExtensionProcess() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + extensions::switches::kExtensionProcess); +} +#endif } // namespace ChromeContentRendererClient::ChromeContentRendererClient() { @@ -1206,7 +1212,7 @@ bool ChromeContentRendererClient::RunIdleHandlerWhenWidgetsHidden() { #if defined(ENABLE_EXTENSIONS) - return !extension_dispatcher_->is_extension_process(); + return !IsStandaloneExtensionProcess(); #else return true; #endif @@ -1321,7 +1327,7 @@ // in a normal process, or if it's a process for an extension that has been // uninstalled. if (frame->top()->document().url() == url) { - if (is_extension_url != extension_dispatcher_->is_extension_process()) + if (is_extension_url != IsStandaloneExtensionProcess()) return true; } #endif // defined(ENABLE_EXTENSIONS) @@ -1445,7 +1451,7 @@ opener_document.url()) != NULL; if (!is_extension_url && !opener_is_extension_url && - extension_dispatcher_->is_extension_process() && + IsStandaloneExtensionProcess() && opener.canRequest(WebURL(new_url))) return false;
diff --git a/chrome/renderer/extensions/DEPS b/chrome/renderer/extensions/DEPS new file mode 100644 index 0000000..75a3418 --- /dev/null +++ b/chrome/renderer/extensions/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+media/audio", +]
diff --git a/chrome/renderer/extensions/cast_streaming_native_handler.cc b/chrome/renderer/extensions/cast_streaming_native_handler.cc index a10a154..1e925543 100644 --- a/chrome/renderer/extensions/cast_streaming_native_handler.cc +++ b/chrome/renderer/extensions/cast_streaming_native_handler.cc
@@ -10,20 +10,29 @@ #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/strings/string_number_conversions.h" +#include "chrome/common/extensions/api/cast_streaming_receiver_session.h" #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h" #include "chrome/common/extensions/api/cast_streaming_udp_transport.h" +#include "chrome/renderer/media/cast_receiver_session.h" #include "chrome/renderer/media/cast_rtp_stream.h" #include "chrome/renderer/media/cast_session.h" #include "chrome/renderer/media/cast_udp_transport.h" #include "content/public/child/v8_value_converter.h" +#include "content/public/renderer/media_stream_api.h" #include "extensions/renderer/script_context.h" +#include "media/audio/audio_parameters.h" #include "net/base/host_port_pair.h" +#include "third_party/WebKit/public/platform/WebMediaStream.h" #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" +#include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h" +#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" +#include "url/gurl.h" using content::V8ValueConverter; // Extension types. +using extensions::api::cast_streaming_receiver_session::RtpReceiverParams; using extensions::api::cast_streaming_rtp_stream::CodecSpecificParams; using extensions::api::cast_streaming_rtp_stream::RtpParams; using extensions::api::cast_streaming_rtp_stream::RtpPayloadParams; @@ -32,13 +41,18 @@ namespace extensions { namespace { +const char kInvalidAesIvMask[] = "Invalid value for AES IV mask"; +const char kInvalidAesKey[] = "Invalid value for AES key"; +const char kInvalidAudioParams[] = "Invalid audio params"; +const char kInvalidDestination[] = "Invalid destination"; +const char kInvalidFPS[] = "Invalid FPS"; +const char kInvalidMediaStreamURL[] = "Invalid MediaStream URL"; +const char kInvalidRtpParams[] = "Invalid value for RTP params"; +const char kInvalidLatency[] = "Invalid value for max_latency. (0-1000)"; +const char kInvalidRtpTimebase[] = "Invalid rtp_timebase. (1000-1000000)"; +const char kInvalidStreamArgs[] = "Invalid stream arguments"; const char kRtpStreamNotFound[] = "The RTP stream cannot be found"; const char kUdpTransportNotFound[] = "The UDP transport cannot be found"; -const char kInvalidDestination[] = "Invalid destination"; -const char kInvalidRtpParams[] = "Invalid value for RTP params"; -const char kInvalidAesKey[] = "Invalid value for AES key"; -const char kInvalidAesIvMask[] = "Invalid value for AES IV mask"; -const char kInvalidStreamArgs[] = "Invalid stream arguments"; const char kUnableToConvertArgs[] = "Unable to convert arguments"; const char kUnableToConvertParams[] = "Unable to convert params"; @@ -199,6 +213,9 @@ RouteFunction("GetStats", base::Bind(&CastStreamingNativeHandler::GetStats, base::Unretained(this))); + RouteFunction("StartCastRtpReceiver", + base::Bind(&CastStreamingNativeHandler::StartCastRtpReceiver, + base::Unretained(this))); } CastStreamingNativeHandler::~CastStreamingNativeHandler() { @@ -440,28 +457,17 @@ if (!transport) return; - scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); - scoped_ptr<base::Value> destination_value( - converter->FromV8Value(args[1], context()->v8_context())); - if (!destination_value) { - args.GetIsolate()->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs))); + net::IPEndPoint dest; + if (!IPEndPointFromArg(args.GetIsolate(), + args[1], + &dest)) { return; } - scoped_ptr<IPEndPoint> destination = - IPEndPoint::FromValue(*destination_value); - if (!destination) { - args.GetIsolate()->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(args.GetIsolate(), kInvalidDestination))); - return; - } - net::IPAddressNumber ip; - if (!net::ParseIPLiteralToNumber(destination->address, &ip)) { - args.GetIsolate()->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(args.GetIsolate(), kInvalidDestination))); - return; - } - transport->SetDestination(net::IPEndPoint(ip, destination->port)); + transport->SetDestination( + dest, + base::Bind(&CastStreamingNativeHandler::CallErrorCallback, + weak_factory_.GetWeakPtr(), + transport_id)); } void CastStreamingNativeHandler::SetOptionsCastUdpTransport( @@ -616,4 +622,239 @@ return NULL; } +bool CastStreamingNativeHandler::FrameReceiverConfigFromArg( + v8::Isolate* isolate, + const v8::Handle<v8::Value>& arg, + media::cast::FrameReceiverConfig* config) { + + scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); + scoped_ptr<base::Value> params_value( + converter->FromV8Value(arg, context()->v8_context())); + if (!params_value) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, kUnableToConvertParams))); + return false; + } + scoped_ptr<RtpReceiverParams> params = + RtpReceiverParams::FromValue(*params_value); + if (!params) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); + return false; + } + + config->receiver_ssrc = params->receiver_ssrc; + config->sender_ssrc = params->sender_ssrc; + config->rtp_max_delay_ms = params->max_latency; + if (config->rtp_max_delay_ms < 0 || config->rtp_max_delay_ms > 1000) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, kInvalidLatency))); + return false; + } + config->channels = 2; + if (params->codec_name == "OPUS") { + config->codec = media::cast::CODEC_AUDIO_OPUS; + config->rtp_timebase = 48000; + config->rtp_payload_type = 127; + } else if (params->codec_name == "PCM16") { + config->codec = media::cast::CODEC_AUDIO_PCM16; + config->rtp_timebase = 48000; + config->rtp_payload_type =127; + } else if (params->codec_name == "AAC") { + config->codec = media::cast::CODEC_AUDIO_AAC; + config->rtp_timebase = 48000; + config->rtp_payload_type = 127; + } else if (params->codec_name == "VP8") { + config->codec = media::cast::CODEC_VIDEO_VP8; + config->rtp_timebase = 90000; + config->rtp_payload_type = 96; + } else if (params->codec_name == "H264") { + config->codec = media::cast::CODEC_VIDEO_H264; + config->rtp_timebase = 90000; + config->rtp_payload_type = 96; + } + if (params->rtp_timebase) { + config->rtp_timebase = *params->rtp_timebase; + if (config->rtp_timebase < 1000 || config->rtp_timebase > 1000000) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, kInvalidRtpTimebase))); + return false; + } + } + if (params->aes_key && + !HexDecode(*params->aes_key, &config->aes_key)) { + isolate->ThrowException(v8::Exception::Error( + v8::String::NewFromUtf8(isolate, kInvalidAesKey))); + return false; + } + if (params->aes_iv_mask && + !HexDecode(*params->aes_iv_mask, &config->aes_iv_mask)) { + isolate->ThrowException(v8::Exception::Error( + v8::String::NewFromUtf8(isolate, kInvalidAesIvMask))); + return false; + } + return true; +} + +bool CastStreamingNativeHandler::IPEndPointFromArg( + v8::Isolate* isolate, + const v8::Handle<v8::Value>& arg, + net::IPEndPoint* ip_endpoint) { + scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); + scoped_ptr<base::Value> destination_value( + converter->FromV8Value(arg, context()->v8_context())); + if (!destination_value) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, kInvalidAesIvMask))); + return false; + } + scoped_ptr<IPEndPoint> destination = + IPEndPoint::FromValue(*destination_value); + if (!destination) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, kInvalidDestination))); + return false; + } + net::IPAddressNumber ip; + if (!net::ParseIPLiteralToNumber(destination->address, &ip)) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, kInvalidDestination))); + return false; + } + *ip_endpoint = net::IPEndPoint(ip, destination->port); + return true; +} + +void CastStreamingNativeHandler::StartCastRtpReceiver( + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (args.Length() < 8 || args.Length() > 9 || + !args[0]->IsObject() || + !args[1]->IsObject() || + !args[2]->IsObject() || + !args[3]->IsInt32() || + !args[4]->IsInt32() || + !args[5]->IsNumber() || + !args[6]->IsString()) { + args.GetIsolate()->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs))); + return; + } + + v8::Isolate* isolate = context()->v8_context()->GetIsolate(); + + scoped_refptr<CastReceiverSession> session( + new CastReceiverSession()); + media::cast::FrameReceiverConfig audio_config; + media::cast::FrameReceiverConfig video_config; + net::IPEndPoint local_endpoint; + net::IPEndPoint remote_endpoint; + + if (!FrameReceiverConfigFromArg(isolate, args[0], &audio_config) || + !FrameReceiverConfigFromArg(isolate, args[1], &video_config) || + !IPEndPointFromArg(isolate, args[2], &local_endpoint)) { + return; + } + + const std::string url = *v8::String::Utf8Value(args[7]); + blink::WebMediaStream stream = + blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url)); + + if (stream.isNull()) { + args.GetIsolate()->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(args.GetIsolate(), kInvalidMediaStreamURL))); + return; + } + + const int max_width = args[3]->ToInt32(args.GetIsolate())->Value(); + const int max_height = args[4]->ToInt32(args.GetIsolate())->Value(); + const double fps = args[5]->NumberValue(); + + if (fps <= 1) { + args.GetIsolate()->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(args.GetIsolate(), kInvalidFPS))); + return; + } + + media::VideoCaptureFormat capture_format( + gfx::Size(max_width, max_height), + fps, + media::PIXEL_FORMAT_I420); + + video_config.target_frame_rate = fps; + audio_config.target_frame_rate = 100; + + media::AudioParameters params( + media::AudioParameters::AUDIO_PCM_LINEAR, + media::CHANNEL_LAYOUT_STEREO, + audio_config.rtp_timebase, // sampling rate + 16, + audio_config.rtp_timebase / audio_config.target_frame_rate); + + if (!params.IsValid()) { + args.GetIsolate()->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams))); + return; + } + + base::DictionaryValue* options = NULL; + if (args.Length() >= 10) { + scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); + base::Value* options_value = + converter->FromV8Value(args[8], context()->v8_context()); + if (!options_value->IsType(base::Value::TYPE_NULL)) { + if (!options_value || !options_value->GetAsDictionary(&options)) { + delete options_value; + args.GetIsolate()->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs))); + return; + } + } + } + + if (!options) { + options = new base::DictionaryValue(); + } + + v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent error_callback; + error_callback.Reset(args.GetIsolate(), + v8::Handle<v8::Function>(args[7].As<v8::Function>())); + + session->Start( + audio_config, + video_config, + local_endpoint, + remote_endpoint, + make_scoped_ptr(options), + capture_format, + base::Bind(&CastStreamingNativeHandler::AddTracksToMediaStream, + weak_factory_.GetWeakPtr(), + url, + params), + base::Bind(&CastStreamingNativeHandler::CallReceiverErrorCallback, + weak_factory_.GetWeakPtr(), + error_callback)); +} + +void CastStreamingNativeHandler::CallReceiverErrorCallback( + v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent function, + const std::string& error_message) { + v8::Isolate* isolate = context()->v8_context()->GetIsolate(); + v8::Handle<v8::Value> arg = v8::String::NewFromUtf8(isolate, + error_message.data(), + v8::String::kNormalString, + error_message.size()); + context()->CallFunction( + v8::Local<v8::Function>::New(isolate, function), 1, &arg); +} + + +void CastStreamingNativeHandler::AddTracksToMediaStream( + const std::string& url, + const media::AudioParameters& params, + scoped_refptr<media::AudioCapturerSource> audio, + scoped_ptr<media::VideoCapturerSource> video) { + content::AddAudioTrackToMediaStream(audio, params, true, true, url); + content::AddVideoTrackToMediaStream(video.Pass(), true, true, url); +} + } // namespace extensions
diff --git a/chrome/renderer/extensions/cast_streaming_native_handler.h b/chrome/renderer/extensions/cast_streaming_native_handler.h index 225ade0..64a56e4e 100644 --- a/chrome/renderer/extensions/cast_streaming_native_handler.h +++ b/chrome/renderer/extensions/cast_streaming_native_handler.h
@@ -21,6 +21,23 @@ class DictionaryValue; } +namespace blink { +class WebMediaStream; +} + +namespace net { +class IPEndPoint; +} + +namespace media { +class AudioCapturerSource; +class AudioParameters; +class VideoCapturerSource; +namespace cast { +struct FrameReceiverConfig; +} +} + namespace extensions { // Native code that handle chrome.webrtc custom bindings. @@ -52,6 +69,8 @@ const v8::FunctionCallbackInfo<v8::Value>& args); void StopCastUdpTransport( const v8::FunctionCallbackInfo<v8::Value>& args); + void StartCastRtpReceiver( + const v8::FunctionCallbackInfo<v8::Value>& args); void ToggleLogging(const v8::FunctionCallbackInfo<v8::Value>& args); void GetRawEvents(const v8::FunctionCallbackInfo<v8::Value>& args); @@ -67,6 +86,20 @@ void CallStopCallback(int stream_id); void CallErrorCallback(int stream_id, const std::string& message); + // Callback called after a cast receiver has been started. Adds the + // output audio/video streams to the MediaStream specified by |url|. + void AddTracksToMediaStream( + const std::string& url, + const media::AudioParameters& params, + scoped_refptr<media::AudioCapturerSource> audio, + scoped_ptr<media::VideoCapturerSource> video); + + // |function| is a javascript function that will take |error_message| as + // an argument. Called when something goes wrong in a cast receiver. + void CallReceiverErrorCallback( + v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent function, + const std::string& error_message); + void CallGetRawEventsCallback(int transport_id, scoped_ptr<base::BinaryValue> raw_events); void CallGetStatsCallback(int transport_id, @@ -77,6 +110,19 @@ CastRtpStream* GetRtpStreamOrThrow(int stream_id) const; CastUdpTransport* GetUdpTransportOrThrow(int transport_id) const; + // Fills out a media::cast::FrameReceiverConfig from the v8 + // equivialent. (cast.streaming.receiverSession.RtpReceiverParams) + // Returns true if everything was ok, raises a v8 exception and + // returns false if anything went wrong. + bool FrameReceiverConfigFromArg( + v8::Isolate* isolate, + const v8::Handle<v8::Value>& arg, + media::cast::FrameReceiverConfig* config); + + bool IPEndPointFromArg(v8::Isolate* isolate, + const v8::Handle<v8::Value>& arg, + net::IPEndPoint* ip_endpoint); + int last_transport_id_; typedef std::map<int, linked_ptr<CastRtpStream> > RtpStreamMap;
diff --git a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc index 88df7cb5..77f2f175 100644 --- a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc +++ b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
@@ -214,6 +214,9 @@ source_map->RegisterSource( "cast.streaming.udpTransport", IDR_CAST_STREAMING_UDP_TRANSPORT_CUSTOM_BINDINGS_JS); + source_map->RegisterSource( + "cast.streaming.receiverSession", + IDR_CAST_STREAMING_RECEIVER_SESSION_CUSTOM_BINDINGS_JS); #endif source_map->RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS);
diff --git a/chrome/renderer/media/cast_receiver_session.cc b/chrome/renderer/media/cast_receiver_session.cc index 6870f2396c..d1ba653 100644 --- a/chrome/renderer/media/cast_receiver_session.cc +++ b/chrome/renderer/media/cast_receiver_session.cc
@@ -8,6 +8,7 @@ #include "chrome/renderer/media/cast_receiver_audio_valve.h" #include "content/public/renderer/render_thread.h" #include "media/base/audio_capturer_source.h" +#include "media/base/bind_to_current_loop.h" #include "media/base/video_capturer_source.h" #include "third_party/WebKit/public/platform/WebMediaStream.h" #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" @@ -71,7 +72,8 @@ const net::IPEndPoint& remote_endpoint, scoped_ptr<base::DictionaryValue> options, const media::VideoCaptureFormat& capture_format, - const StartCB& start_callback) { + const StartCB& start_callback, + const CastReceiverSessionDelegate::ErrorCallback& error_callback) { audio_config_ = audio_config; video_config_ = video_config; format_ = capture_format; @@ -84,7 +86,8 @@ local_endpoint, remote_endpoint, base::Passed(&options), - format_)); + format_, + media::BindToCurrentLoop(error_callback))); scoped_refptr<media::AudioCapturerSource> audio( new CastReceiverSession::AudioCapturerSource(this)); scoped_ptr<media::VideoCapturerSource> video(
diff --git a/chrome/renderer/media/cast_receiver_session.h b/chrome/renderer/media/cast_receiver_session.h index 0827879..d2925220d 100644 --- a/chrome/renderer/media/cast_receiver_session.h +++ b/chrome/renderer/media/cast_receiver_session.h
@@ -49,7 +49,8 @@ const net::IPEndPoint& remote_endpoint, scoped_ptr<base::DictionaryValue> options, const media::VideoCaptureFormat& capture_format, - const StartCB& start_callback); + const StartCB& start_callback, + const CastReceiverSessionDelegate::ErrorCallback& error_callback); private: class VideoCapturerSource;
diff --git a/chrome/renderer/media/cast_receiver_session_delegate.cc b/chrome/renderer/media/cast_receiver_session_delegate.cc index 400dbf38..3509989 100644 --- a/chrome/renderer/media/cast_receiver_session_delegate.cc +++ b/chrome/renderer/media/cast_receiver_session_delegate.cc
@@ -24,12 +24,14 @@ const net::IPEndPoint& local_endpoint, const net::IPEndPoint& remote_endpoint, scoped_ptr<base::DictionaryValue> options, - const media::VideoCaptureFormat& format) { + const media::VideoCaptureFormat& format, + const ErrorCallback& error_callback) { format_ = format; DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); CastSessionDelegateBase::StartUDP(local_endpoint, remote_endpoint, - options.Pass()); + options.Pass(), + error_callback); cast_receiver_ = media::cast::CastReceiver::Create(cast_environment_, audio_config, video_config, @@ -96,6 +98,6 @@ bool is_continous) { if (frame_callback_.is_null()) return; - frame_callback_.Run(video_frame, format_, playout_time); + frame_callback_.Run(video_frame, playout_time); cast_receiver_->RequestDecodedVideoFrame(on_video_decoded_cb_); }
diff --git a/chrome/renderer/media/cast_receiver_session_delegate.h b/chrome/renderer/media/cast_receiver_session_delegate.h index 804d944..98de8fd 100644 --- a/chrome/renderer/media/cast_receiver_session_delegate.h +++ b/chrome/renderer/media/cast_receiver_session_delegate.h
@@ -13,6 +13,8 @@ class CastReceiverSessionDelegate : public CastSessionDelegateBase { public: + typedef base::Callback<void(const std::string&)> ErrorCallback; + CastReceiverSessionDelegate(); ~CastReceiverSessionDelegate() override; @@ -26,7 +28,8 @@ const net::IPEndPoint& local_endpoint, const net::IPEndPoint& remote_endpoint, scoped_ptr<base::DictionaryValue> options, - const media::VideoCaptureFormat& format); + const media::VideoCaptureFormat& format, + const ErrorCallback& error_callback); void StartAudio(scoped_refptr<CastReceiverAudioValve> audio_valve);
diff --git a/chrome/renderer/media/cast_rtp_stream.cc b/chrome/renderer/media/cast_rtp_stream.cc index a3f970d..6cc8e6f 100644 --- a/chrome/renderer/media/cast_rtp_stream.cc +++ b/chrome/renderer/media/cast_rtp_stream.cc
@@ -272,7 +272,6 @@ const scoped_refptr<media::cast::VideoFrameInput> frame_input, // These parameters are passed for each frame. const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time) { base::TimeTicks timestamp; if (estimated_capture_time.is_null())
diff --git a/chrome/renderer/media/cast_session.cc b/chrome/renderer/media/cast_session.cc index 0990d3a..0983a2b 100644 --- a/chrome/renderer/media/cast_session.cc +++ b/chrome/renderer/media/cast_session.cc
@@ -85,7 +85,8 @@ } void CastSession::StartUDP(const net::IPEndPoint& remote_endpoint, - scoped_ptr<base::DictionaryValue> options) { + scoped_ptr<base::DictionaryValue> options, + const ErrorCallback& error_callback) { io_message_loop_proxy_->PostTask( FROM_HERE, base::Bind( @@ -93,7 +94,8 @@ base::Unretained(delegate_.get()), net::IPEndPoint(), remote_endpoint, - base::Passed(&options))); + base::Passed(&options), + media::BindToCurrentLoop(error_callback))); } void CastSession::ToggleLogging(bool is_audio, bool enable) {
diff --git a/chrome/renderer/media/cast_session.h b/chrome/renderer/media/cast_session.h index 12e602f..afffb35 100644 --- a/chrome/renderer/media/cast_session.h +++ b/chrome/renderer/media/cast_session.h
@@ -71,7 +71,8 @@ // udp transport. // Must be called before initialization of audio or video. void StartUDP(const net::IPEndPoint& remote_endpoint, - scoped_ptr<base::DictionaryValue> options); + scoped_ptr<base::DictionaryValue> options, + const ErrorCallback& error_callback); // Creates or destroys event subscriber for the audio or video stream. // |is_audio|: true if the event subscriber is for audio. Video otherwise.
diff --git a/chrome/renderer/media/cast_session_delegate.cc b/chrome/renderer/media/cast_session_delegate.cc index 6a0da851..2b07386 100644 --- a/chrome/renderer/media/cast_session_delegate.cc +++ b/chrome/renderer/media/cast_session_delegate.cc
@@ -45,7 +45,8 @@ void CastSessionDelegateBase::StartUDP( const net::IPEndPoint& local_endpoint, const net::IPEndPoint& remote_endpoint, - scoped_ptr<base::DictionaryValue> options) { + scoped_ptr<base::DictionaryValue> options, + const ErrorCallback& error_callback) { DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); // CastSender uses the renderer's IO thread as the main thread. This reduces @@ -66,15 +67,30 @@ base::Bind(&CastSessionDelegateBase::ReceivePacket, base::Unretained(this)), base::Bind(&CastSessionDelegateBase::StatusNotificationCB, - base::Unretained(this)), + base::Unretained(this), error_callback), base::Bind(&CastSessionDelegateBase::LogRawEvents, base::Unretained(this)))); } void CastSessionDelegateBase::StatusNotificationCB( - media::cast::CastTransportStatus unused_status) { + const ErrorCallback& error_callback, + media::cast::CastTransportStatus status) { DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); - // TODO(hubbe): Call javascript UDPTransport error function. + std::string error_message; + + switch (status) { + case media::cast::TRANSPORT_AUDIO_UNINITIALIZED: + case media::cast::TRANSPORT_VIDEO_UNINITIALIZED: + case media::cast::TRANSPORT_AUDIO_INITIALIZED: + case media::cast::TRANSPORT_VIDEO_INITIALIZED: + return; // Not errors, do nothing. + case media::cast::TRANSPORT_INVALID_CRYPTO_CONFIG: + error_callback.Run("Invalid encrypt/decrypt configuration."); + break; + case media::cast::TRANSPORT_SOCKET_ERROR: + error_callback.Run("Socket error."); + break; + } } CastSessionDelegate::CastSessionDelegate() @@ -132,11 +148,13 @@ void CastSessionDelegate::StartUDP( const net::IPEndPoint& local_endpoint, const net::IPEndPoint& remote_endpoint, - scoped_ptr<base::DictionaryValue> options) { + scoped_ptr<base::DictionaryValue> options, + const ErrorCallback& error_callback) { DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); CastSessionDelegateBase::StartUDP(local_endpoint, remote_endpoint, - options.Pass()); + options.Pass(), + error_callback); event_subscribers_.reset( new media::cast::RawEventSubscriberBundle(cast_environment_));
diff --git a/chrome/renderer/media/cast_session_delegate.h b/chrome/renderer/media/cast_session_delegate.h index 7528147e..a2e688c8 100644 --- a/chrome/renderer/media/cast_session_delegate.h +++ b/chrome/renderer/media/cast_session_delegate.h
@@ -43,6 +43,8 @@ // CastReceiverSessionDelegate. class CastSessionDelegateBase { public: + typedef base::Callback<void(const std::string&)> ErrorCallback; + CastSessionDelegateBase(); virtual ~CastSessionDelegateBase(); @@ -51,10 +53,12 @@ // Must be called before initialization of audio or video. void StartUDP(const net::IPEndPoint& local_endpoint, const net::IPEndPoint& remote_endpoint, - scoped_ptr<base::DictionaryValue> options); + scoped_ptr<base::DictionaryValue> options, + const ErrorCallback& error_callback); protected: void StatusNotificationCB( + const ErrorCallback& error_callback, media::cast::CastTransportStatus status); virtual void ReceivePacket(scoped_ptr<media::cast::Packet> packet) = 0; @@ -85,14 +89,14 @@ media::cast::VideoFrameInput>&)> VideoFrameInputAvailableCallback; typedef base::Callback<void(scoped_ptr<base::BinaryValue>)> EventLogsCallback; typedef base::Callback<void(scoped_ptr<base::DictionaryValue>)> StatsCallback; - typedef base::Callback<void(const std::string&)> ErrorCallback; CastSessionDelegate(); ~CastSessionDelegate() override; void StartUDP(const net::IPEndPoint& local_endpoint, const net::IPEndPoint& remote_endpoint, - scoped_ptr<base::DictionaryValue> options); + scoped_ptr<base::DictionaryValue> options, + const ErrorCallback& error_callback); // After calling StartAudio() or StartVideo() encoding of that media will // begin as soon as data is delivered to its sink, if the second method is
diff --git a/chrome/renderer/media/cast_udp_transport.cc b/chrome/renderer/media/cast_udp_transport.cc index 0cecbcac..3861873 100644 --- a/chrome/renderer/media/cast_udp_transport.cc +++ b/chrome/renderer/media/cast_udp_transport.cc
@@ -17,12 +17,15 @@ CastUdpTransport::~CastUdpTransport() { } -void CastUdpTransport::SetDestination(const net::IPEndPoint& remote_address) { +void CastUdpTransport::SetDestination( + const net::IPEndPoint& remote_address, + const CastSessionDelegate::ErrorCallback& error_callback) { DVLOG(1) << "CastUdpTransport::SetDestination = " << remote_address.ToString(); remote_address_ = remote_address; cast_session_->StartUDP(remote_address, - make_scoped_ptr(options_->DeepCopy())); + make_scoped_ptr(options_->DeepCopy()), + error_callback); } void CastUdpTransport::SetOptions(scoped_ptr<base::DictionaryValue> options) {
diff --git a/chrome/renderer/media/cast_udp_transport.h b/chrome/renderer/media/cast_udp_transport.h index ee10c240..d105c5f 100644 --- a/chrome/renderer/media/cast_udp_transport.h +++ b/chrome/renderer/media/cast_udp_transport.h
@@ -8,6 +8,7 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "chrome/renderer/media/cast_session_delegate.h" #include "net/base/ip_endpoint.h" namespace base { @@ -25,7 +26,8 @@ virtual ~CastUdpTransport(); // Specify the remote IP address and port. - void SetDestination(const net::IPEndPoint& remote_address); + void SetDestination(const net::IPEndPoint& remote_address, + const CastSessionDelegate::ErrorCallback& error_callback); // Set options. void SetOptions(scoped_ptr<base::DictionaryValue> options);
diff --git a/chrome/renderer/page_load_histograms.cc b/chrome/renderer/page_load_histograms.cc index 61d6f3757..91ca92b1 100644 --- a/chrome/renderer/page_load_histograms.cc +++ b/chrome/renderer/page_load_histograms.cc
@@ -18,7 +18,7 @@ #include "base/time/time.h" #include "chrome/common/chrome_switches.h" #include "chrome/renderer/chrome_content_renderer_client.h" -#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" +#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h" #include "content/public/common/content_constants.h" #include "content/public/renderer/document_state.h" #include "content/public/renderer/render_thread.h" @@ -724,11 +724,7 @@ } // namespace PageLoadHistograms::PageLoadHistograms(content::RenderView* render_view) - : content::RenderViewObserver(render_view), - data_reduction_proxy_params_( - data_reduction_proxy::DataReductionProxyParams::kAllowed | - data_reduction_proxy::DataReductionProxyParams::kFallbackAllowed | - data_reduction_proxy::DataReductionProxyParams::kAlternativeAllowed) { + : content::RenderViewObserver(render_view) { } void PageLoadHistograms::Dump(WebFrame* frame) { @@ -750,9 +746,12 @@ DocumentState* document_state = DocumentState::FromDataSource(frame->dataSource()); - bool data_reduction_proxy_was_used = - data_reduction_proxy_params_.IsDataReductionProxy( - document_state->proxy_server(), NULL); + bool data_reduction_proxy_was_used = false; + if (!document_state->proxy_server().IsEmpty()) { + Send(new DataReductionProxyViewHostMsg_IsDataReductionProxy( + document_state->proxy_server(), &data_reduction_proxy_was_used)); + } + bool came_from_websearch = IsFromGoogleSearchResult(frame->document().url(), GURL(frame->document().referrer()));
diff --git a/chrome/renderer/page_load_histograms.h b/chrome/renderer/page_load_histograms.h index 5f87345f..7f52444 100644 --- a/chrome/renderer/page_load_histograms.h +++ b/chrome/renderer/page_load_histograms.h
@@ -6,7 +6,6 @@ #define CHROME_RENDERER_PAGE_LOAD_HISTOGRAMS_H_ #include "base/basictypes.h" -#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" #include "content/public/renderer/render_view_observer.h" namespace content { @@ -46,8 +45,6 @@ void LogPageLoadTime(const content::DocumentState* load_times, const blink::WebDataSource* ds) const; - data_reduction_proxy::DataReductionProxyParams data_reduction_proxy_params_; - DISALLOW_COPY_AND_ASSIGN(PageLoadHistograms); };
diff --git a/chrome/renderer/resources/extensions/cast_streaming_receiver_session_custom_bindings.js b/chrome/renderer/resources/extensions/cast_streaming_receiver_session_custom_bindings.js new file mode 100644 index 0000000..8751071 --- /dev/null +++ b/chrome/renderer/resources/extensions/cast_streaming_receiver_session_custom_bindings.js
@@ -0,0 +1,20 @@ +// 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. + +// Custom binding for the Cast Streaming Session API. + +var binding = require('binding').Binding.create( + 'cast.streaming.receiverSession'); +var natives = requireNative('cast_streaming_natives'); + +binding.registerCustomHook(function(bindingsAPI, extensionId) { + var apiFunctions = bindingsAPI.apiFunctions; + apiFunctions.setHandleRequest('createAndBind', + function(ap, vp, local, weidgth, height, fr, url, cb, op) { + natives.StartCastRtpReceiver( + ap, vp, local, weidgth, height, fr, url, cb, op); + }); +}); + +exports.binding = binding.generate();
diff --git a/chrome/renderer/resources/extensions/chrome_web_view_experimental.js b/chrome/renderer/resources/extensions/chrome_web_view_experimental.js index 442f84b5..f3db4bb 100644 --- a/chrome/renderer/resources/extensions/chrome_web_view_experimental.js +++ b/chrome/renderer/resources/extensions/chrome_web_view_experimental.js
@@ -19,23 +19,6 @@ var MessagingNatives = requireNative('messaging_natives'); var utils = require('utils'); var WebViewImpl = require('webView').WebViewImpl; -var DeclarativeContentSchema = - requireNative('schema_registry').GetSchema('declarativeContent'); - -var DeclarativeContentEvent = function(opt_eventName, - opt_argSchemas, - opt_eventOptions, - opt_webViewInstanceId) { - EventBindings.Event.call(this, - opt_eventName, - opt_argSchemas, - opt_eventOptions, - opt_webViewInstanceId); -} - -DeclarativeContentEvent.prototype = { - __proto__: EventBindings.Event.prototype -}; function GetUniqueSubEventName(eventName) { return eventName + '/' + idGeneratorNatives.GetNextId(); @@ -192,35 +175,3 @@ enumerable: true }); }; - -WebViewImpl.prototype.maybeSetupExperimentalChromeWebViewEvents = function( - request) { - var createDeclarativeContentEvent = function(declarativeContentEvent) { - return function() { - if (!this[declarativeContentEvent.name]) { - this[declarativeContentEvent.name] = - new DeclarativeContentEvent( - 'webViewInternal.declarativeContent.' + - declarativeContentEvent.name, - declarativeContentEvent.parameters, - declarativeContentEvent.options, - this.viewInstanceId); - } - return this[declarativeContentEvent.name]; - }.bind(this); - }.bind(this); - - for (var i = 0; i < DeclarativeContentSchema.events.length; ++i) { - var eventSchema = DeclarativeContentSchema.events[i]; - var declarativeContentEvent = createDeclarativeContentEvent(eventSchema); - Object.defineProperty( - request, - eventSchema.name, - { - get: declarativeContentEvent, - enumerable: true - } - ); - } - return request; -};
diff --git a/chrome/renderer/resources/neterror.css b/chrome/renderer/resources/neterror.css index e93543c..a630a5a1 100644 --- a/chrome/renderer/resources/neterror.css +++ b/chrome/renderer/resources/neterror.css
@@ -58,6 +58,10 @@ position: relative; } +.error-code { + display: block; +} + #content-top { margin: 20px; } @@ -130,6 +134,12 @@ margin: auto; } +.secondary-button { + -webkit-margin-end: 16px; + background: #d9d9d9; + color: #696969; +} + .hidden { display: none; } @@ -147,12 +157,6 @@ color: #777; } -.error-code { - color: #A0A0A0; - font-size: .825em; - margin-top: 15px; -} - /* Increase line height at higher resolutions. */ @media (min-width: 641px) and (min-height: 641px) { #help-box-inner { @@ -240,26 +244,28 @@ /* details-button is special; it's a <button> element that looks like a link. */ #details-button { - background-color: inherit; - background-image: none; - border: none; box-shadow: none; min-width: 0; - padding: 0; - text-decoration: underline; } /* Styles for platform dependent separation of controls and details button. */ .suggested-left > #control-buttons, -.suggested-right > #details-button { +.suggested-left #stale-load-button, +.suggested-right > #details-button { float: left; } .suggested-right > #control-buttons, -.suggested-left > #details-button { +.suggested-right #stale-load-button, +.suggested-left > #details-button { float: right; } +.suggested-left .secondary-button { + -webkit-margin-end: 0px; + -webkit-margin-start: 16px; +} + #details-button.singular { float: none; }
diff --git a/chrome/renderer/resources/neterror.html b/chrome/renderer/resources/neterror.html index d397f4a4..bf1f1b47 100644 --- a/chrome/renderer/resources/neterror.html +++ b/chrome/renderer/resources/neterror.html
@@ -19,6 +19,7 @@ <div id="main-message"> <h1 i18n-content="heading"></h1> <p hidden></p> + <div class="error-code" jscontent="errorCode"></div> </div> </div> <div id="buttons" class="nav-wrapper"> @@ -66,7 +67,6 @@ </button> </div> </form> - <div class="error-code" jscontent="errorCode"></div> </div> </div> <div id="sub-frame-error">
diff --git a/chrome/renderer/resources/neterror.js b/chrome/renderer/resources/neterror.js index 5929643..cee640f 100644 --- a/chrome/renderer/resources/neterror.js +++ b/chrome/renderer/resources/neterror.js
@@ -12,8 +12,13 @@ detailsButton.innerText = detailsButton.hideDetailsText; // Details appears over the main content on small screens. - if (mobileNav) + if (mobileNav) { document.getElementById('main-content').classList.toggle('hidden'); + var runnerContainer = document.querySelector('.runner-container'); + if (runnerContainer) { + runnerContainer.classList.toggle('hidden'); + } + } } function diagnoseErrors() { @@ -142,7 +147,6 @@ if (loadTimeData.valueExists('summary') && !loadTimeData.getValue('summary').msg) { detailsButton.style.display = 'none'; - document.getElementById('details').style.display = 'block'; } </if>
diff --git a/chrome/renderer/resources/offline.js b/chrome/renderer/resources/offline.js index fbf46d9..75404cc 100644 --- a/chrome/renderer/resources/offline.js +++ b/chrome/renderer/resources/offline.js
@@ -793,6 +793,11 @@ // our canvas element. context.scale(ratio, ratio); return true; + } else if (devicePixelRatio == 1) { + // Reset the canvas width / height. Fixes scaling bug when the page is + // zoomed and the devicePixelRatio changes accordingly. + canvas.style.width = canvas.width + 'px'; + canvas.style.height = canvas.height + 'px'; } return false; };
diff --git a/chrome/renderer/resources/plugin_poster.html b/chrome/renderer/resources/plugin_poster.html index e75a5988..9dc99c41 100644 --- a/chrome/renderer/resources/plugin_poster.html +++ b/chrome/renderer/resources/plugin_poster.html
@@ -8,6 +8,13 @@ if (plugin.didFinishLoading) plugin.didFinishLoading(); } + +document.onkeydown = function(e) { + if (e.keyIdentifier == 'Enter' || e.keyIdentifier == 'U+0020') { + plugin.load(); + e.preventDefault(); + } +}; </script> <link rel="stylesheet" href="plugin_placeholders.css"></link> <style>
diff --git a/chrome/renderer/resources/renderer_resources.grd b/chrome/renderer/resources/renderer_resources.grd index 150ec9eb..53b221d 100644 --- a/chrome/renderer/resources/renderer_resources.grd +++ b/chrome/renderer/resources/renderer_resources.grd
@@ -39,6 +39,7 @@ <include name="IDR_CAST_STREAMING_RTP_STREAM_CUSTOM_BINDINGS_JS" file="extensions\cast_streaming_rtp_stream_custom_bindings.js" type="BINDATA" /> <include name="IDR_CAST_STREAMING_SESSION_CUSTOM_BINDINGS_JS" file="extensions\cast_streaming_session_custom_bindings.js" type="BINDATA" /> <include name="IDR_CAST_STREAMING_UDP_TRANSPORT_CUSTOM_BINDINGS_JS" file="extensions\cast_streaming_udp_transport_custom_bindings.js" type="BINDATA" /> + <include name="IDR_CAST_STREAMING_RECEIVER_SESSION_CUSTOM_BINDINGS_JS" file="extensions\cast_streaming_receiver_session_custom_bindings.js" type="BINDATA" /> <include name="IDR_CHROME_DIRECT_SETTING_JS" file="extensions\chrome_direct_setting.js" type="BINDATA" /> <include name="IDR_CHROME_SETTING_JS" file="extensions\chrome_setting.js" type="BINDATA" />
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 7082051..c1a7a2a 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -215,7 +215,7 @@ ] } -if (!is_android && (!is_win || link_chrome_on_windows)) { +if (!is_android) { import("//chrome/chrome_tests.gni") test("interactive_ui_tests") { @@ -244,8 +244,6 @@ "//net", "//net:net_resources", "//net:test_support", - - #"//ppapi:ppapi_tests", # TODO(GYP) this doesn't exist yet. "//skia", "//sync", "//testing/gmock", @@ -261,6 +259,7 @@ # Runtime dependencies datadeps = [ + "//ppapi:ppapi_tests", "//third_party/mesa:osmesa", ] @@ -669,7 +668,8 @@ # Runtime dependencies data_deps = [ - #"//ppapi:ppapi_tests", # TODO(GYP) this doesn't exist yet. + "//ppapi:ppapi_tests", + #'../remoting/remoting.gyp:remoting_browser_test_resources', TODO(GYP) #'../remoting/remoting.gyp:remoting_webapp_unittest', TODO(GYP) "//third_party/mesa:osmesa",
diff --git a/chrome/test/base/chrome_test_suite.cc b/chrome/test/base/chrome_test_suite.cc index 30708f10..a2258b5d 100644 --- a/chrome/test/base/chrome_test_suite.cc +++ b/chrome/test/base/chrome_test_suite.cc
@@ -22,15 +22,6 @@ #include "extensions/common/constants.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_ANDROID) -#include "base/android/jni_android.h" -#include "chrome/browser/android/chrome_jni_registrar.h" -#include "net/android/net_jni_registrar.h" -#include "ui/base/android/ui_base_jni_registrar.h" -#include "ui/gfx/android/gfx_jni_registrar.h" -#include "ui/gl/android/gl_jni_registrar.h" -#endif - #if defined(OS_CHROMEOS) #include "base/process/process_metrics.h" #include "chromeos/chromeos_paths.h" @@ -81,15 +72,6 @@ #endif // !defined(OS_IOS) #endif -#if defined(OS_ANDROID) - // Register JNI bindings for android. - gfx::android::RegisterJni(base::android::AttachCurrentThread()); - net::android::RegisterJni(base::android::AttachCurrentThread()); - ui::android::RegisterJni(base::android::AttachCurrentThread()); - ui::gl::android::RegisterJni(base::android::AttachCurrentThread()); - chrome::android::RegisterJni(base::android::AttachCurrentThread()); -#endif - if (!browser_dir_.empty()) { PathService::Override(base::DIR_EXE, browser_dir_); PathService::Override(base::DIR_MODULE, browser_dir_);
diff --git a/chrome/test/base/test_browser_window.cc b/chrome/test/base/test_browser_window.cc index f04e7ae..62f9183 100644 --- a/chrome/test/base/test_browser_window.cc +++ b/chrome/test/base/test_browser_window.cc
@@ -231,3 +231,7 @@ void TestBrowserWindow::ExecuteExtensionCommand( const extensions::Extension* extension, const extensions::Command& command) {} + +ExclusiveAccessContext* TestBrowserWindow::GetExclusiveAccessContext() { + return nullptr; +}
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h index ab05492b..6ee00f2e30 100644 --- a/chrome/test/base/test_browser_window.h +++ b/chrome/test/base/test_browser_window.h
@@ -66,7 +66,7 @@ ExclusiveAccessBubbleType type, bool with_toolbar) override {} void ExitFullscreen() override {} - void UpdateFullscreenExitBubbleContent( + void UpdateExclusiveAccessExitBubbleContent( const GURL& url, ExclusiveAccessBubbleType bubble_type) override {} bool ShouldHideUIForFullscreen() const override; @@ -150,6 +150,7 @@ int GetRenderViewHeightInsetWithDetachedBookmarkBar() override; void ExecuteExtensionCommand(const extensions::Extension* extension, const extensions::Command& command) override; + ExclusiveAccessContext* GetExclusiveAccessContext() override; protected: void DestroyBrowser() override {}
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc index d320aa1..f6047a02 100644 --- a/chrome/test/base/testing_browser_process.cc +++ b/chrome/test/base/testing_browser_process.cc
@@ -154,6 +154,10 @@ return nullptr; } +PromoResourceService* TestingBrowserProcess::promo_resource_service() { + return nullptr; +} + policy::BrowserPolicyConnector* TestingBrowserProcess::browser_policy_connector() { #if defined(ENABLE_CONFIGURATION_POLICY)
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h index 757b5ba..1444c6b 100644 --- a/chrome/test/base/testing_browser_process.h +++ b/chrome/test/base/testing_browser_process.h
@@ -68,6 +68,7 @@ ProfileManager* profile_manager() override; PrefService* local_state() override; chrome_variations::VariationsService* variations_service() override; + PromoResourceService* promo_resource_service() override; policy::BrowserPolicyConnector* browser_policy_connector() override; policy::PolicyService* policy_service() override; IconManager* icon_manager() override;
diff --git a/chrome/test/data/extensions/api_test/bindings/api_enums/background.js b/chrome/test/data/extensions/api_test/bindings/api_enums/background.js new file mode 100644 index 0000000..c795e4e --- /dev/null +++ b/chrome/test/data/extensions/api_test/bindings/api_enums/background.js
@@ -0,0 +1,40 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +chrome.test.runTests([ + function() { + // Test management (backed by a json file) api enums. + + // The enum should be declared on the API object. + chrome.test.assertTrue( + 'LaunchType' in chrome.management, + '"LaunchType" is not present on chrome.management.'); + // The object should have entries for each enum entry. Note that we don't + // test all entries here because we don't want to update this test if the + // management api changes. + chrome.test.assertTrue( + 'OPEN_AS_REGULAR_TAB' in chrome.management.LaunchType, + '"OPEN_AS_REGULAR_TAB" is not present on management.LaunchType'); + // The value of the enum should be its string value. + chrome.test.assertEq(chrome.management.LaunchType.OPEN_AS_REGULAR_TAB, + 'OPEN_AS_REGULAR_TAB'); + // There should be more than one value for the enum. + chrome.test.assertTrue( + Object.keys(chrome.management.LaunchType).length > 1); + + // Perform an analogous test for the notifications api (backed by an idl). + chrome.test.assertTrue( + 'PermissionLevel' in chrome.notifications, + '"PermissionLevel" is not present on chrome.notifications.'); + chrome.test.assertTrue( + 'granted' in chrome.notifications.PermissionLevel, + '"granted" is not present on notifications.PermissionLevel'); + chrome.test.assertEq(chrome.notifications.PermissionLevel.granted, + 'granted'); + chrome.test.assertTrue( + Object.keys(chrome.notifications.PermissionLevel).length > 1); + + chrome.test.succeed(); + } +]);
diff --git a/chrome/test/data/extensions/api_test/bindings/api_enums/manifest.json b/chrome/test/data/extensions/api_test/bindings/api_enums/manifest.json new file mode 100644 index 0000000..49c3850 --- /dev/null +++ b/chrome/test/data/extensions/api_test/bindings/api_enums/manifest.json
@@ -0,0 +1,9 @@ +{ + "name": "bindings/api_enums", + "manifest_version": 2, + "version": "1", + "background": { + "scripts": ["background.js"] + }, + "permissions": ["management", "notifications"] +}
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 b106b76..fb46498 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
@@ -25,16 +25,19 @@ // Clobbering constructors would break everything. // Clobbering toString is annoying. // Clobbering __proto__ breaks in ways that grep can't find. + // Clobbering function name will break because + // SafeBuiltins does not support getters yet. See crbug.com/463526. // Clobbering Function.call would make it impossible to implement these tests. // Clobbering Object.valueOf breaks v8. if (name == 'constructor' || name == 'toString' || name == '__proto__' || + name == 'name' && typeof obj == 'function' || qualifiedName == 'Function.call' || qualifiedName == 'Object.valueOf') { return; } - if (typeof(obj[name]) == 'function') { + if (typeof obj[name] == 'function') { obj[name] = function() { throw new Error('Clobbered ' + qualifiedName + ' function'); };
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_auth_required.js b/chrome/test/data/extensions/api_test/webrequest/test_auth_required.js index 500eaab4..7e6b779 100644 --- a/chrome/test/data/extensions/api_test/webrequest/test_auth_required.js +++ b/chrome/test/data/extensions/api_test/webrequest/test_auth_required.js
@@ -41,7 +41,8 @@ details: { url: url, responseHeadersExist: true, - statusLine: "HTTP/1.1 401 Unauthorized" + statusLine: "HTTP/1.1 401 Unauthorized", + statusCode: 401, } }, { label: "onAuthRequired", @@ -119,7 +120,8 @@ details: { url: url, responseHeadersExist: true, - statusLine: "HTTP/1.1 401 Unauthorized" + statusLine: "HTTP/1.1 401 Unauthorized", + statusCode: 401, } }, { label: "onAuthRequired", @@ -199,7 +201,8 @@ details: { url: url, responseHeadersExist: true, - statusLine: "HTTP/1.1 401 Unauthorized" + statusLine: "HTTP/1.1 401 Unauthorized", + statusCode: 401, } }, { label: "onAuthRequired", @@ -281,7 +284,8 @@ details: { url: url, responseHeadersExist: true, - statusLine: "HTTP/1.1 401 Unauthorized" + statusLine: "HTTP/1.1 401 Unauthorized", + statusCode: 401, } }, { label: "onAuthRequired", @@ -361,7 +365,8 @@ details: { url: url, responseHeadersExist: true, - statusLine: "HTTP/1.1 401 Unauthorized" + statusLine: "HTTP/1.1 401 Unauthorized", + statusCode: 401, } }, { label: "onAuthRequired", @@ -441,7 +446,8 @@ details: { url: url, responseHeadersExist: true, - statusLine: "HTTP/1.1 401 Unauthorized" + statusLine: "HTTP/1.1 401 Unauthorized", + statusCode: 401, } }, { label: "onAuthRequired", @@ -523,7 +529,8 @@ details: { url: url, responseHeadersExist: true, - statusLine: "HTTP/1.1 401 Unauthorized" + statusLine: "HTTP/1.1 401 Unauthorized", + statusCode: 401, } }, { label: "onAuthRequired",
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_blocking.js b/chrome/test/data/extensions/api_test/webrequest/test_blocking.js index 93008a6a..3cd5d9b 100644 --- a/chrome/test/data/extensions/api_test/webrequest/test_blocking.js +++ b/chrome/test/data/extensions/api_test/webrequest/test_blocking.js
@@ -101,6 +101,7 @@ details: { url: getURLHttpSimpleLoad(), statusLine: "HTTP/1.1 200 OK", + statusCode: 200, }, retval: {cancel: true} }, @@ -160,6 +161,7 @@ details: { url: getURLHttpSimpleLoad(), statusLine: "HTTP/1.1 200 OK", + statusCode: 200, } }, { label: "onResponseStarted", @@ -230,6 +232,7 @@ details: { url: getURLHttpSimpleLoad(), statusLine: "HTTP/1.1 200 OK", + statusCode: 200, } }, { label: "onResponseStarted", @@ -364,6 +367,7 @@ details: { url: getURLEchoUserAgent(), statusLine: "HTTP/1.1 200 OK", + statusCode: 200, } }, { label: "onResponseStarted", @@ -439,6 +443,7 @@ details: { url: getURLEchoUserAgent(), statusLine: "HTTP/1.1 200 OK", + statusCode: 200, } }, { label: "onResponseStarted", @@ -512,6 +517,7 @@ details: { url: getURLSetCookie(), statusLine: "HTTP/1.1 200 OK", + statusCode: 200, responseHeadersExist: true, }, retval_function: function(name, details) { @@ -602,6 +608,7 @@ details: { url: getURLNonUTF8SetCookie(), statusLine: "HTTP/1.1 200 OK", + statusCode: 200, responseHeadersExist: true, }, retval_function: function(name, details) { @@ -699,6 +706,7 @@ details: { url: getURLHttpSimpleLoad(), statusLine: "HTTP/1.1 200 OK", + statusCode: 200, }, retval: {redirectUrl: getURL("simpleLoad/a.html")} }, @@ -943,6 +951,7 @@ tabId: 1, type: "xmlhttprequest", statusLine: "HTTP/1.1 200 OK", + statusCode: 200, } }, { label: "x-onCompleted", @@ -1074,6 +1083,7 @@ type: "image", url: redirectTarget, statusLine: "HTTP/1.1 200 OK", + statusCode: 200, } }, { label: "onResponseStarted",
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_complex.js b/chrome/test/data/extensions/api_test/webrequest/test_complex.js index 9d4e24c..a66ac3b2 100644 --- a/chrome/test/data/extensions/api_test/webrequest/test_complex.js +++ b/chrome/test/data/extensions/api_test/webrequest/test_complex.js
@@ -253,6 +253,7 @@ type: "main_frame", url: getURLHttpXHR(), statusLine: "HTTP/1.1 200 OK", + statusCode: 200, } }, { label: "onResponseStarted-1", @@ -305,6 +306,7 @@ type: "script", url: getURLHttpXHRJavaScript(), statusLine: "HTTP/1.1 200 OK", + statusCode: 200, } }, { label: "a.js-onResponseStarted", @@ -357,6 +359,7 @@ type: "xmlhttprequest", url: getURLHttpXHRData(), statusLine: "HTTP/1.1 200 OK", + statusCode: 200, } }, { label: "onResponseStarted-2",
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_declarative1.js b/chrome/test/data/extensions/api_test/webrequest/test_declarative1.js index 591f329..ad96b3b 100644 --- a/chrome/test/data/extensions/api_test/webrequest/test_declarative1.js +++ b/chrome/test/data/extensions/api_test/webrequest/test_declarative1.js
@@ -80,7 +80,8 @@ event: "onHeadersReceived", details: { url: getURLOfHTMLWithThirdParty(), - statusLine: "HTTP/1.1 200 OK" + statusLine: "HTTP/1.1 200 OK", + statusCode: 200 } }, { label: "onResponseStarted", @@ -198,6 +199,7 @@ details: { statusLine: "HTTP/1.1 200 OK", url: getURLHttpWithHeaders(), + statusCode: 200 } }, { label: "onErrorOccurred",
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_simple.js b/chrome/test/data/extensions/api_test/webrequest/test_simple.js index 2ef4a05..5a2218d 100644 --- a/chrome/test/data/extensions/api_test/webrequest/test_simple.js +++ b/chrome/test/data/extensions/api_test/webrequest/test_simple.js
@@ -80,7 +80,8 @@ details: { url: getURLHttpSimpleLoadRedirect(), responseHeadersExist: true, - statusLine: "HTTP/1.1 301 Moved Permanently" + statusLine: "HTTP/1.1 301 Moved Permanently", + statusCode: 301 } }, { label: "onBeforeRedirect", @@ -122,6 +123,7 @@ url: getURLHttpSimpleLoad(), responseHeadersExist: true, statusLine: "HTTP/1.1 200 OK", + statusCode: 200 } }, { label: "onResponseStarted",
diff --git a/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.html b/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.html index 8060cb2..f7d49cd 100644 --- a/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.html +++ b/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.html
@@ -6,6 +6,7 @@ <html> <body> +<input id="textfield" type="text"> <script src="main.js"></script> </body> </html>
diff --git a/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js b/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js index bd16ca6..ce4fdc07 100644 --- a/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js +++ b/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js
@@ -31,4 +31,15 @@ }); } -chrome.test.sendMessage('Launched'); +document.addEventListener('DOMContentLoaded', function() { + chrome.test.sendMessage('Launched'); +}); + +var textfield = document.getElementById('textfield'); +textfield.onfocus = function() { + chrome.test.sendMessage('textfieldFocused'); +}; + +textfield.onblur = function() { + chrome.test.sendMessage('textfieldBlurred'); +};
diff --git a/chrome/test/data/extensions/platform_apps/hidden_with_id/empty.html b/chrome/test/data/extensions/platform_apps/hidden_with_id/empty.html new file mode 100644 index 0000000..aabcd1b --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/hidden_with_id/empty.html
@@ -0,0 +1 @@ +<!-- This file intentionally left blank. -->
diff --git a/chrome/test/data/extensions/platform_apps/hidden_with_id/manifest.json b/chrome/test/data/extensions/platform_apps/hidden_with_id/manifest.json new file mode 100644 index 0000000..098c347 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/hidden_with_id/manifest.json
@@ -0,0 +1,10 @@ +{ + "name": "Platform App Hidden With ID", + "version": "1", + "manifest_version": 2, + "app": { + "background": { + "scripts": ["test.js"] + } + } +}
diff --git a/chrome/test/data/extensions/platform_apps/hidden_with_id/test.js b/chrome/test/data/extensions/platform_apps/hidden_with_id/test.js new file mode 100644 index 0000000..91ccea0 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/hidden_with_id/test.js
@@ -0,0 +1,31 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function sendLaunchedAndRunReply() { + chrome.test.sendMessage('Launched', function (reply) { + if (reply) + window[reply](); + }); +} + +function createHidden() { + chrome.app.window.create('empty.html', { + id: 'hidden_with_id', + hidden: true, + }, function () { + sendLaunchedAndRunReply(); + }); +} + +function createVisible() { + chrome.app.window.create('empty.html', { + id: 'hidden_with_id', + }, function () { + sendLaunchedAndRunReply(); + }); +} + +chrome.app.runtime.onLaunched.addListener(function() { + sendLaunchedAndRunReply(); +});
diff --git a/chrome/test/data/extensions/platform_apps/web_view/shim/main.js b/chrome/test/data/extensions/platform_apps/web_view/shim/main.js index 763b63d..fbb4623 100644 --- a/chrome/test/data/extensions/platform_apps/web_view/shim/main.js +++ b/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
@@ -549,38 +549,6 @@ document.body.appendChild(webview); } -function testDeclarativeContentAPIExistence() { - var apiPropertiesToCheck = [ - // Declarative Content API. - 'onPageChanged' - ]; - var webview = document.createElement('webview'); - webview.setAttribute('partition', arguments.callee.name); - webview.addEventListener('loadstop', function(e) { - for (var i = 0; i < apiPropertiesToCheck.length; ++i) { - embedder.test.assertEq('object', - typeof webview.request[apiPropertiesToCheck[i]]); - embedder.test.assertEq( - 'function', - typeof webview.request[apiPropertiesToCheck[i]].addRules); - embedder.test.assertEq( - 'function', - typeof webview.request[apiPropertiesToCheck[i]].getRules); - embedder.test.assertEq( - 'function', - typeof webview.request[apiPropertiesToCheck[i]].removeRules); - } - - // Try to overwrite webview.request, shall not succeed. - webview.request = '123'; - embedder.test.assertTrue(typeof webview.request !== 'string'); - - embedder.test.succeed(); - }); - webview.setAttribute('src', 'data:text/html,webview check api'); - document.body.appendChild(webview); -} - // This test verifies that the loadstart, loadstop, and exit events fire as // expected. function testEventName() { @@ -2080,7 +2048,6 @@ testInlineScriptFromAccessibleResources, 'testInvalidChromeExtensionURL': testInvalidChromeExtensionURL, 'testWebRequestAPIExistence': testWebRequestAPIExistence, - 'testDeclarativeContentAPIExistence': testDeclarativeContentAPIExistence, 'testEventName': testEventName, 'testOnEventProperties': testOnEventProperties, 'testLoadProgressEvent': testLoadProgressEvent,
diff --git a/chrome/test/data/notifications/android_test_worker.js b/chrome/test/data/notifications/android_test_worker.js index 421494a..f2a2de5 100644 --- a/chrome/test/data/notifications/android_test_worker.js +++ b/chrome/test/data/notifications/android_test_worker.js
@@ -8,3 +8,7 @@ messagePort = event.data; messagePort.postMessage('ready'); }); + +addEventListener('notificationclick', function(event) { + event.notification.close(); +});
diff --git a/chrome/test/data/password/many_password_signup_form.html b/chrome/test/data/password/many_password_signup_form.html new file mode 100644 index 0000000..1003155 --- /dev/null +++ b/chrome/test/data/password/many_password_signup_form.html
@@ -0,0 +1,13 @@ +<html> +<body> +<form method="POST" action="done.html" onsubmit="return true;" id="testform"> + <input type="text" id="username_field" name="username_field"> + <input type="password" id="password_field" name="password_field"> + <input type="password" id="confirm_field" name="confirm_field"> + <input type="password" id="security_answer" name="security_answer"> + <input type="text" id="more_info" name="more_info"> + <input type="password" id="SSN" name="SSN"> + <input type="submit" id="input_submit_button" name="input_submit_button"> +</form> +</html> +</body>
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index 5b69cb0..878c0107 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -470,6 +470,14 @@ "note": "This policy is retired, see http://crbug.com/133291." }, + "CaptivePortalAuthenticationIgnoresProxy": { + "os": ["chromeos"], + "test_policy": { "CaptivePortalAuthenticationIgnoresProxy": true }, + "pref_mappings": [ + { "pref": "proxy.captive_portal_ignores_proxy" } + ] + }, + "ProxyMode": { "os": ["win", "mac", "linux"], "test_policy": { "ProxyMode": "direct" },
diff --git a/chrome/test/data/webrtc/resources/tools/linux/ffmpeg.sha1 b/chrome/test/data/webrtc/resources/tools/linux/ffmpeg.sha1 new file mode 100644 index 0000000..4e0ba67f --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/linux/ffmpeg.sha1
@@ -0,0 +1 @@ +333a4e5ef11602e30efbc3081291aa7760b2bc23 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/pesq.sha1 b/chrome/test/data/webrtc/resources/tools/linux/pesq.sha1 similarity index 100% rename from chrome/test/data/webrtc/resources/tools/pesq.sha1 rename to chrome/test/data/webrtc/resources/tools/linux/pesq.sha1
diff --git a/chrome/test/data/webrtc/resources/tools/linux/zxing.sha1 b/chrome/test/data/webrtc/resources/tools/linux/zxing.sha1 new file mode 100644 index 0000000..d789e39 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/linux/zxing.sha1
@@ -0,0 +1 @@ +f3cf3f6b42977821708f1586099da7cccfaf5eeb \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/mac/ffmpeg.sha1 b/chrome/test/data/webrtc/resources/tools/mac/ffmpeg.sha1 new file mode 100644 index 0000000..b8c380f3 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/mac/ffmpeg.sha1
@@ -0,0 +1 @@ +58783bcefa695b050c23ae29fd044e1d1974d2bc \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/pesq_mac.sha1 b/chrome/test/data/webrtc/resources/tools/mac/pesq.sha1 similarity index 100% rename from chrome/test/data/webrtc/resources/tools/pesq_mac.sha1 rename to chrome/test/data/webrtc/resources/tools/mac/pesq.sha1
diff --git a/chrome/test/data/webrtc/resources/tools/mac/zxing.sha1 b/chrome/test/data/webrtc/resources/tools/mac/zxing.sha1 new file mode 100644 index 0000000..1b496e7c --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/mac/zxing.sha1
@@ -0,0 +1 @@ +6778e3ac489f4fc18a1ed1252bbd6eca54c9960e \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygEMF-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygEMF-1.dll.sha1 new file mode 100644 index 0000000..13ada8aa --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygEMF-1.dll.sha1
@@ -0,0 +1 @@ +4dffd9a099f6e541a0d2aff162aebb4438aa8bf7 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygICE-6.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygICE-6.dll.sha1 new file mode 100644 index 0000000..3bbd905 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygICE-6.dll.sha1
@@ -0,0 +1 @@ +5381656ace3270e8ef8f707c9df288fde75cef72 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygMagick++-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygMagick++-1.dll.sha1 new file mode 100644 index 0000000..ff934c70 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygMagick++-1.dll.sha1
@@ -0,0 +1 @@ +120b4f60511d1e8cdd14fbade0c814feefb0c7b2 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygMagick++-5.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygMagick++-5.dll.sha1 new file mode 100644 index 0000000..2534411 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygMagick++-5.dll.sha1
@@ -0,0 +1 @@ +5ecd18f12adb080e1bb82cf88d33f6b450222888 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygMagickCore-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygMagickCore-1.dll.sha1 new file mode 100644 index 0000000..34b4d738 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygMagickCore-1.dll.sha1
@@ -0,0 +1 @@ +c289cd5eb1130bc86bf290b2e5a636f762a1008c \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygMagickCore-5.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygMagickCore-5.dll.sha1 new file mode 100644 index 0000000..2661f9d --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygMagickCore-5.dll.sha1
@@ -0,0 +1 @@ +520657343b39e45c455979cbe1871e931ec6df2d \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygMagickWand-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygMagickWand-1.dll.sha1 new file mode 100644 index 0000000..802a7dbd --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygMagickWand-1.dll.sha1
@@ -0,0 +1 @@ +5b5a74b3e82b5868210ab2544f6978bf700116c1 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygMagickWand-5.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygMagickWand-5.dll.sha1 new file mode 100644 index 0000000..bb199cd --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygMagickWand-5.dll.sha1
@@ -0,0 +1 @@ +8a4a4756b6331376b0ad154d5f9e4f3260520a38 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygSM-6.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygSM-6.dll.sha1 new file mode 100644 index 0000000..1bfe2fca --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygSM-6.dll.sha1
@@ -0,0 +1 @@ +b797e00e7611e52414a016edd47ee4c9e8d900e4 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygX11-6.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygX11-6.dll.sha1 new file mode 100644 index 0000000..2f7a878f --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygX11-6.dll.sha1
@@ -0,0 +1 @@ +9c9f218d3cd887c9e2c9c59bbafe1261ffaf7e84 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygXau-6.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygXau-6.dll.sha1 new file mode 100644 index 0000000..9948b7f --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygXau-6.dll.sha1
@@ -0,0 +1 @@ +2c8229b012e529bbe818a8edfd15c03e90eadf5d \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygXaw-7.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygXaw-7.dll.sha1 new file mode 100644 index 0000000..3d5bb84c --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygXaw-7.dll.sha1
@@ -0,0 +1 @@ +6fe7631a96ab1a806e1c73ce646d2ddc560be7f9 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygXdmcp-6.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygXdmcp-6.dll.sha1 new file mode 100644 index 0000000..3b450261 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygXdmcp-6.dll.sha1
@@ -0,0 +1 @@ +0e6982fa3e0e9a83c7112d096ed276fab086a955 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygXext-6.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygXext-6.dll.sha1 new file mode 100644 index 0000000..485d0fa6 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygXext-6.dll.sha1
@@ -0,0 +1 @@ +e6a68be83898d69b15c66b735d6eaaa4ea6aedf0 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygXft-2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygXft-2.dll.sha1 new file mode 100644 index 0000000..b0b18c76 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygXft-2.dll.sha1
@@ -0,0 +1 @@ +bc682da3888716c0f982db7e3bf3d46d41c736e5 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygXmu-6.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygXmu-6.dll.sha1 new file mode 100644 index 0000000..8b414fe --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygXmu-6.dll.sha1
@@ -0,0 +1 @@ +48063eb7f607c8a7c0c540faccf388966cb92f42 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygXpm-4.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygXpm-4.dll.sha1 new file mode 100644 index 0000000..0e3c4099 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygXpm-4.dll.sha1
@@ -0,0 +1 @@ +fc6213ed13d99ec14d22bfc5a9c533b67094a792 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygXrender-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygXrender-1.dll.sha1 new file mode 100644 index 0000000..9b08e78 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygXrender-1.dll.sha1
@@ -0,0 +1 @@ +c6940d61bd14db07a707824edd2b67e6a1b6e1e2 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygXt-6.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygXt-6.dll.sha1 new file mode 100644 index 0000000..843827f --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygXt-6.dll.sha1
@@ -0,0 +1 @@ +a5a528a2f4398b2097af60c2070745ce229f4005 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygattr-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygattr-1.dll.sha1 new file mode 100644 index 0000000..a04198a --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygattr-1.dll.sha1
@@ -0,0 +1 @@ +0e84a068d46a4691d55603b99c6341ae0b049243 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygautotrace-3.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygautotrace-3.dll.sha1 new file mode 100644 index 0000000..8c05563 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygautotrace-3.dll.sha1
@@ -0,0 +1 @@ +6e2bb1cc1fce79ba221cfbf0ef21634327fc580a \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygbz2-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygbz2-1.dll.sha1 new file mode 100644 index 0000000..133ba08 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygbz2-1.dll.sha1
@@ -0,0 +1 @@ +990f8dcd0934b73cd0bd87b1482f7b532cfed071 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygcairo-2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygcairo-2.dll.sha1 new file mode 100644 index 0000000..e2f3505 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygcairo-2.dll.sha1
@@ -0,0 +1 @@ +bea314b000f02bb42d7dec160ab4b4749b6f82c5 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygcairo-gobject-2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygcairo-gobject-2.dll.sha1 new file mode 100644 index 0000000..f2b49a1 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygcairo-gobject-2.dll.sha1
@@ -0,0 +1 @@ +13cb1e859801f0008f8dca05e2edb2389db2b716 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygcairo-script-interpreter-2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygcairo-script-interpreter-2.dll.sha1 new file mode 100644 index 0000000..5e207d64 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygcairo-script-interpreter-2.dll.sha1
@@ -0,0 +1 @@ +3a743c3eb16932b770252624fa440a3d66a21cd0 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygcharset-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygcharset-1.dll.sha1 new file mode 100644 index 0000000..a8c7e75ca --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygcharset-1.dll.sha1
@@ -0,0 +1 @@ +790a74405e115d386ae95e00ded534bebcd2a0fa \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygcroco-0.6-3.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygcroco-0.6-3.dll.sha1 new file mode 100644 index 0000000..284863c --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygcroco-0.6-3.dll.sha1
@@ -0,0 +1 @@ +b6efb1d84d7296db090b0ce6a16dd74d8d05c479 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygcrypt-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygcrypt-0.dll.sha1 new file mode 100644 index 0000000..d520d25 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygcrypt-0.dll.sha1
@@ -0,0 +1 @@ +8b8d9c937ee18ebd2ea709b334e3600cea0dfbdf \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygcrypto-0.9.8.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygcrypto-0.9.8.dll.sha1 new file mode 100644 index 0000000..ee70809 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygcrypto-0.9.8.dll.sha1
@@ -0,0 +1 @@ +1abeec13689e403a4b59802aa74bedc10147d161 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygcrypto-1.0.0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygcrypto-1.0.0.dll.sha1 new file mode 100644 index 0000000..947b23a --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygcrypto-1.0.0.dll.sha1
@@ -0,0 +1 @@ +b8d5f99e6f5c87003ca1046511a1b11a6482e8da \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygdatrie-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygdatrie-1.dll.sha1 new file mode 100644 index 0000000..e29954d --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygdatrie-1.dll.sha1
@@ -0,0 +1 @@ +971fca4d171b8587ddbd036fc03a0957f864d219 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygdb-4.5.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygdb-4.5.dll.sha1 new file mode 100644 index 0000000..b61e245 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygdb-4.5.dll.sha1
@@ -0,0 +1 @@ +6e6cfc54f0e599b487c6121b4085b445666b281c \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygdb_cxx-4.5.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygdb_cxx-4.5.dll.sha1 new file mode 100644 index 0000000..64dc869 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygdb_cxx-4.5.dll.sha1
@@ -0,0 +1 @@ +ec7661eb54a3b67d4bb5b3d2e97a985e86956b9c \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygdbus-1-3.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygdbus-1-3.dll.sha1 new file mode 100644 index 0000000..831e3b0a --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygdbus-1-3.dll.sha1
@@ -0,0 +1 @@ +3ff66e122ec05ee5920a22168e0a13cc1f1f5c94 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygexpat-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygexpat-1.dll.sha1 new file mode 100644 index 0000000..4fb05ec2 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygexpat-1.dll.sha1
@@ -0,0 +1 @@ +e44623ba2a32438437335c45fb4fec9e71f1c40b \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygfam-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygfam-0.dll.sha1 new file mode 100644 index 0000000..b29548f9 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygfam-0.dll.sha1
@@ -0,0 +1 @@ +d78883226a4caf68f077bd85e86e2910c64b0a7e \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygffi-4.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygffi-4.dll.sha1 new file mode 100644 index 0000000..ff5414d --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygffi-4.dll.sha1
@@ -0,0 +1 @@ +82f4ad8a1ddc9bb624f98e8a3c4b366b72a62de8 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygfftw3-3.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygfftw3-3.dll.sha1 new file mode 100644 index 0000000..af8972d --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygfftw3-3.dll.sha1
@@ -0,0 +1 @@ +2a03cf1072fe7dca391d7c60e97c1abeb114f1d3 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygfftw3_threads-3.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygfftw3_threads-3.dll.sha1 new file mode 100644 index 0000000..1cf15c0 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygfftw3_threads-3.dll.sha1
@@ -0,0 +1 @@ +0abae96305f254a75d5d501720891a3cf94aa90e \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygfftw3f-3.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygfftw3f-3.dll.sha1 new file mode 100644 index 0000000..905ecdc --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygfftw3f-3.dll.sha1
@@ -0,0 +1 @@ +2421e456d3f3d5696f4a0e05508bdaf4845e22d1 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygfftw3f_threads-3.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygfftw3f_threads-3.dll.sha1 new file mode 100644 index 0000000..9ab935b --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygfftw3f_threads-3.dll.sha1
@@ -0,0 +1 @@ +c5f59c5596e528550e18d0f49287a1009188a987 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygfontconfig-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygfontconfig-1.dll.sha1 new file mode 100644 index 0000000..0b9d285b --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygfontconfig-1.dll.sha1
@@ -0,0 +1 @@ +b57ece16d8fbcffc3093077cfbc59e27837d0a22 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygform-10.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygform-10.dll.sha1 new file mode 100644 index 0000000..4e8a9ec --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygform-10.dll.sha1
@@ -0,0 +1 @@ +ad015f1a5519f4273bf363f672517ef3f6979d1e \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygformw-10.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygformw-10.dll.sha1 new file mode 100644 index 0000000..3672c59b --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygformw-10.dll.sha1
@@ -0,0 +1 @@ +f916406b3c3089fdcf30704a2cbc950c8777e8ee \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygfpx-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygfpx-1.dll.sha1 new file mode 100644 index 0000000..0e2460f --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygfpx-1.dll.sha1
@@ -0,0 +1 @@ +5bd5c3dc8cf76f5b51924ac791732cab9c1bfbc9 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygfreetype-6.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygfreetype-6.dll.sha1 new file mode 100644 index 0000000..dbcc05e9 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygfreetype-6.dll.sha1
@@ -0,0 +1 @@ +c1dab7fcaf8e432da82bb54db0fe5443dcc6108e \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggcc_s-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggcc_s-1.dll.sha1 new file mode 100644 index 0000000..c816925 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggcc_s-1.dll.sha1
@@ -0,0 +1 @@ +9e1bf06cb56add8605dbc30fca7f80456ae277f7 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggd-2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggd-2.dll.sha1 new file mode 100644 index 0000000..5676c292 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggd-2.dll.sha1
@@ -0,0 +1 @@ +fb6196220213b528fde5240644092cb46f280241 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggdbm-4.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggdbm-4.dll.sha1 new file mode 100644 index 0000000..b9993822 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggdbm-4.dll.sha1
@@ -0,0 +1 @@ +313d5bcff3cec41fd0ad900f9b85ad0496faa321 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggdbm_compat-4.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggdbm_compat-4.dll.sha1 new file mode 100644 index 0000000..50daa35 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggdbm_compat-4.dll.sha1
@@ -0,0 +1 @@ +25aa87318875cc0dc629bba4ef026a1ff317a3af \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggdk_pixbuf-2.0-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggdk_pixbuf-2.0-0.dll.sha1 new file mode 100644 index 0000000..06050c6 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggdk_pixbuf-2.0-0.dll.sha1
@@ -0,0 +1 @@ +5219082f9f75966922b87a7af74c00b646c4727f \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggif-4.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggif-4.dll.sha1 new file mode 100644 index 0000000..d3ea402 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggif-4.dll.sha1
@@ -0,0 +1 @@ +cc7e49fc71a1fe9a0ab71abc0abd7f20e0343869 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggio-2.0-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggio-2.0-0.dll.sha1 new file mode 100644 index 0000000..41244e16 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggio-2.0-0.dll.sha1
@@ -0,0 +1 @@ +440585cf42662e7914b6e56e2382b02fdbba6b46 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygglib-2.0-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygglib-2.0-0.dll.sha1 new file mode 100644 index 0000000..ce1f4c9 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygglib-2.0-0.dll.sha1
@@ -0,0 +1 @@ +343f7949dc69522a2e113d6d38de44d978d2faef \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggmodule-2.0-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggmodule-2.0-0.dll.sha1 new file mode 100644 index 0000000..15de0ac --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggmodule-2.0-0.dll.sha1
@@ -0,0 +1 @@ +37ef0fbb18621551f330cc62fbd47b3e8d9c8f5a \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggmp-3.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggmp-3.dll.sha1 new file mode 100644 index 0000000..e5f0b576 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggmp-3.dll.sha1
@@ -0,0 +1 @@ +565d5ff727282f6d816bf92172922d14182ec94c \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggobject-2.0-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggobject-2.0-0.dll.sha1 new file mode 100644 index 0000000..1d8ee64 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggobject-2.0-0.dll.sha1
@@ -0,0 +1 @@ +700bc0a7f33b277879f29ddcfabc2b402610cb77 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggomp-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggomp-1.dll.sha1 new file mode 100644 index 0000000..d37a7e1 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggomp-1.dll.sha1
@@ -0,0 +1 @@ +73f38ddbd12332c016df34cfcca2ba921e65dc65 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggraphite2-3.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggraphite2-3.dll.sha1 new file mode 100644 index 0000000..e1a89dc --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggraphite2-3.dll.sha1
@@ -0,0 +1 @@ +9efd795275d1f96517e5a0f244d8a7475db5cb1d \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggs-9.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggs-9.dll.sha1 new file mode 100644 index 0000000..7b57c30 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggs-9.dll.sha1
@@ -0,0 +1 @@ +b625a1ae0239575c71ccda73ce45d0968104fc25 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyggthread-2.0-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyggthread-2.0-0.dll.sha1 new file mode 100644 index 0000000..abe679e --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyggthread-2.0-0.dll.sha1
@@ -0,0 +1 @@ +e92450092f0bc993ecbcd7ffded19c1c5065f576 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygharfbuzz-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygharfbuzz-0.dll.sha1 new file mode 100644 index 0000000..1be2898 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygharfbuzz-0.dll.sha1
@@ -0,0 +1 @@ +b85e98d97e0a5d4433944f9a61702b8c72de01a6 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyghistory7.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyghistory7.dll.sha1 new file mode 100644 index 0000000..81523127 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyghistory7.dll.sha1
@@ -0,0 +1 @@ +7e956b29c3dcc794b0f1c3fce846672c52dbd4e1 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicons-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicons-0.dll.sha1 new file mode 100644 index 0000000..52d6853 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicons-0.dll.sha1
@@ -0,0 +1 @@ +898ff4657f30ca444730bdc3bb001514c1716046 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygiconv-2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygiconv-2.dll.sha1 new file mode 100644 index 0000000..696104bd --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygiconv-2.dll.sha1
@@ -0,0 +1 @@ +c120461cdd2fc30c69706cc63b27ae49bdea675c \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicudata.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicudata.dll.sha1 new file mode 100644 index 0000000..3e9f951 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicudata.dll.sha1
@@ -0,0 +1 @@ +58c1f82ef478adefd0033395cda1485b9412c7b3 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicudata48.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicudata48.dll.sha1 new file mode 100644 index 0000000..28a598c --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicudata48.dll.sha1
@@ -0,0 +1 @@ +92ca111c2be38397991c44ccacc3a67cb5c6a5b8 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicui18n.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicui18n.dll.sha1 new file mode 100644 index 0000000..b5f51a1 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicui18n.dll.sha1
@@ -0,0 +1 @@ +2a015f94928e5b7d52958c7be9775a896e51398a \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicui18n48.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicui18n48.dll.sha1 new file mode 100644 index 0000000..42096dfc --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicui18n48.dll.sha1
@@ -0,0 +1 @@ +66426b6620d0fed4177c295dad2a63756f6cc593 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicuio.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicuio.dll.sha1 new file mode 100644 index 0000000..11f5ba9d --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicuio.dll.sha1
@@ -0,0 +1 @@ +a3c8274ea09f70f9c01117236e123089c5163934 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicuio48.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicuio48.dll.sha1 new file mode 100644 index 0000000..661d07bf --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicuio48.dll.sha1
@@ -0,0 +1 @@ +b17017f069e79f25a1aed785b5a434f225ee8dbf \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicule.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicule.dll.sha1 new file mode 100644 index 0000000..298950f --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicule.dll.sha1
@@ -0,0 +1 @@ +78198238fdd2d0f0273634f5f1bf45df2d540070 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicule48.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicule48.dll.sha1 new file mode 100644 index 0000000..31e9bde2 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicule48.dll.sha1
@@ -0,0 +1 @@ +9b58dc534be46a869da670d33e264f8e24f757a1 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygiculx.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygiculx.dll.sha1 new file mode 100644 index 0000000..591068ad5 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygiculx.dll.sha1
@@ -0,0 +1 @@ +6067e76fa0a2a0deee325780f2fb024e21d4c38f \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygiculx48.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygiculx48.dll.sha1 new file mode 100644 index 0000000..faa04f6 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygiculx48.dll.sha1
@@ -0,0 +1 @@ +795e3529a036d9f91eab404d9b12f58ba8df687e \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicutest.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicutest.dll.sha1 new file mode 100644 index 0000000..342df7e --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicutest.dll.sha1
@@ -0,0 +1 @@ +220a64eaea188d884f7090137290469b4cebb8d8 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicutest48.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicutest48.dll.sha1 new file mode 100644 index 0000000..29d49ffd --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicutest48.dll.sha1
@@ -0,0 +1 @@ +ed1837353a5cf3f0b8df58566fb6fbadd13b32ef \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicuuc.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicuuc.dll.sha1 new file mode 100644 index 0000000..2e0c7166 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicuuc.dll.sha1
@@ -0,0 +1 @@ +60c0353aec5d23b01575ae827c9c52f14bf444df \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygicuuc48.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygicuuc48.dll.sha1 new file mode 100644 index 0000000..f41e4777 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygicuuc48.dll.sha1
@@ -0,0 +1 @@ +989854added78030b05bec29fb9607f3e61ca261 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygidn-11.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygidn-11.dll.sha1 new file mode 100644 index 0000000..833c24f --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygidn-11.dll.sha1
@@ -0,0 +1 @@ +6809296c66c4d25f6866ea72600137a7e95a9941 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygintl-3.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygintl-3.dll.sha1 new file mode 100644 index 0000000..99aa504 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygintl-3.dll.sha1
@@ -0,0 +1 @@ +3a355271c58342a39f5c221ed28f6238cbf2f5c6 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygintl-8.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygintl-8.dll.sha1 new file mode 100644 index 0000000..6f71b30 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygintl-8.dll.sha1
@@ -0,0 +1 @@ +72c33b4c94cc8a73bf374cd8a942d6c590f20be8 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygjasper-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygjasper-1.dll.sha1 new file mode 100644 index 0000000..d643922 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygjasper-1.dll.sha1
@@ -0,0 +1 @@ +9a38b383ab963d5a84b23297d61dccfc42228b8f \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygjbig-2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygjbig-2.dll.sha1 new file mode 100644 index 0000000..6453edf --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygjbig-2.dll.sha1
@@ -0,0 +1 @@ +cb6362af2e9ab44f25f5cd337dbfc513b3399840 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygjpeg-7.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygjpeg-7.dll.sha1 new file mode 100644 index 0000000..86cb1f5 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygjpeg-7.dll.sha1
@@ -0,0 +1 @@ +ba24c6a42c9c959a72a6edbf2c86f35b4faa9684 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygjpeg-8.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygjpeg-8.dll.sha1 new file mode 100644 index 0000000..15d38d6e --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygjpeg-8.dll.sha1
@@ -0,0 +1 @@ +551cc8498767757803d222160613d202905d759d \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyglcms-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyglcms-1.dll.sha1 new file mode 100644 index 0000000..1dfea8a --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyglcms-1.dll.sha1
@@ -0,0 +1 @@ +5e80e346bc2e538f71216db1c4f52d7e1dbe6e66 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyglcms2-2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyglcms2-2.dll.sha1 new file mode 100644 index 0000000..59fd4db --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyglcms2-2.dll.sha1
@@ -0,0 +1 @@ +c8cab07b75d2cc1d303f76e1876bc1768068f042 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyglsa.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyglsa.dll.sha1 new file mode 100644 index 0000000..a3926a3c --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyglsa.dll.sha1
@@ -0,0 +1 @@ +2ffabc758eaf6a2a8566294618633e0dd7322477 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyglsa64.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyglsa64.dll.sha1 new file mode 100644 index 0000000..21e1ea7 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyglsa64.dll.sha1
@@ -0,0 +1 @@ +b14940b39351282ebb9f23c600c9f8d9c337833e \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygltdl-7.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygltdl-7.dll.sha1 new file mode 100644 index 0000000..d3b3849 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygltdl-7.dll.sha1
@@ -0,0 +1 @@ +f58d53e0fcfc4fc98851cce9f0aacf7d6ed1388c \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyglzma-5.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyglzma-5.dll.sha1 new file mode 100644 index 0000000..ddf8309c --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyglzma-5.dll.sha1
@@ -0,0 +1 @@ +65a0e994a1b3d5578e39c10fa284f4fb13bfeb88 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygmagic-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygmagic-1.dll.sha1 new file mode 100644 index 0000000..adbd1d8 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygmagic-1.dll.sha1
@@ -0,0 +1 @@ +c0b04a2444445fbc382467439c51cdbc1e90f009 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygmenu-10.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygmenu-10.dll.sha1 new file mode 100644 index 0000000..499eda8 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygmenu-10.dll.sha1
@@ -0,0 +1 @@ +c7a6a30626107ad1150cc1074d62a476728edfec \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygmenuw-10.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygmenuw-10.dll.sha1 new file mode 100644 index 0000000..08f2e29 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygmenuw-10.dll.sha1
@@ -0,0 +1 @@ +9e792b1c8fd0fdf992a1f06c361123ad1833f59d \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygming-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygming-1.dll.sha1 new file mode 100644 index 0000000..2d3c80a --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygming-1.dll.sha1
@@ -0,0 +1 @@ +3f20881c17b0d87a150e148b432c889ffa596b74 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygmp-3.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygmp-3.dll.sha1 new file mode 100644 index 0000000..00572bf --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygmp-3.dll.sha1
@@ -0,0 +1 @@ +94ea4af89faadd221223b25fe472356bbc8c4064 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygncurses++-10.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygncurses++-10.dll.sha1 new file mode 100644 index 0000000..687cac40 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygncurses++-10.dll.sha1
@@ -0,0 +1 @@ +21a8fcef8c6d66769ea8c019294e27c959135df0 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygncurses++w-10.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygncurses++w-10.dll.sha1 new file mode 100644 index 0000000..51b5fac5 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygncurses++w-10.dll.sha1
@@ -0,0 +1 @@ +fb5fea774f9e78f7ddc29a516e58f7afc45a113e \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygncurses-10.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygncurses-10.dll.sha1 new file mode 100644 index 0000000..b5eba51d --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygncurses-10.dll.sha1
@@ -0,0 +1 @@ +5bc703d14e864e9befd0fd5f44272592d050475a \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygncursesw-10.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygncursesw-10.dll.sha1 new file mode 100644 index 0000000..57087fd --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygncursesw-10.dll.sha1
@@ -0,0 +1 @@ +78b1afe0c9041cebdd4ed1e56d2bf4c8fbecd921 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpanel-10.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpanel-10.dll.sha1 new file mode 100644 index 0000000..c14fe85b --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpanel-10.dll.sha1
@@ -0,0 +1 @@ +8fb3eeff239da3e9e43dd76775dc0afee518724f \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpanelw-10.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpanelw-10.dll.sha1 new file mode 100644 index 0000000..47452ceec --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpanelw-10.dll.sha1
@@ -0,0 +1 @@ +9ba395e919eb4c8ad559164ad3b71cd3841df8fa \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpango-1.0-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpango-1.0-0.dll.sha1 new file mode 100644 index 0000000..ecb84123 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpango-1.0-0.dll.sha1
@@ -0,0 +1 @@ +4d05a789b8b9e6c05a0e1d315bc7afd7ec015301 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpangocairo-1.0-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpangocairo-1.0-0.dll.sha1 new file mode 100644 index 0000000..b5adeeb --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpangocairo-1.0-0.dll.sha1
@@ -0,0 +1 @@ +b6753663b06ca5751c9299dab1309860dbbc83ee \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpangoft2-1.0-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpangoft2-1.0-0.dll.sha1 new file mode 100644 index 0000000..0e04807 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpangoft2-1.0-0.dll.sha1
@@ -0,0 +1 @@ +4ca6f24c58a45bdbc832e590a16b8aa860b165d7 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpangoxft-1.0-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpangoxft-1.0-0.dll.sha1 new file mode 100644 index 0000000..38c5482 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpangoxft-1.0-0.dll.sha1
@@ -0,0 +1 @@ +41ceee24e37c1e608e4eddac1b7ebc35c6e0697e \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpaper-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpaper-1.dll.sha1 new file mode 100644 index 0000000..be53175b --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpaper-1.dll.sha1
@@ -0,0 +1 @@ +edebc8b3e83ea9c855e6c8a735e2e0ea0f3467e9 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpcre-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpcre-0.dll.sha1 new file mode 100644 index 0000000..b25d188 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpcre-0.dll.sha1
@@ -0,0 +1 @@ +19de1650d85398b71046329d30d47934a9074f03 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpcre-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpcre-1.dll.sha1 new file mode 100644 index 0000000..2412050 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpcre-1.dll.sha1
@@ -0,0 +1 @@ +28e70bf479bfd46136ab90b108c8da025989ec8d \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygperl5_14.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygperl5_14.dll.sha1 new file mode 100644 index 0000000..454fd58 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygperl5_14.dll.sha1
@@ -0,0 +1 @@ +443430fba095f486d8a5aaa143b16f874581449d \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpixman-1-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpixman-1-0.dll.sha1 new file mode 100644 index 0000000..846e6dc --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpixman-1-0.dll.sha1
@@ -0,0 +1 @@ +0460c239ee07cd48ada93d5b255abd4d2450227d \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygplotter-2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygplotter-2.dll.sha1 new file mode 100644 index 0000000..a727a66 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygplotter-2.dll.sha1
@@ -0,0 +1 @@ +633f96712f6f3a1f63ffbb30dc6d54927ecc9625 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpng12.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpng12.dll.sha1 new file mode 100644 index 0000000..f18d7ec --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpng12.dll.sha1
@@ -0,0 +1 @@ +b2885ee84dd9a19ef2ae94e81edc004463faf98c \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpng14-14.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpng14-14.dll.sha1 new file mode 100644 index 0000000..e8a573f --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpng14-14.dll.sha1
@@ -0,0 +1 @@ +9f916788fb5702dd71724b21a28f65f484acc1b5 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpng15-15.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpng15-15.dll.sha1 new file mode 100644 index 0000000..6d16da6 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpng15-15.dll.sha1
@@ -0,0 +1 @@ +f270fc7cc289432d8986525e4086cd593e69f5df \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpopt-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpopt-0.dll.sha1 new file mode 100644 index 0000000..28ba62b --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpopt-0.dll.sha1
@@ -0,0 +1 @@ +f0dd911bd052ac86b77ac416423a91de881374a9 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygpstoedit-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygpstoedit-0.dll.sha1 new file mode 100644 index 0000000..9ccc62ac1 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygpstoedit-0.dll.sha1
@@ -0,0 +1 @@ +8769e9cade95b51bf031921dbf538af7b7ed9616 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygreadline7.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygreadline7.dll.sha1 new file mode 100644 index 0000000..af803366 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygreadline7.dll.sha1
@@ -0,0 +1 @@ +16ba39c158758803af249e2ba1f82ac41fc4c8e8 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygrsvg-2-2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygrsvg-2-2.dll.sha1 new file mode 100644 index 0000000..075efdee --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygrsvg-2-2.dll.sha1
@@ -0,0 +1 @@ +f31b442d60a6254df74fb1c50eecc7764da70497 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygsigsegv-2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygsigsegv-2.dll.sha1 new file mode 100644 index 0000000..2b31322 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygsigsegv-2.dll.sha1
@@ -0,0 +1 @@ +de1a8754327d24d9691c0da1f85ab97e305bdf39 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygsqlite3-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygsqlite3-0.dll.sha1 new file mode 100644 index 0000000..4f1d359 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygsqlite3-0.dll.sha1
@@ -0,0 +1 @@ +ee3488768cc77446bc3314547e1a7f5b442c5df4 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygssl-0.9.8.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygssl-0.9.8.dll.sha1 new file mode 100644 index 0000000..d1c0bd29 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygssl-0.9.8.dll.sha1
@@ -0,0 +1 @@ +33d0635a7480df65371ab93e5cf281570b50fae5 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygssl-1.0.0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygssl-1.0.0.dll.sha1 new file mode 100644 index 0000000..119faf16 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygssl-1.0.0.dll.sha1
@@ -0,0 +1 @@ +24abaccaa15508bb26a87e8480d8cc9bb3fdaece \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygssp-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygssp-0.dll.sha1 new file mode 100644 index 0000000..71213ae3 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygssp-0.dll.sha1
@@ -0,0 +1 @@ +f093531a544f830d9577220bb3a1bf5bd8df2ec2 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygstdc++-6.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygstdc++-6.dll.sha1 new file mode 100644 index 0000000..24307b44 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygstdc++-6.dll.sha1
@@ -0,0 +1 @@ +e6b44b19242a011df419b09b64c46597d4378b90 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygthai-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygthai-0.dll.sha1 new file mode 100644 index 0000000..5b49fd1 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygthai-0.dll.sha1
@@ -0,0 +1 @@ +f11ff45f289b8d36d624d4d53b51859986627675 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygtic-10.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygtic-10.dll.sha1 new file mode 100644 index 0000000..89792cb7 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygtic-10.dll.sha1
@@ -0,0 +1 @@ +7b16da6042a554d4fdd7909b6093d192ab9a2aa3 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygticw-10.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygticw-10.dll.sha1 new file mode 100644 index 0000000..94115f2 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygticw-10.dll.sha1
@@ -0,0 +1 @@ +61017a0d8a09fec100c631b2b40bd6d935954769 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygtiff-5.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygtiff-5.dll.sha1 new file mode 100644 index 0000000..f718575 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygtiff-5.dll.sha1
@@ -0,0 +1 @@ +7b7dcf0a48a1f2da4baa5fbef95160bde900bd53 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygtiffxx-5.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygtiffxx-5.dll.sha1 new file mode 100644 index 0000000..ceace63d --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygtiffxx-5.dll.sha1
@@ -0,0 +1 @@ +7587f424284e82e775d99ea05fe0394bd7fca030 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cyguuid-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cyguuid-1.dll.sha1 new file mode 100644 index 0000000..763a579 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cyguuid-1.dll.sha1
@@ -0,0 +1 @@ +b418145c0635c4d9c3d46d8a0334fed16fa41b07 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygwin1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygwin1.dll.sha1 new file mode 100644 index 0000000..85adb7c2 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygwin1.dll.sha1
@@ -0,0 +1 @@ +2124fabeb6adc54fe7d24f6055847a5d7a87b369 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygxcb-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygxcb-1.dll.sha1 new file mode 100644 index 0000000..0708117 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygxcb-1.dll.sha1
@@ -0,0 +1 @@ +17d2046d7d7720f9938c1de6ed805aaff1a6481c \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygxcb-render-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygxcb-render-0.dll.sha1 new file mode 100644 index 0000000..590881f7 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygxcb-render-0.dll.sha1
@@ -0,0 +1 @@ +b482081ef69175e97807af097caa2fb13f68d87b \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygxcb-shm-0.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygxcb-shm-0.dll.sha1 new file mode 100644 index 0000000..72ca105 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygxcb-shm-0.dll.sha1
@@ -0,0 +1 @@ +acdb0328ec4b29efef9da66acb2b78259acdf4a7 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygxml2-2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygxml2-2.dll.sha1 new file mode 100644 index 0000000..8a852d8a --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygxml2-2.dll.sha1
@@ -0,0 +1 @@ +d5b32c9640c210b211c1247aa1d0c8e09f638c2f \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/cygz.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/cygz.dll.sha1 new file mode 100644 index 0000000..8adc962 --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/cygz.dll.sha1
@@ -0,0 +1 @@ +c9fb7d74bc0c53085bae99a5f39310984bb0fd06 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/win/ffmpeg.exe.sha1 b/chrome/test/data/webrtc/resources/tools/win/ffmpeg.exe.sha1 new file mode 100644 index 0000000..872aaee --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/ffmpeg.exe.sha1
@@ -0,0 +1 @@ +e525fa4ed35e292567e756d8455310d7a2db2389 \ No newline at end of file
diff --git a/chrome/test/data/webrtc/resources/tools/libgomp-1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/libgomp-1.dll.sha1 similarity index 100% rename from chrome/test/data/webrtc/resources/tools/libgomp-1.dll.sha1 rename to chrome/test/data/webrtc/resources/tools/win/libgomp-1.dll.sha1
diff --git a/chrome/test/data/webrtc/resources/tools/pesq.exe.sha1 b/chrome/test/data/webrtc/resources/tools/win/pesq.exe.sha1 similarity index 100% rename from chrome/test/data/webrtc/resources/tools/pesq.exe.sha1 rename to chrome/test/data/webrtc/resources/tools/win/pesq.exe.sha1
diff --git a/chrome/test/data/webrtc/resources/tools/pthreadgc2.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/pthreadgc2.dll.sha1 similarity index 100% rename from chrome/test/data/webrtc/resources/tools/pthreadgc2.dll.sha1 rename to chrome/test/data/webrtc/resources/tools/win/pthreadgc2.dll.sha1
diff --git a/chrome/test/data/webrtc/resources/tools/sox.exe.sha1 b/chrome/test/data/webrtc/resources/tools/win/sox.exe.sha1 similarity index 100% rename from chrome/test/data/webrtc/resources/tools/sox.exe.sha1 rename to chrome/test/data/webrtc/resources/tools/win/sox.exe.sha1
diff --git a/chrome/test/data/webrtc/resources/tools/zlib1.dll.sha1 b/chrome/test/data/webrtc/resources/tools/win/zlib1.dll.sha1 similarity index 100% rename from chrome/test/data/webrtc/resources/tools/zlib1.dll.sha1 rename to chrome/test/data/webrtc/resources/tools/win/zlib1.dll.sha1
diff --git a/chrome/test/data/webrtc/resources/tools/win/zxing.exe.sha1 b/chrome/test/data/webrtc/resources/tools/win/zxing.exe.sha1 new file mode 100644 index 0000000..0e5290f --- /dev/null +++ b/chrome/test/data/webrtc/resources/tools/win/zxing.exe.sha1
@@ -0,0 +1 @@ +86ca3148778079665ad5b9459311d343a1865943 \ No newline at end of file
diff --git a/chrome/test/remoting/remote_desktop_browsertest.cc b/chrome/test/remoting/remote_desktop_browsertest.cc index 3f7f575..5e76bd24 100644 --- a/chrome/test/remoting/remote_desktop_browsertest.cc +++ b/chrome/test/remoting/remote_desktop_browsertest.cc
@@ -387,7 +387,7 @@ ASSERT_TRUE(RemoteDesktopBrowserTest::IsSessionConnected()); - ExecuteScript("remoting.disconnect();"); + ExecuteScript("remoting.app.disconnect();"); EXPECT_TRUE(HtmlElementVisible("client-dialog")); EXPECT_TRUE(HtmlElementVisible("client-reconnect-button")); @@ -557,13 +557,13 @@ // Verify that the local host is online. ASSERT_TRUE(ExecuteScriptAndExtractBool( - "remoting.hostList.localHost_.hostName && " - "remoting.hostList.localHost_.hostId && " - "remoting.hostList.localHost_.status && " - "remoting.hostList.localHost_.status == 'ONLINE'")); + "remoting.hostList.localHostSection_.host_.hostName && " + "remoting.hostList.localHostSection_.host_.hostId && " + "remoting.hostList.localHostSection_.host_.status && " + "remoting.hostList.localHostSection_.host_.status == 'ONLINE'")); // Connect. - ClickOnControl("this-host-connect"); + ClickOnControl("local-host-connect-button"); // Enter the pin # passed in from the command line. EnterPin(me2me_pin(), remember_pin); @@ -823,7 +823,8 @@ bool RemoteDesktopBrowserTest::IsLocalHostReady() { // TODO(weitaosu): Instead of polling, can we register a callback to // remoting.hostList.setLocalHost_? - return ExecuteScriptAndExtractBool("remoting.hostList.localHost_ != null"); + return ExecuteScriptAndExtractBool( + "remoting.hostList.localHostSection_.host_ != null"); } bool RemoteDesktopBrowserTest::IsHostListReady() {
diff --git a/chrome/utility/importer/firefox_importer.cc b/chrome/utility/importer/firefox_importer.cc index 8e4aa72..97c530a 100644 --- a/chrome/utility/importer/firefox_importer.cc +++ b/chrome/utility/importer/firefox_importer.cc
@@ -538,9 +538,9 @@ // file exists only if the user has set keywords for search engines. base::FilePath search_metadata_json_file = source_path_.AppendASCII("search-metadata.json"); - JSONFileValueSerializer metadata_serializer(search_metadata_json_file); + JSONFileValueDeserializer metadata_deserializer(search_metadata_json_file); scoped_ptr<base::Value> metadata_root( - metadata_serializer.Deserialize(NULL, NULL)); + metadata_deserializer.Deserialize(NULL, NULL)); const base::DictionaryValue* search_metadata_root = NULL; if (metadata_root) metadata_root->GetAsDictionary(&search_metadata_root); @@ -550,8 +550,8 @@ if (!base::PathExists(search_json_file)) return; - JSONFileValueSerializer serializer(search_json_file); - scoped_ptr<base::Value> root(serializer.Deserialize(NULL, NULL)); + JSONFileValueDeserializer deserializer(search_json_file); + scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, NULL)); const base::DictionaryValue* search_root = NULL; if (!root || !root->GetAsDictionary(&search_root)) return;
diff --git a/chrome_elf/elf_imports_unittest.cc b/chrome_elf/elf_imports_unittest.cc index 136912b..dda1bb12 100644 --- a/chrome_elf/elf_imports_unittest.cc +++ b/chrome_elf/elf_imports_unittest.cc
@@ -66,6 +66,9 @@ #if defined(SYZYASAN) "syzyasan_rtl.dll", #endif +#if defined(ADDRESS_SANITIZER) && defined(COMPONENT_BUILD) + "clang_rt.asan_dynamic-i386.dll", +#endif "ADVAPI32.dll" }; @@ -76,7 +79,7 @@ if (MatchPattern(*it, kValidFilePatterns[i])) match = true; } - ASSERT_TRUE(match) << "Illegal import in chrome_elf.dll."; + ASSERT_TRUE(match) << "Illegal import in chrome_elf.dll: " << *it; } }
diff --git a/chromecast/base/metrics/cast_metrics_helper.cc b/chromecast/base/metrics/cast_metrics_helper.cc index 0e0c889..85cdfe8 100644 --- a/chromecast/base/metrics/cast_metrics_helper.cc +++ b/chromecast/base/metrics/cast_metrics_helper.cc
@@ -149,6 +149,8 @@ void CastMetricsHelper::LogTimeToFirstPaint() { MAKE_SURE_THREAD(LogTimeToFirstPaint); + if (app_id_.empty()) + return; base::TimeDelta launch_time = base::TimeTicks::Now() - app_start_time_; const std::string uma_name(GetMetricsNameWithAppName("Startup", "TimeToFirstPaint"));
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWindowAndroid.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWindowAndroid.java index c2cf186..ee7aa3c 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWindowAndroid.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWindowAndroid.java
@@ -20,10 +20,10 @@ import org.chromium.content.browser.ContentView; import org.chromium.content.browser.ContentViewCore; import org.chromium.content.browser.ContentViewRenderView; -import org.chromium.content.browser.WebContentsObserver; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.ui.base.WindowAndroid; /**
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index 2ccdcd3d..56a82502 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc
@@ -9,6 +9,7 @@ #include "base/base_switches.h" #include "base/command_line.h" #include "base/files/scoped_file.h" +#include "base/i18n/icu_util.h" #include "base/i18n/rtl.h" #include "base/path_service.h" #include "chromecast/browser/cast_browser_context.h" @@ -273,17 +274,16 @@ int child_process_id, content::FileDescriptorInfo* mappings) { #if defined(OS_ANDROID) - int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; - base::FilePath pak_file; - CHECK(PathService::Get(FILE_CAST_PAK, &pak_file)); - base::File pak_with_flags(pak_file, flags); - if (!pak_with_flags.IsValid()) { + const int flags_open_read = base::File::FLAG_OPEN | base::File::FLAG_READ; + base::FilePath pak_file_path; + CHECK(PathService::Get(FILE_CAST_PAK, &pak_file_path)); + base::File pak_file(pak_file_path, flags_open_read); + if (!pak_file.IsValid()) { NOTREACHED() << "Failed to open file when creating renderer process: " << "cast_shell.pak"; } - mappings->Transfer( - kAndroidPakDescriptor, - base::ScopedFD(pak_with_flags.TakePlatformFile())); + mappings->Transfer(kAndroidPakDescriptor, + base::ScopedFD(pak_file.TakePlatformFile())); if (breakpad::IsCrashReporterEnabled()) { base::File minidump_file( @@ -297,6 +297,16 @@ base::ScopedFD(minidump_file.TakePlatformFile())); } } + + base::FilePath app_data_path; + CHECK(PathService::Get(base::DIR_ANDROID_APP_DATA, &app_data_path)); + base::FilePath icudata_path = + app_data_path.AppendASCII(base::i18n::kIcuDataFileName); + base::File icudata_file(icudata_path, flags_open_read); + if (!icudata_file.IsValid()) + NOTREACHED() << "Failed to open ICU file when creating renderer process"; + mappings->Transfer(kAndroidICUDataDescriptor, + base::ScopedFD(icudata_file.TakePlatformFile())); #else int crash_signal_fd = GetCrashSignalFD(command_line); if (crash_signal_fd >= 0) {
diff --git a/chromecast/browser/url_request_context_factory.cc b/chromecast/browser/url_request_context_factory.cc index 892fd003..4a25eb6 100644 --- a/chromecast/browser/url_request_context_factory.cc +++ b/chromecast/browser/url_request_context_factory.cc
@@ -19,7 +19,6 @@ #include "net/cookies/cookie_store.h" #include "net/dns/host_resolver.h" #include "net/http/http_auth_handler_factory.h" -#include "net/http/http_cache.h" #include "net/http/http_network_layer.h" #include "net/http/http_server_properties_impl.h" #include "net/http/http_stream_factory.h" @@ -355,9 +354,6 @@ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); InitializeSystemContextDependencies(); - net::HttpCache::BackendFactory* main_backend = - net::HttpCache::DefaultBackend::InMemory(16 * 1024 * 1024); - bool ignore_certificate_errors = false; base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); if (cmd_line->HasSwitch(switches::kIgnoreCertificateErrors)) { @@ -367,7 +363,8 @@ PopulateNetworkSessionParams(ignore_certificate_errors, &network_session_params); InitializeMainContextDependencies( - new net::HttpCache(network_session_params, main_backend), + new net::HttpNetworkLayer( + new net::HttpNetworkSession(network_session_params)), protocol_handlers, request_interceptors.Pass());
diff --git a/chromecast/chromecast.gyp b/chromecast/chromecast.gyp index 82f4b86..6543a00 100644 --- a/chromecast/chromecast.gyp +++ b/chromecast/chromecast.gyp
@@ -174,7 +174,7 @@ '../components/components.gyp:metrics_net', '../components/components.gyp:metrics_profiler', '../content/content.gyp:content', - '../content/content.gyp:content_app_browser', + '../content/content.gyp:content_app_both', '../skia/skia.gyp:skia', '../third_party/WebKit/public/blink.gyp:blink', '../third_party/widevine/cdm/widevine_cdm.gyp:widevine_cdm_version_h', @@ -227,6 +227,9 @@ 'common/cast_resource_delegate.h', 'common/chromecast_switches.cc', 'common/chromecast_switches.h', + 'common/media/cast_messages.h', + 'common/media/cast_message_generator.cc', + 'common/media/cast_message_generator.h', 'common/platform_client_auth.h', 'common/pref_names.cc', 'common/pref_names.h', @@ -238,6 +241,8 @@ 'renderer/cast_render_process_observer.h', 'renderer/key_systems_cast.cc', 'renderer/key_systems_cast.h', + 'renderer/media/capabilities_message_filter.cc', + 'renderer/media/capabilities_message_filter.h', ], 'conditions': [ ['chromecast_branding=="Chrome"', { @@ -353,7 +358,6 @@ '../breakpad/breakpad.gyp:breakpad_client', '../components/components.gyp:breakpad_host', '../components/components.gyp:crash_component', - '../content/content.gyp:content_app_browser', '../content/content.gyp:content', '../skia/skia.gyp:skia', '../ui/gfx/gfx.gyp:gfx', @@ -496,8 +500,8 @@ 'common/media/shared_memory_chunk.h', 'renderer/media/audio_pipeline_proxy.cc', 'renderer/media/audio_pipeline_proxy.h', - 'renderer/media/cma_media_renderer_factory.cc', - 'renderer/media/cma_media_renderer_factory.h', + 'renderer/media/chromecast_media_renderer_factory.cc', + 'renderer/media/chromecast_media_renderer_factory.h', 'renderer/media/cma_message_filter_proxy.cc', 'renderer/media/cma_message_filter_proxy.h', 'renderer/media/media_channel_proxy.cc',
diff --git a/chromecast/common/chromecast_switches.cc b/chromecast/common/chromecast_switches.cc index aca640d..fe16627 100644 --- a/chromecast/common/chromecast_switches.cc +++ b/chromecast/common/chromecast_switches.cc
@@ -9,6 +9,9 @@ // Enable the CMA media pipeline. const char kEnableCmaMediaPipeline[] = "enable-cma-media-pipeline"; +// The bitmask of codecs (media_caps.h) supported by the current HDMI sink. +const char kHdmiSinkSupportedCodecs[] = "hdmi-sink-supported-codecs"; + #if defined(OS_ANDROID) // Enable file accesses for debug. const char kEnableLocalFileAccesses[] = "enable-local-file-accesses";
diff --git a/chromecast/common/chromecast_switches.h b/chromecast/common/chromecast_switches.h index 4bb74902..5840d4501 100644 --- a/chromecast/common/chromecast_switches.h +++ b/chromecast/common/chromecast_switches.h
@@ -9,7 +9,9 @@ namespace switches { +// Media switches extern const char kEnableCmaMediaPipeline[]; +extern const char kHdmiSinkSupportedCodecs[]; #if defined(OS_ANDROID) // Content-implementation switches
diff --git a/chromecast/common/media/cast_message_generator.cc b/chromecast/common/media/cast_message_generator.cc new file mode 100644 index 0000000..ee6c73e2 --- /dev/null +++ b/chromecast/common/media/cast_message_generator.cc
@@ -0,0 +1,15 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Get basic type definitions. +#define IPC_MESSAGE_IMPL +#include "chromecast/common/media/cast_message_generator.h" + +// Generate constructors. +#include "ipc/struct_constructor_macros.h" +#include "chromecast/common/media/cast_message_generator.h" + +// Generate destructors. +#include "ipc/struct_destructor_macros.h" +#include "chromecast/common/media/cast_message_generator.h"
diff --git a/chromecast/common/media/cast_message_generator.h b/chromecast/common/media/cast_message_generator.h new file mode 100644 index 0000000..ac6c0041 --- /dev/null +++ b/chromecast/common/media/cast_message_generator.h
@@ -0,0 +1,8 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Multiply-included file, hence no include guard. + +#include "chromecast/common/media/cast_messages.h" +
diff --git a/chromecast/common/media/cast_messages.h b/chromecast/common/media/cast_messages.h new file mode 100644 index 0000000..3d9cc2a8 --- /dev/null +++ b/chromecast/common/media/cast_messages.h
@@ -0,0 +1,17 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// IPC messages related to media on Chromecast. +// Multiply-included message file, hence no include guard. + +#include "ipc/ipc_message_macros.h" + +#undef IPC_MESSAGE_EXPORT +#define IPC_MESSAGE_EXPORT +#define IPC_MESSAGE_START CastMediaMsgStart + +// Messages sent from the browser to the renderer process. + +IPC_MESSAGE_CONTROL1(CmaMsg_UpdateSupportedHdmiSinkCodecs, + int /* Codec support, bitmask of media_caps.h values */)
diff --git a/chromecast/media/base/media_caps.cc b/chromecast/media/base/media_caps.cc new file mode 100644 index 0000000..2924882 --- /dev/null +++ b/chromecast/media/base/media_caps.cc
@@ -0,0 +1,38 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/media/base/media_caps.h" + +namespace media { + +namespace { +int g_hdmi_codecs = 0; +} // namespace + +void SetHdmiSinkCodecs(int codecs_mask) { + g_hdmi_codecs = codecs_mask; +} + +bool HdmiSinkSupportsAC3() { + return g_hdmi_codecs & HdmiSinkCodec::kSinkCodecAc3; +} + +bool HdmiSinkSupportsDTS() { + return g_hdmi_codecs & HdmiSinkCodec::kSinkCodecDts; +} + +bool HdmiSinkSupportsDTSHD() { + return g_hdmi_codecs & HdmiSinkCodec::kSinkCodecDtsHd; +} + +bool HdmiSinkSupportsEAC3() { + return g_hdmi_codecs & HdmiSinkCodec::kSinkCodecEac3; +} + +bool HdmiSinkSupportsPcmSurroundSound() { + return g_hdmi_codecs & HdmiSinkCodec::kSinkCodecPcmSurroundSound; +} + +} // namespace media +
diff --git a/chromecast/media/base/media_caps.h b/chromecast/media/base/media_caps.h index 8e13798..8ae2c7b 100644 --- a/chromecast/media/base/media_caps.h +++ b/chromecast/media/base/media_caps.h
@@ -7,6 +7,18 @@ namespace media { +enum HdmiSinkCodec { + kSinkCodecAc3 = 1, + kSinkCodecDts = 1 << 1, + kSinkCodecDtsHd = 1 << 2, + kSinkCodecEac3 = 1 << 3, + kSinkCodecPcmSurroundSound = 1 << 4, +}; + +// Records the known supported codecs for the current HDMI sink, as a bit mask +// of HdmiSinkCodec values. +void SetHdmiSinkCodecs(int codecs_mask); + bool HdmiSinkSupportsAC3(); bool HdmiSinkSupportsDTS(); bool HdmiSinkSupportsDTSHD();
diff --git a/chromecast/media/base/switching_media_renderer.cc b/chromecast/media/base/switching_media_renderer.cc new file mode 100644 index 0000000..ec8b1521 --- /dev/null +++ b/chromecast/media/base/switching_media_renderer.cc
@@ -0,0 +1,103 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/media/base/switching_media_renderer.h" + +#include "base/logging.h" +#include "media/base/audio_decoder_config.h" +#include "media/base/demuxer_stream.h" +#include "media/base/demuxer_stream_provider.h" + +namespace chromecast { +namespace media { + +SwitchingMediaRenderer::SwitchingMediaRenderer( + scoped_ptr<::media::Renderer> default_renderer, + scoped_ptr<::media::Renderer> cma_renderer) + : default_renderer_(default_renderer.Pass()), + cma_renderer_(cma_renderer.Pass()) { + DCHECK(default_renderer_); + DCHECK(cma_renderer_); +} + +SwitchingMediaRenderer::~SwitchingMediaRenderer() { +} + +void SwitchingMediaRenderer::Initialize( + ::media::DemuxerStreamProvider* demuxer_stream_provider, + const ::media::PipelineStatusCB& init_cb, + const ::media::StatisticsCB& statistics_cb, + const ::media::BufferingStateCB& buffering_state_cb, + const ::media::Renderer::PaintCB& paint_cb, + const base::Closure& ended_cb, + const ::media::PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) { + // At this point the DemuxerStreamProvider should be fully initialized, so we + // have enough information to decide which renderer to use. + demuxer_stream_provider_ = demuxer_stream_provider; + DCHECK(demuxer_stream_provider_); + ::media::DemuxerStream* audio_stream = + demuxer_stream_provider_->GetStream(::media::DemuxerStream::AUDIO); + ::media::DemuxerStream* video_stream = + demuxer_stream_provider_->GetStream(::media::DemuxerStream::VIDEO); + if (audio_stream && !video_stream && + audio_stream->audio_decoder_config().codec() != ::media::kCodecAAC && + audio_stream->audio_decoder_config().codec() != ::media::kCodecVorbis) { + // We'll use the default Chrome media renderer with software audio decoding + cma_renderer_.reset(); + } else { + // We'll use the CMA-based rendering with hardware decoding + default_renderer_.reset(); + } + + return GetRenderer()->Initialize( + demuxer_stream_provider, init_cb, statistics_cb, buffering_state_cb, + paint_cb, ended_cb, error_cb, waiting_for_decryption_key_cb); +} + +::media::Renderer* SwitchingMediaRenderer::GetRenderer() const { + DCHECK(default_renderer_ || cma_renderer_); + if (cma_renderer_) + return cma_renderer_.get(); + + DCHECK(default_renderer_); + return default_renderer_.get(); +} + +void SwitchingMediaRenderer::SetCdm( + ::media::CdmContext* cdm_context, + const ::media::CdmAttachedCB& cdm_attached_cb) { + GetRenderer()->SetCdm(cdm_context, cdm_attached_cb); +} + +void SwitchingMediaRenderer::Flush(const base::Closure& flush_cb) { + GetRenderer()->Flush(flush_cb); +} + +void SwitchingMediaRenderer::StartPlayingFrom(base::TimeDelta time) { + GetRenderer()->StartPlayingFrom(time); +} + +void SwitchingMediaRenderer::SetPlaybackRate(float playback_rate) { + GetRenderer()->SetPlaybackRate(playback_rate); +} + +void SwitchingMediaRenderer::SetVolume(float volume) { + GetRenderer()->SetVolume(volume); +} + +base::TimeDelta SwitchingMediaRenderer::GetMediaTime() { + return GetRenderer()->GetMediaTime(); +} + +bool SwitchingMediaRenderer::HasAudio() { + return GetRenderer()->HasAudio(); +} + +bool SwitchingMediaRenderer::HasVideo() { + return GetRenderer()->HasVideo(); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/base/switching_media_renderer.h b/chromecast/media/base/switching_media_renderer.h new file mode 100644 index 0000000..830cef6 --- /dev/null +++ b/chromecast/media/base/switching_media_renderer.h
@@ -0,0 +1,67 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_MEDIA_BASE_SWITCHING_MEDIA_RENDERER_H_ +#define CHROMECAST_MEDIA_BASE_SWITCHING_MEDIA_RENDERER_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "media/base/renderer.h" + +namespace media { +class DemuxerStreamProvider; +} + +namespace chromecast { +namespace media { + +// Chromecast's custom media renderer which is capable of selecting an +// appropriate media renderer at runtime depending on the content. +// We'll look at media types of media streams present in DemuxerStreamProvider +// and will use either CMA-based renderer (for media types that are supported by +// our hardware decoder - H264 and VP8 video, AAC and Vorbis audio) or the +// default Chrome media renderer (this will allow us to support audio codecs +// like FLAC and Opus, which are decoded in software). +class SwitchingMediaRenderer : public ::media::Renderer { + public: + SwitchingMediaRenderer( + scoped_ptr<::media::Renderer> default_renderer, + scoped_ptr<::media::Renderer> cma_renderer); + ~SwitchingMediaRenderer() override; + + // ::media::Renderer implementation: + void Initialize( + ::media::DemuxerStreamProvider* demuxer_stream_provider, + const ::media::PipelineStatusCB& init_cb, + const ::media::StatisticsCB& statistics_cb, + const ::media::BufferingStateCB& buffering_state_cb, + const ::media::Renderer::PaintCB& paint_cb, + const base::Closure& ended_cb, + const ::media::PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) override; + void SetCdm(::media::CdmContext* cdm_context, + const ::media::CdmAttachedCB& cdm_attached_cb) override; + void Flush(const base::Closure& flush_cb) override; + void StartPlayingFrom(base::TimeDelta time) override; + void SetPlaybackRate(float playback_rate) override; + void SetVolume(float volume) override; + base::TimeDelta GetMediaTime() override; + bool HasAudio() override; + bool HasVideo() override; + + private: + // Returns the pointer to the actual renderer being used + ::media::Renderer* GetRenderer() const; + + ::media::DemuxerStreamProvider* demuxer_stream_provider_; + scoped_ptr<::media::Renderer> default_renderer_; + scoped_ptr<::media::Renderer> cma_renderer_; + + DISALLOW_COPY_AND_ASSIGN(SwitchingMediaRenderer); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_BASE_SWITCHING_MEDIA_RENDERER_H_
diff --git a/chromecast/media/cma/filters/cma_renderer.cc b/chromecast/media/cma/filters/cma_renderer.cc index 799dd61..a8a46f5 100644 --- a/chromecast/media/cma/filters/cma_renderer.cc +++ b/chromecast/media/cma/filters/cma_renderer.cc
@@ -75,7 +75,8 @@ const ::media::BufferingStateCB& buffering_state_cb, const PaintCB& paint_cb, const base::Closure& ended_cb, - const ::media::PipelineStatusCB& error_cb) { + const ::media::PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) { CMALOG(kLogControl) << __FUNCTION__; DCHECK(thread_checker_.CalledOnValidThread()); DCHECK_EQ(state_, kUninitialized) << state_; @@ -84,6 +85,7 @@ DCHECK(!ended_cb.is_null()); DCHECK(!error_cb.is_null()); DCHECK(!buffering_state_cb.is_null()); + DCHECK(!waiting_for_decryption_key_cb.is_null()); DCHECK(demuxer_stream_provider->GetStream(::media::DemuxerStream::AUDIO) || demuxer_stream_provider->GetStream(::media::DemuxerStream::VIDEO)); @@ -95,6 +97,8 @@ paint_cb_ = paint_cb; ended_cb_ = ended_cb; error_cb_ = error_cb; + // TODO(erickung): wire up waiting_for_decryption_key_cb. + waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; MediaPipelineClient media_pipeline_client; media_pipeline_client.error_cb = error_cb_;
diff --git a/chromecast/media/cma/filters/cma_renderer.h b/chromecast/media/cma/filters/cma_renderer.h index 33fc2b1..62efd7c 100644 --- a/chromecast/media/cma/filters/cma_renderer.h +++ b/chromecast/media/cma/filters/cma_renderer.h
@@ -45,7 +45,8 @@ const ::media::BufferingStateCB& buffering_state_cb, const PaintCB& paint_cb, const base::Closure& ended_cb, - const ::media::PipelineStatusCB& error_cb) override; + const ::media::PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) override; void Flush(const base::Closure& flush_cb) override; void StartPlayingFrom(base::TimeDelta time) override; void SetPlaybackRate(float playback_rate) override; @@ -108,6 +109,7 @@ ::media::PipelineStatusCB error_cb_; ::media::BufferingStateCB buffering_state_cb_; base::Closure flush_cb_; + base::Closure waiting_for_decryption_key_cb_; // Renderer state. // Used mostly for checking that transitions are correct.
diff --git a/chromecast/media/cma/pipeline/audio_pipeline_impl.cc b/chromecast/media/cma/pipeline/audio_pipeline_impl.cc index 404031fa..a524888 100644 --- a/chromecast/media/cma/pipeline/audio_pipeline_impl.cc +++ b/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
@@ -22,9 +22,9 @@ AudioPipelineImpl::AudioPipelineImpl(AudioPipelineDevice* audio_device) : audio_device_(audio_device), weak_factory_(this) { - av_pipeline_impl_.reset(new AvPipelineImpl( + av_pipeline_impl_ = new AvPipelineImpl( audio_device_, - base::Bind(&AudioPipelineImpl::OnUpdateConfig, base::Unretained(this)))); + base::Bind(&AudioPipelineImpl::OnUpdateConfig, base::Unretained(this))); weak_this_ = weak_factory_.GetWeakPtr(); }
diff --git a/chromecast/media/cma/pipeline/audio_pipeline_impl.h b/chromecast/media/cma/pipeline/audio_pipeline_impl.h index 7d2e63a..7451acf 100644 --- a/chromecast/media/cma/pipeline/audio_pipeline_impl.h +++ b/chromecast/media/cma/pipeline/audio_pipeline_impl.h
@@ -62,7 +62,7 @@ AudioPipelineDevice* audio_device_; - scoped_ptr<AvPipelineImpl> av_pipeline_impl_; + scoped_refptr<AvPipelineImpl> av_pipeline_impl_; AvPipelineClient audio_client_; ::media::PipelineStatistics previous_stats_;
diff --git a/chromecast/media/cma/pipeline/av_pipeline_impl.cc b/chromecast/media/cma/pipeline/av_pipeline_impl.cc index 2e2da54f..6c415c7 100644 --- a/chromecast/media/cma/pipeline/av_pipeline_impl.cc +++ b/chromecast/media/cma/pipeline/av_pipeline_impl.cc
@@ -45,10 +45,8 @@ enable_time_update_(false), pending_time_update_task_(false), media_keys_(NULL), - media_keys_callback_id_(kNoCallbackId), - weak_factory_(this) { + media_keys_callback_id_(kNoCallbackId) { DCHECK(media_component_device); - weak_this_ = weak_factory_.GetWeakPtr(); thread_checker_.DetachFromThread(); } @@ -58,8 +56,11 @@ DCHECK(thread_checker_.CalledOnValidThread()); media_component_device_->SetClient(MediaComponentDevice::Client()); - if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) - media_keys_->UnregisterPlayer(media_keys_callback_id_); + { + base::AutoLock lock(media_keys_lock_); + if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) + media_keys_->UnregisterPlayer(media_keys_callback_id_); + } } void AvPipelineImpl::TransitionToState(State state) { @@ -80,7 +81,7 @@ frame_provider.Pass(), max_buffer_size, max_frame_size, - base::Bind(&AvPipelineImpl::OnFrameBuffered, weak_this_))); + base::Bind(&AvPipelineImpl::OnFrameBuffered, this))); } void AvPipelineImpl::SetClient(const AvPipelineClient& client) { @@ -94,7 +95,7 @@ DCHECK_EQ(state_, kUninitialized); MediaComponentDevice::Client client; - client.eos_cb = base::Bind(&AvPipelineImpl::OnEos, weak_this_); + client.eos_cb = base::Bind(&AvPipelineImpl::OnEos, this); media_component_device_->SetClient(client); if (!media_component_device_->SetState(MediaComponentDevice::kStateIdle)) return false; @@ -128,7 +129,7 @@ enable_feeding_ = true; base::MessageLoopProxy::current()->PostTask( FROM_HERE, - base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); + base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, this)); return true; } @@ -183,15 +184,21 @@ DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(media_keys); - if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) - media_keys_->UnregisterPlayer(media_keys_callback_id_); + { + base::AutoLock lock(media_keys_lock_); + if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) + media_keys_->UnregisterPlayer(media_keys_callback_id_); - media_keys_ = media_keys; - media_keys_callback_id_ = media_keys_->RegisterPlayer( - ::media::BindToCurrentLoop( - base::Bind(&AvPipelineImpl::OnCdmStateChanged, weak_this_)), - ::media::BindToCurrentLoop( - base::Bind(&AvPipelineImpl::OnCdmDestroyed, weak_this_))); + media_keys_ = media_keys; + media_keys_callback_id_ = media_keys_->RegisterPlayer( + ::media::BindToCurrentLoop( + base::Bind(&AvPipelineImpl::OnCdmStateChanged, this)), + // Note: this callback gets invoked in ~BrowserCdmCast. Posting + // OnCdmDestroyed to the media thread results in a race condition + // with media_keys_ accesses. This callback must run synchronously, + // otherwise media_keys_ access might occur after it is deleted. + base::Bind(&AvPipelineImpl::OnCdmDestroyed, this)); + } } void AvPipelineImpl::OnEos() { @@ -214,7 +221,7 @@ pending_read_ = true; frame_provider_->Read( - base::Bind(&AvPipelineImpl::OnNewFrame, weak_this_)); + base::Bind(&AvPipelineImpl::OnNewFrame, this)); } void AvPipelineImpl::OnNewFrame( @@ -232,7 +239,7 @@ base::MessageLoopProxy::current()->PostTask( FROM_HERE, - base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); + base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, this)); } void AvPipelineImpl::ProcessPendingBuffer() { @@ -243,7 +250,7 @@ if (!pending_buffer_.get() && !pending_read_) { base::MessageLoopProxy::current()->PostTask( FROM_HERE, - base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); + base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, this)); return; } @@ -262,12 +269,15 @@ // Verify that CDM has the key ID. // Should not send the frame if the key ID is not available yet. std::string key_id(pending_buffer_->decrypt_config()->key_id()); - if (!media_keys_) { - CMALOG(kLogControl) << "No CDM for frame: pts=" - << pending_buffer_->timestamp().InMilliseconds(); - return; + { + base::AutoLock lock(media_keys_lock_); + if (!media_keys_) { + CMALOG(kLogControl) << "No CDM for frame: pts=" + << pending_buffer_->timestamp().InMilliseconds(); + return; + } + decrypt_context = media_keys_->GetDecryptContext(key_id); } - decrypt_context = media_keys_->GetDecryptContext(key_id); if (!decrypt_context.get()) { CMALOG(kLogControl) << "frame(pts=" << pending_buffer_->timestamp().InMilliseconds() @@ -294,7 +304,7 @@ MediaComponentDevice::FrameStatus status = media_component_device_->PushFrame( decrypt_context, pending_buffer_, - base::Bind(&AvPipelineImpl::OnFramePushed, weak_this_)); + base::Bind(&AvPipelineImpl::OnFramePushed, this)); pending_buffer_ = scoped_refptr<DecoderBufferBase>(); pending_push_ = (status == MediaComponentDevice::kFramePending); @@ -313,7 +323,7 @@ } base::MessageLoopProxy::current()->PostTask( FROM_HERE, - base::Bind(&AvPipelineImpl::ProcessPendingBuffer, weak_this_)); + base::Bind(&AvPipelineImpl::ProcessPendingBuffer, this)); } void AvPipelineImpl::OnCdmStateChanged() { @@ -328,7 +338,7 @@ } void AvPipelineImpl::OnCdmDestroyed() { - DCHECK(thread_checker_.CalledOnValidThread()); + base::AutoLock lock(media_keys_lock_); media_keys_ = NULL; }
diff --git a/chromecast/media/cma/pipeline/av_pipeline_impl.h b/chromecast/media/cma/pipeline/av_pipeline_impl.h index 20b3fc4..19b8498c 100644 --- a/chromecast/media/cma/pipeline/av_pipeline_impl.h +++ b/chromecast/media/cma/pipeline/av_pipeline_impl.h
@@ -10,7 +10,7 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" +#include "base/synchronization/lock.h" #include "base/threading/thread_checker.h" #include "chromecast/media/cma/backend/media_component_device.h" #include "chromecast/media/cma/pipeline/av_pipeline_client.h" @@ -29,7 +29,7 @@ class DecoderBufferBase; class MediaComponentDevice; -class AvPipelineImpl { +class AvPipelineImpl : public base::RefCountedThreadSafe<AvPipelineImpl> { public: // Pipeline states. enum State { @@ -48,7 +48,6 @@ AvPipelineImpl( MediaComponentDevice* media_component_device, const UpdateConfigCB& update_config_cb); - ~AvPipelineImpl(); // Setting the frame provider or the client must be done in the // |kUninitialized| state. @@ -78,6 +77,9 @@ void SetCdm(BrowserCdmCast* media_keys); private: + friend class base::RefCountedThreadSafe<AvPipelineImpl>; + ~AvPipelineImpl(); + // Callback invoked when the CDM state has changed in a way that might // impact media playback. void OnCdmStateChange(); @@ -157,12 +159,10 @@ bool pending_time_update_task_; // Decryption keys, if available. + base::Lock media_keys_lock_; BrowserCdmCast* media_keys_; int media_keys_callback_id_; - base::WeakPtr<AvPipelineImpl> weak_this_; - base::WeakPtrFactory<AvPipelineImpl> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(AvPipelineImpl); };
diff --git a/chromecast/media/cma/pipeline/video_pipeline_impl.cc b/chromecast/media/cma/pipeline/video_pipeline_impl.cc index d3ae9be..3a1c619e7 100644 --- a/chromecast/media/cma/pipeline/video_pipeline_impl.cc +++ b/chromecast/media/cma/pipeline/video_pipeline_impl.cc
@@ -23,9 +23,9 @@ : video_device_(video_device), weak_factory_(this) { weak_this_ = weak_factory_.GetWeakPtr(); - av_pipeline_impl_.reset(new AvPipelineImpl( + av_pipeline_impl_ = new AvPipelineImpl( video_device_, - base::Bind(&VideoPipelineImpl::OnUpdateConfig, base::Unretained(this)))); + base::Bind(&VideoPipelineImpl::OnUpdateConfig, base::Unretained(this))); } VideoPipelineImpl::~VideoPipelineImpl() {
diff --git a/chromecast/media/cma/pipeline/video_pipeline_impl.h b/chromecast/media/cma/pipeline/video_pipeline_impl.h index e065ac1..9a57cd5 100644 --- a/chromecast/media/cma/pipeline/video_pipeline_impl.h +++ b/chromecast/media/cma/pipeline/video_pipeline_impl.h
@@ -65,7 +65,7 @@ VideoPipelineDevice* video_device_; - scoped_ptr<AvPipelineImpl> av_pipeline_impl_; + scoped_refptr<AvPipelineImpl> av_pipeline_impl_; VideoPipelineClient video_client_; ::media::PipelineStatistics previous_stats_;
diff --git a/chromecast/media/media.gyp b/chromecast/media/media.gyp index 1051a6b..bc468a6f 100644 --- a/chromecast/media/media.gyp +++ b/chromecast/media/media.gyp
@@ -22,6 +22,10 @@ 'base/decrypt_context_clearkey.h', 'base/key_systems_common.cc', 'base/key_systems_common.h', + 'base/media_caps.cc', + 'base/media_caps.h', + 'base/switching_media_renderer.cc', + 'base/switching_media_renderer.h', ], 'conditions': [ ['chromecast_branding=="Chrome"', {
diff --git a/chromecast/renderer/DEPS b/chromecast/renderer/DEPS index 22bc1dd..1015677 100644 --- a/chromecast/renderer/DEPS +++ b/chromecast/renderer/DEPS
@@ -6,6 +6,7 @@ "+components/network_hints/renderer", "+content/public/renderer", "+media/base", + "+media/renderers", "+third_party/WebKit/public/platform", "+third_party/WebKit/public/web", ]
diff --git a/chromecast/renderer/cast_content_renderer_client.cc b/chromecast/renderer/cast_content_renderer_client.cc index 1bb0930..8934e95 100644 --- a/chromecast/renderer/cast_content_renderer_client.cc +++ b/chromecast/renderer/cast_content_renderer_client.cc
@@ -8,12 +8,14 @@ #include "base/command_line.h" #include "base/memory/memory_pressure_listener.h" +#include "base/strings/string_number_conversions.h" #include "chromecast/common/chromecast_switches.h" #include "chromecast/crash/cast_crash_keys.h" +#include "chromecast/media/base/media_caps.h" #include "chromecast/renderer/cast_media_load_deferrer.h" #include "chromecast/renderer/cast_render_process_observer.h" #include "chromecast/renderer/key_systems_cast.h" -#include "chromecast/renderer/media/cma_media_renderer_factory.h" +#include "chromecast/renderer/media/chromecast_media_renderer_factory.h" #include "components/network_hints/renderer/prescient_networking_dispatcher.h" #include "content/public/common/content_switches.h" #include "content/public/renderer/render_frame.h" @@ -107,6 +109,16 @@ PlatformPollFreemem(); #endif + // Set the initial known codecs mask. + if (command_line->HasSwitch(switches::kHdmiSinkSupportedCodecs)) { + int hdmi_codecs_mask; + if (base::StringToInt(command_line->GetSwitchValueASCII( + switches::kHdmiSinkSupportedCodecs), + &hdmi_codecs_mask)) { + ::media::SetHdmiSinkCodecs(hdmi_codecs_mask); + } + } + cast_observer_.reset( new CastRenderProcessObserver(PlatformGetRendererMessageFilters())); @@ -160,8 +172,8 @@ return nullptr; return scoped_ptr<::media::RendererFactory>( - new chromecast::media::CmaMediaRendererFactory( - render_frame->GetRoutingID())); + new chromecast::media::ChromecastMediaRendererFactory( + media_log, render_frame->GetRoutingID())); } #endif
diff --git a/chromecast/renderer/cast_render_process_observer.cc b/chromecast/renderer/cast_render_process_observer.cc index 316fd616..caba244 100644 --- a/chromecast/renderer/cast_render_process_observer.cc +++ b/chromecast/renderer/cast_render_process_observer.cc
@@ -4,6 +4,7 @@ #include "chromecast/renderer/cast_render_process_observer.h" +#include "chromecast/renderer/media/capabilities_message_filter.h" #include "chromecast/renderer/media/cma_message_filter_proxy.h" #include "content/public/renderer/render_thread.h" @@ -31,6 +32,8 @@ new media::CmaMessageFilterProxy(thread->GetIOMessageLoopProxy()); thread->AddFilter(cma_message_filter_proxy_.get()); #endif // !defined(OS_ANDROID) + capabilities_message_filter_ = new CapabilitiesMessageFilter; + thread->AddFilter(capabilities_message_filter_.get()); for (const auto& filter : platform_message_filters_) { thread->AddFilter(filter.get()); } @@ -41,9 +44,13 @@ #if !defined(OS_ANDROID) if (cma_message_filter_proxy_.get()) { thread->RemoveFilter(cma_message_filter_proxy_.get()); - cma_message_filter_proxy_ = NULL; + cma_message_filter_proxy_ = nullptr; } #endif // !defined(OS_ANDROID) + if (capabilities_message_filter_.get()) { + thread->RemoveFilter(capabilities_message_filter_.get()); + capabilities_message_filter_ = nullptr; + } for (auto& filter : platform_message_filters_) { if (filter.get()) { thread->RemoveFilter(filter.get());
diff --git a/chromecast/renderer/cast_render_process_observer.h b/chromecast/renderer/cast_render_process_observer.h index 0c28b5817..479026c5 100644 --- a/chromecast/renderer/cast_render_process_observer.h +++ b/chromecast/renderer/cast_render_process_observer.h
@@ -16,6 +16,7 @@ } namespace chromecast { +class CapabilitiesMessageFilter; namespace media { class CmaMessageFilterProxy; } @@ -38,6 +39,7 @@ #if !defined(OS_ANDROID) scoped_refptr<media::CmaMessageFilterProxy> cma_message_filter_proxy_; #endif // !defined(OS_ANDROID) + scoped_refptr<CapabilitiesMessageFilter> capabilities_message_filter_; std::vector<scoped_refptr<IPC::MessageFilter>> platform_message_filters_; DISALLOW_COPY_AND_ASSIGN(CastRenderProcessObserver);
diff --git a/chromecast/renderer/media/capabilities_message_filter.cc b/chromecast/renderer/media/capabilities_message_filter.cc new file mode 100644 index 0000000..fb109721 --- /dev/null +++ b/chromecast/renderer/media/capabilities_message_filter.cc
@@ -0,0 +1,32 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/renderer/media/capabilities_message_filter.h" + +#include "chromecast/common/media/cast_messages.h" +#include "chromecast/media/base/media_caps.h" + +namespace chromecast { + +CapabilitiesMessageFilter::CapabilitiesMessageFilter() { +} + +CapabilitiesMessageFilter::~CapabilitiesMessageFilter() { +} + +bool CapabilitiesMessageFilter::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(CapabilitiesMessageFilter, message) + IPC_MESSAGE_HANDLER(CmaMsg_UpdateSupportedHdmiSinkCodecs, + OnUpdateSupportedHdmiSinkCodecs) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void CapabilitiesMessageFilter::OnUpdateSupportedHdmiSinkCodecs(int codecs) { + ::media::SetHdmiSinkCodecs(codecs); +} + +} // namespace chromecast
diff --git a/chromecast/renderer/media/capabilities_message_filter.h b/chromecast/renderer/media/capabilities_message_filter.h new file mode 100644 index 0000000..6c9c1dee --- /dev/null +++ b/chromecast/renderer/media/capabilities_message_filter.h
@@ -0,0 +1,29 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_RENDERER_MEDIA_CAPABILITIES_MESSAGE_FILTER_H_ +#define CHROMECAST_RENDERER_MEDIA_CAPABILITIES_MESSAGE_FILTER_H_ + +#include "ipc/message_filter.h" + +namespace chromecast { + +class CapabilitiesMessageFilter : public IPC::MessageFilter { + public: + CapabilitiesMessageFilter(); + + // IPC::ChannelProxy::MessageFilter implementation: + bool OnMessageReceived(const IPC::Message& message) override; + + private: + ~CapabilitiesMessageFilter() override; + + void OnUpdateSupportedHdmiSinkCodecs(int codecs); + + DISALLOW_COPY_AND_ASSIGN(CapabilitiesMessageFilter); +}; + +} // namespace chromecast + +#endif // CHROMECAST_RENDERER_MEDIA_CAPABILITIES_MESSAGE_FILTER_H_
diff --git a/chromecast/renderer/media/chromecast_media_renderer_factory.cc b/chromecast/renderer/media/chromecast_media_renderer_factory.cc new file mode 100644 index 0000000..cdfab39f --- /dev/null +++ b/chromecast/renderer/media/chromecast_media_renderer_factory.cc
@@ -0,0 +1,74 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/renderer/media/chromecast_media_renderer_factory.h" + +#include "base/command_line.h" +#include "chromecast/media/base/switching_media_renderer.h" +#include "chromecast/media/cma/filters/cma_renderer.h" +#include "chromecast/renderer/media/media_pipeline_proxy.h" +#include "content/public/renderer/render_thread.h" +#include "media/base/audio_hardware_config.h" +#include "media/base/media_log.h" +#include "media/renderers/default_renderer_factory.h" +#include "media/renderers/gpu_video_accelerator_factories.h" + +namespace chromecast { +namespace media { + +ChromecastMediaRendererFactory::ChromecastMediaRendererFactory( + const scoped_refptr<::media::MediaLog>& media_log, + int render_frame_id) + : render_frame_id_(render_frame_id), + media_log_(media_log) { +} + +ChromecastMediaRendererFactory::~ChromecastMediaRendererFactory() { +} + +scoped_ptr<::media::Renderer> ChromecastMediaRendererFactory::CreateRenderer( + const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, + ::media::AudioRendererSink* audio_renderer_sink) { + if (!default_render_factory_) { + // Chromecast doesn't have input audio devices, so leave this uninitialized + ::media::AudioParameters input_audio_params; + // TODO(servolk): Audio parameters are hardcoded for now, but in the future + // either we need to obtain AudioHardwareConfig from RenderThreadImpl, + // or media renderer needs to figure out optimal audio parameters itself. + const int kDefaultSamplingRate = 48000; + const int kDefaultBitsPerSample = 16; + // About 20ms of stereo (2 channels) 16bit (2 byte) audio + int buffer_size = kDefaultSamplingRate * 20 * 2 * 2 / 1000; + ::media::AudioParameters output_audio_params( + ::media::AudioParameters::AUDIO_PCM_LOW_LATENCY, + ::media::CHANNEL_LAYOUT_STEREO, + kDefaultSamplingRate, kDefaultBitsPerSample, + buffer_size, ::media::AudioParameters::NO_EFFECTS); + ::media::AudioHardwareConfig audio_config(input_audio_params, + output_audio_params); + + default_render_factory_.reset(new ::media::DefaultRendererFactory( + media_log_, /*gpu_factories*/ nullptr, audio_config)); + } + + DCHECK(default_render_factory_); + // TODO(erickung): crbug.com/443956. Need to provide right LoadType. + LoadType cma_load_type = kLoadTypeMediaSource; + scoped_ptr<MediaPipeline> cma_media_pipeline( + new MediaPipelineProxy( + render_frame_id_, + content::RenderThread::Get()->GetIOMessageLoopProxy(), + cma_load_type)); + scoped_ptr<CmaRenderer> cma_renderer( + new CmaRenderer(cma_media_pipeline.Pass())); + scoped_ptr<::media::Renderer> default_media_render( + default_render_factory_->CreateRenderer(media_task_runner, + audio_renderer_sink)); + scoped_ptr<SwitchingMediaRenderer> media_renderer(new SwitchingMediaRenderer( + default_media_render.Pass(), cma_renderer.Pass())); + return media_renderer.Pass(); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/renderer/media/chromecast_media_renderer_factory.h b/chromecast/renderer/media/chromecast_media_renderer_factory.h new file mode 100644 index 0000000..f880ff6c --- /dev/null +++ b/chromecast/renderer/media/chromecast_media_renderer_factory.h
@@ -0,0 +1,43 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_RENDERER_MEDIA_CHROMECAST_MEDIA_RENDERER_FACTORY_H_ +#define CHROMECAST_RENDERER_MEDIA_CHROMECAST_MEDIA_RENDERER_FACTORY_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "media/base/renderer_factory.h" + +namespace media { +class MediaLog; +class DefaultRendererFactory; +} + +namespace chromecast { +namespace media { + +class ChromecastMediaRendererFactory : public ::media::RendererFactory { + public: + ChromecastMediaRendererFactory( + const scoped_refptr<::media::MediaLog>& media_log, + int render_frame_id); + ~ChromecastMediaRendererFactory() final; + + // ::media::RendererFactory implementation. + scoped_ptr<::media::Renderer> CreateRenderer( + const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, + ::media::AudioRendererSink* audio_renderer_sink) final; + + private: + int render_frame_id_; + scoped_refptr<::media::MediaLog> media_log_; + scoped_ptr<::media::DefaultRendererFactory> default_render_factory_; + + DISALLOW_COPY_AND_ASSIGN(ChromecastMediaRendererFactory); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_RENDERER_MEDIA_CHROMECAST_MEDIA_RENDERER_FACTORY_H_
diff --git a/chromecast/renderer/media/cma_media_renderer_factory.cc b/chromecast/renderer/media/cma_media_renderer_factory.cc deleted file mode 100644 index 2a38149..0000000 --- a/chromecast/renderer/media/cma_media_renderer_factory.cc +++ /dev/null
@@ -1,37 +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 "chromecast/renderer/media/cma_media_renderer_factory.h" - -#include "base/command_line.h" -#include "chromecast/media/cma/filters/cma_renderer.h" -#include "chromecast/renderer/media/media_pipeline_proxy.h" -#include "content/public/renderer/render_thread.h" - -namespace chromecast { -namespace media { - -CmaMediaRendererFactory::CmaMediaRendererFactory(int render_frame_id) - : render_frame_id_(render_frame_id) { -} - -CmaMediaRendererFactory::~CmaMediaRendererFactory() { -} - -scoped_ptr< ::media::Renderer> CmaMediaRendererFactory::CreateRenderer( - const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, - ::media::AudioRendererSink* audio_renderer_sink) { - // TODO(erickung): crbug.com/443956. Need to provide right LoadType. - LoadType cma_load_type = kLoadTypeMediaSource; - scoped_ptr<MediaPipeline> cma_media_pipeline( - new MediaPipelineProxy( - render_frame_id_, - content::RenderThread::Get()->GetIOMessageLoopProxy(), - cma_load_type)); - return scoped_ptr< ::media::Renderer>( - new CmaRenderer(cma_media_pipeline.Pass())); -} - -} // namespace media -} // namespace chromecast \ No newline at end of file
diff --git a/chromecast/renderer/media/cma_media_renderer_factory.h b/chromecast/renderer/media/cma_media_renderer_factory.h deleted file mode 100644 index b14b3d73..0000000 --- a/chromecast/renderer/media/cma_media_renderer_factory.h +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROMECAST_RENDERER_MEDIA_CMA_MEDIA_RENDERER_FACTORY_H_ -#define CHROMECAST_RENDERER_MEDIA_CMA_MEDIA_RENDERER_FACTORY_H_ - -#include "base/macros.h" -#include "media/base/renderer_factory.h" - -namespace chromecast { -namespace media { - -class CmaMediaRendererFactory : public ::media::RendererFactory { - public: - explicit CmaMediaRendererFactory(int render_frame_id); - ~CmaMediaRendererFactory() final; - - // ::media::RendererFactory implementation. - scoped_ptr< ::media::Renderer> CreateRenderer( - const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, - ::media::AudioRendererSink* audio_renderer_sink) final; - - private: - int render_frame_id_; - DISALLOW_COPY_AND_ASSIGN(CmaMediaRendererFactory); -}; - -} // namespace media -} // namespace chromecast - -#endif // CHROMECAST_RENDERER_MEDIA_CMA_MEDIA_RENDERER_FACTORY_H_ \ No newline at end of file
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 6297834..89db33a3 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -6835.0.0 \ No newline at end of file +6846.0.0 \ No newline at end of file
diff --git a/chromeos/app_mode/kiosk_oem_manifest_parser.cc b/chromeos/app_mode/kiosk_oem_manifest_parser.cc index 77d79fb0..f13d1a8 100644 --- a/chromeos/app_mode/kiosk_oem_manifest_parser.cc +++ b/chromeos/app_mode/kiosk_oem_manifest_parser.cc
@@ -28,14 +28,14 @@ bool KioskOemManifestParser::Load( const base::FilePath& kiosk_oem_file, KioskOemManifestParser::Manifest* manifest) { - int error_code = JSONFileValueSerializer::JSON_NO_ERROR; + int error_code = JSONFileValueDeserializer::JSON_NO_ERROR; std::string error_msg; - scoped_ptr<JSONFileValueSerializer> serializer( - new JSONFileValueSerializer(kiosk_oem_file)); + scoped_ptr<JSONFileValueDeserializer> deserializer( + new JSONFileValueDeserializer(kiosk_oem_file)); scoped_ptr<base::Value> value( - serializer->Deserialize(&error_code, &error_msg)); + deserializer->Deserialize(&error_code, &error_msg)); base::DictionaryValue* dict = NULL; - if (error_code != JSONFileValueSerializer::JSON_NO_ERROR || + if (error_code != JSONFileValueDeserializer::JSON_NO_ERROR || !value.get() || !value->GetAsDictionary(&dict)) { return false;
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc index 9549971..b96d5d4 100644 --- a/chromeos/chromeos_switches.cc +++ b/chromeos/chromeos_switches.cc
@@ -261,6 +261,7 @@ // Overrides network stub behavior. By default, ethernet, wifi and vpn are // enabled, and transitions occur instantaneously. Multiple options can be // comma separated (no spaces). Note: all options are in the format 'foo=x'. +// Values are case sensitive and based on Shill names in service_constants.h. // See FakeShillManagerClient::SetInitialNetworkState for implementation. // Examples: // 'clear=1' - Clears all default configurations @@ -270,6 +271,7 @@ // 'wifi=none' - Wifi is unavailable // 'wifi=portal' - Wifi connection will be in Portal state // 'cellular=1' - Cellular is initially connected +// 'cellular=LTE' - Cellular is initially connected, technology is LTE // 'interactive=3' - Interactive mode, connect/scan/etc requests take 3 secs const char kShillStub[] = "shill-stub"; @@ -313,8 +315,8 @@ const char kArtifactsDir[] = "artifacts-dir"; // Bypass proxy for captive portal authorization. -const char kEnableCaptivePortalBypassProxy[] = - "enable-captive-portal-bypass-proxy"; +const char kEnableCaptivePortalBypassProxyOption[] = + "enable-captive-portal-bypass-proxy-option"; // Disable automatic timezone update. const char kDisableTimeZoneTrackingOption[] =
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h index 60ef237..6a9f9bf 100644 --- a/chromeos/chromeos_switches.h +++ b/chromeos/chromeos_switches.h
@@ -103,7 +103,7 @@ CHROMEOS_EXPORT extern const char kSystemDevMode[]; CHROMEOS_EXPORT extern const char kTestAutoUpdateUI[]; CHROMEOS_EXPORT extern const char kWakeOnPackets[]; -CHROMEOS_EXPORT extern const char kEnableCaptivePortalBypassProxy[]; +CHROMEOS_EXPORT extern const char kEnableCaptivePortalBypassProxyOption[]; CHROMEOS_EXPORT extern const char kDisableTimeZoneTrackingOption[]; CHROMEOS_EXPORT bool WakeOnWifiEnabled();
diff --git a/chromeos/dbus/fake_easy_unlock_client.cc b/chromeos/dbus/fake_easy_unlock_client.cc index ee741fb..77441881 100644 --- a/chromeos/dbus/fake_easy_unlock_client.cc +++ b/chromeos/dbus/fake_easy_unlock_client.cc
@@ -20,8 +20,8 @@ // Extracts key pair index from a key in format "<key_type>: <key_pair_index>}". int ExtractKeyPairIndexFromKey(const std::string& key, const std::string& key_type) { - JSONStringValueSerializer serializer(key); - scoped_ptr<base::Value> json_value(serializer.Deserialize(NULL, NULL)); + JSONStringValueDeserializer deserializer(key); + scoped_ptr<base::Value> json_value(deserializer.Deserialize(NULL, NULL)); if (!json_value) return -1;
diff --git a/chromeos/dbus/fake_leadership_daemon_manager_client.cc b/chromeos/dbus/fake_leadership_daemon_manager_client.cc index e285a95f..7104aff 100644 --- a/chromeos/dbus/fake_leadership_daemon_manager_client.cc +++ b/chromeos/dbus/fake_leadership_daemon_manager_client.cc
@@ -13,10 +13,15 @@ callback.Run(DBUS_METHOD_CALL_SUCCESS, std::string()); } +void ObjectPathDBBusMethodCallbackThunk( + const ObjectPathDBusMethodCallback& callback) { + callback.Run(DBUS_METHOD_CALL_SUCCESS, dbus::ObjectPath()); +} + void VoidDBBusMethodCallbackThunk(const VoidDBusMethodCallback& callback) { callback.Run(DBUS_METHOD_CALL_SUCCESS); } -} +} // namespace FakeLeadershipDaemonManagerClient::FakeLeadershipDaemonManagerClient() { } @@ -36,9 +41,9 @@ void FakeLeadershipDaemonManagerClient::JoinGroup( const std::string& group, const base::DictionaryValue& options, - const StringDBusMethodCallback& callback) { + const ObjectPathDBusMethodCallback& callback) { base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&StringDBBusMethodCallbackThunk, callback)); + FROM_HERE, base::Bind(&ObjectPathDBBusMethodCallbackThunk, callback)); } void FakeLeadershipDaemonManagerClient::LeaveGroup(
diff --git a/chromeos/dbus/fake_leadership_daemon_manager_client.h b/chromeos/dbus/fake_leadership_daemon_manager_client.h index f74c010..f6d9f28 100644 --- a/chromeos/dbus/fake_leadership_daemon_manager_client.h +++ b/chromeos/dbus/fake_leadership_daemon_manager_client.h
@@ -28,7 +28,7 @@ void RemoveObserver(Observer* observer) override; void JoinGroup(const std::string& group, const base::DictionaryValue& options, - const StringDBusMethodCallback& callback) override; + const ObjectPathDBusMethodCallback& callback) override; void LeaveGroup(const std::string& object_path, const VoidDBusMethodCallback& callback) override; void SetScore(const std::string& object_path,
diff --git a/chromeos/dbus/fake_shill_manager_client.cc b/chromeos/dbus/fake_shill_manager_client.cc index 72dedef..2702ad9 100644 --- a/chromeos/dbus/fake_shill_manager_client.cc +++ b/chromeos/dbus/fake_shill_manager_client.cc
@@ -105,6 +105,19 @@ base::StringValue(shill::kStatePortal)); } +bool IsCellularTechnology(const std::string& type) { + return (type == shill::kNetworkTechnology1Xrtt || + type == shill::kNetworkTechnologyEvdo || + type == shill::kNetworkTechnologyGsm || + type == shill::kNetworkTechnologyGprs || + type == shill::kNetworkTechnologyEdge || + type == shill::kNetworkTechnologyUmts || + type == shill::kNetworkTechnologyHspa || + type == shill::kNetworkTechnologyHspaPlus || + type == shill::kNetworkTechnologyLte || + type == shill::kNetworkTechnologyLteAdvanced); +} + const char* kTechnologyUnavailable = "unavailable"; const char* kNetworkActivated = "activated"; const char* kNetworkDisabled = "disabled"; @@ -118,6 +131,7 @@ FakeShillManagerClient::FakeShillManagerClient() : interactive_delay_(0), + cellular_technology_(shill::kNetworkTechnologyGsm), weak_ptr_factory_(this) { ParseCommandLineSwitch(); } @@ -776,7 +790,7 @@ shill::kTypeCellular, state, add_to_visible); - base::StringValue technology_value(shill::kNetworkTechnologyGsm); + base::StringValue technology_value(cellular_technology_); devices->SetDeviceProperty("/device/cellular1", shill::kTechnologyFamilyProperty, technology_value); @@ -1066,7 +1080,6 @@ bool FakeShillManagerClient::SetInitialNetworkState(std::string type_arg, std::string state_arg) { std::string state; - state_arg = base::StringToLowerASCII(state_arg); if (state_arg.empty() || state_arg == "1" || state_arg == "on" || state_arg == "enabled" || state_arg == "connected" || state_arg == "online") { @@ -1088,12 +1101,20 @@ } else if (state_arg == "active" || state_arg == "activated") { // Technology is enabled, a service is connected and Activated. state = kNetworkActivated; + } else if (type_arg == shill::kTypeCellular && + IsCellularTechnology(state_arg)) { + state = shill::kStateOnline; + cellular_technology_ = state_arg; + } else if (type_arg == shill::kTypeCellular && state_arg == "LTEAdvanced") { + // Special case, Shill name contains a ' '. + state = shill::kStateOnline; + cellular_technology_ = shill::kNetworkTechnologyLteAdvanced; } else { - LOG(ERROR) << "Unrecognized initial state: " << state_arg; + LOG(ERROR) << "Unrecognized initial state: " << type_arg << "=" + << state_arg; return false; } - type_arg = base::StringToLowerASCII(type_arg); // Special cases if (type_arg == "wireless") { shill_initial_state_map_[shill::kTypeWifi] = state;
diff --git a/chromeos/dbus/fake_shill_manager_client.h b/chromeos/dbus/fake_shill_manager_client.h index b21b2a1..61d1809 100644 --- a/chromeos/dbus/fake_shill_manager_client.h +++ b/chromeos/dbus/fake_shill_manager_client.h
@@ -142,6 +142,9 @@ // Initial state for fake services. std::map<std::string, std::string> shill_initial_state_map_; + // Technology type for fake cellular service. + std::string cellular_technology_; + // Roaming state for fake cellular service. std::string roaming_state_;
diff --git a/chromeos/dbus/leadership_daemon_manager_client.cc b/chromeos/dbus/leadership_daemon_manager_client.cc index 51f7765..9ad7f42a 100644 --- a/chromeos/dbus/leadership_daemon_manager_client.cc +++ b/chromeos/dbus/leadership_daemon_manager_client.cc
@@ -53,7 +53,7 @@ void RemoveObserver(Observer* observer) override; void JoinGroup(const std::string& group, const base::DictionaryValue& options, - const StringDBusMethodCallback& callback) override; + const ObjectPathDBusMethodCallback& callback) override; void LeaveGroup(const std::string& object_path, const VoidDBusMethodCallback& callback) override; void SetScore(const std::string& object_path, @@ -85,6 +85,8 @@ void OnGroupPropertyChanged(const dbus::ObjectPath& object_path, const std::string& property_name); + void OnObjectPathDBusMethod(const ObjectPathDBusMethodCallback& callback, + dbus::Response* response); void OnStringDBusMethod(const StringDBusMethodCallback& callback, dbus::Response* response); void OnVoidDBusMethod(const VoidDBusMethodCallback& callback, @@ -122,13 +124,13 @@ void LeadershipDaemonManagerClientImpl::JoinGroup( const std::string& group, const base::DictionaryValue& options, - const StringDBusMethodCallback& callback) { + const ObjectPathDBusMethodCallback& callback) { dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy( dbus::ObjectPath(leaderd::kLeaderdManagerPath)); if (!object_proxy) { base::MessageLoop::current()->PostTask( FROM_HERE, - base::Bind(&LeadershipDaemonManagerClientImpl::OnStringDBusMethod, + base::Bind(&LeadershipDaemonManagerClientImpl::OnObjectPathDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback, nullptr)); return; } @@ -140,7 +142,7 @@ dbus::AppendValueData(&writer, options); object_proxy->CallMethod( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, - base::Bind(&LeadershipDaemonManagerClientImpl::OnStringDBusMethod, + base::Bind(&LeadershipDaemonManagerClientImpl::OnObjectPathDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback)); } @@ -298,6 +300,24 @@ GroupPropertyChanged(object_path, property_name)); } +void LeadershipDaemonManagerClientImpl::OnObjectPathDBusMethod( + const ObjectPathDBusMethodCallback& callback, + dbus::Response* response) { + if (!response) { + callback.Run(DBUS_METHOD_CALL_FAILURE, dbus::ObjectPath()); + return; + } + + dbus::MessageReader reader(response); + dbus::ObjectPath result; + if (!reader.PopObjectPath(&result)) { + callback.Run(DBUS_METHOD_CALL_FAILURE, result); + return; + } + + callback.Run(DBUS_METHOD_CALL_SUCCESS, result); +} + void LeadershipDaemonManagerClientImpl::OnStringDBusMethod( const StringDBusMethodCallback& callback, dbus::Response* response) {
diff --git a/chromeos/dbus/leadership_daemon_manager_client.h b/chromeos/dbus/leadership_daemon_manager_client.h index 0be037e..2c68460e 100644 --- a/chromeos/dbus/leadership_daemon_manager_client.h +++ b/chromeos/dbus/leadership_daemon_manager_client.h
@@ -85,7 +85,7 @@ // |callback| is called with |call_status| set to DBUS_METHOD_CALL_FAILURE. virtual void JoinGroup(const std::string& group, const base::DictionaryValue& options, - const StringDBusMethodCallback& callback) = 0; + const ObjectPathDBusMethodCallback& callback) = 0; // Calls LeaveGroup method. // |callback| is called with its |call_status| argument set to
diff --git a/chromeos/geolocation/simple_geolocation_provider.cc b/chromeos/geolocation/simple_geolocation_provider.cc index 4a57ac7..e083b3ed 100644 --- a/chromeos/geolocation/simple_geolocation_provider.cc +++ b/chromeos/geolocation/simple_geolocation_provider.cc
@@ -62,10 +62,13 @@ callback.Run(geoposition, server_error, elapsed); - ScopedVector<SimpleGeolocationRequest>::iterator new_end = - std::remove(requests_.begin(), requests_.end(), request); - DCHECK_EQ(std::distance(new_end, requests_.end()), 1); - requests_.erase(new_end, requests_.end()); + ScopedVector<SimpleGeolocationRequest>::iterator position = + std::find(requests_.begin(), requests_.end(), request); + DCHECK(position != requests_.end()); + if (position != requests_.end()) { + std::swap(*position, *requests_.rbegin()); + requests_.resize(requests_.size() - 1); + } } } // namespace chromeos
diff --git a/chromeos/network/onc/onc_test_utils.cc b/chromeos/network/onc/onc_test_utils.cc index 56e5bc63..522a9ed 100644 --- a/chromeos/network/onc/onc_test_utils.cc +++ b/chromeos/network/onc/onc_test_utils.cc
@@ -48,11 +48,11 @@ return make_scoped_ptr(dict); } - JSONFileValueSerializer serializer(path); - serializer.set_allow_trailing_comma(true); + JSONFileValueDeserializer deserializer(path); + deserializer.set_allow_trailing_comma(true); std::string error_message; - base::Value* content = serializer.Deserialize(NULL, &error_message); + base::Value* content = deserializer.Deserialize(NULL, &error_message); CHECK(content != NULL) << "Couldn't json-deserialize file '" << filename << "': " << error_message;
diff --git a/chromeos/network/portal_detector/network_portal_detector.cc b/chromeos/network/portal_detector/network_portal_detector.cc index f3745c5..5cfdcae 100644 --- a/chromeos/network/portal_detector/network_portal_detector.cc +++ b/chromeos/network/portal_detector/network_portal_detector.cc
@@ -119,4 +119,7 @@ PortalDetectorStrategy::StrategyId /* id */) { } +void NetworkPortalDetectorStubImpl::OnLockScreenRequest() { +} + } // namespace chromeos
diff --git a/chromeos/network/portal_detector/network_portal_detector.h b/chromeos/network/portal_detector/network_portal_detector.h index 8a65d1e..3639a17 100644 --- a/chromeos/network/portal_detector/network_portal_detector.h +++ b/chromeos/network/portal_detector/network_portal_detector.h
@@ -122,6 +122,9 @@ // Returns non-localized string representation of |status|. static std::string CaptivePortalStatusString(CaptivePortalStatus status); + // Closes portal login window before screen is locked. + virtual void OnLockScreenRequest() = 0; + protected: NetworkPortalDetector() {} virtual ~NetworkPortalDetector() {} @@ -159,6 +162,7 @@ void Enable(bool start_detection) override; bool StartDetectionIfIdle() override; void SetStrategy(PortalDetectorStrategy::StrategyId id) override; + void OnLockScreenRequest() override; private: DISALLOW_COPY_AND_ASSIGN(NetworkPortalDetectorStubImpl);
diff --git a/chromeos/timezone/timezone_provider.cc b/chromeos/timezone/timezone_provider.cc index c9646c6..08e10e5 100644 --- a/chromeos/timezone/timezone_provider.cc +++ b/chromeos/timezone/timezone_provider.cc
@@ -47,10 +47,13 @@ TimeZoneRequest::TimeZoneResponseCallback callback, scoped_ptr<TimeZoneResponseData> timezone, bool server_error) { - ScopedVector<TimeZoneRequest>::iterator new_end = - std::remove(requests_.begin(), requests_.end(), request); - DCHECK_EQ(std::distance(new_end, requests_.end()), 1); - requests_.erase(new_end, requests_.end()); + ScopedVector<TimeZoneRequest>::iterator position = + std::find(requests_.begin(), requests_.end(), request); + DCHECK(position != requests_.end()); + if (position != requests_.end()) { + std::swap(*position, *requests_.rbegin()); + requests_.resize(requests_.size() - 1); + } callback.Run(timezone.Pass(), server_error); }
diff --git a/chromeos/tools/onc_validator/onc_validator.cc b/chromeos/tools/onc_validator/onc_validator.cc index d47597eb..84a9220 100644 --- a/chromeos/tools/onc_validator/onc_validator.cc +++ b/chromeos/tools/onc_validator/onc_validator.cc
@@ -84,13 +84,13 @@ scoped_ptr<base::DictionaryValue> ReadDictionary(std::string filename) { base::FilePath path(filename); - JSONFileValueSerializer serializer(path); - serializer.set_allow_trailing_comma(true); + JSONFileValueDeserializer deserializer(path); + deserializer.set_allow_trailing_comma(true); base::DictionaryValue* dict = NULL; std::string json_error; - base::Value* value = serializer.Deserialize(NULL, &json_error); + base::Value* value = deserializer.Deserialize(NULL, &json_error); if (!value) { LOG(ERROR) << "Couldn't json-deserialize file '" << filename << "': " << json_error;
diff --git a/components/BUILD.gn b/components/BUILD.gn index 95b02c9..d472b0b9 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -40,6 +40,7 @@ "//components/enhanced_bookmarks", "//components/favicon/core", "//components/favicon_base", + "//components/feedback", "//components/gcm_driver", "//components/google/core/browser", "//components/history/content/browser", @@ -109,8 +110,9 @@ "//components/web_cache/common", "//components/web_cache/renderer", "//components/web_modal", - "//components/webdata/common", "//components/web_resource", + "//components/webdata/common", + "//components/webui_generator", "//components/wifi", "//components/wifi_sync", ] @@ -132,6 +134,7 @@ deps -= [ "//components/history/content/browser", "//components/keyed_service/content", + "//components/webui_generator", ] } @@ -161,6 +164,7 @@ "//components/domain_reliability", # Blocked on content. "//components/favicon_base", # Should work, needs checking. "//components/favicon/core", # Blocked on keyed service. + "//components/feedback", # Blocked on content. "//components/gcm_driver", # Should work, needs checking. "//components/google/core/browser", # Should work, needs checking. "//components/history/core/browser", # Should work, needs checking. @@ -202,7 +206,6 @@ if (!is_ios && !is_android) { deps += [ "//components/copresence", - "//components/feedback", "//components/storage_monitor", ] } @@ -220,89 +223,84 @@ # component (it's important to use a source_set instead of a static library or # no tests will run) and add a reference here. You can add more than one unit # test target if convenient. -if (!is_win || link_chrome_on_windows) { - test("components_unittests") { - sources = [ - "test/run_all_unittests.cc", - ] +test("components_unittests") { + sources = [ + "test/run_all_unittests.cc", + ] - # Add only ":unit_tests" dependencies here. If your tests have dependencies - # (this would at least include the component itself), they should be on the - # test source set and not here. - deps = [ - "//components/auto_login_parser:unit_tests", - "//components/autofill/content/browser:unit_tests", - "//components/autofill/core/browser:unit_tests", - "//components/autofill/core/common:unit_tests", - "//components/bookmarks/browser:unit_tests", - "//components/captive_portal:unit_tests", - "//components/cloud_devices/common:unit_tests", - "//components/content_settings/core/browser:unit_tests", - "//components/content_settings/core/common:unit_tests", - "//components/crx_file:unit_tests", - "//components/data_reduction_proxy/core/browser:unit_tests", - "//components/data_reduction_proxy/core/common:unit_tests", - "//components/device_event_log:unit_tests", - "//components/dom_distiller/core:unit_tests", - "//components/domain_reliability:unit_tests", - "//components/favicon_base:unit_tests", - "//components/google/core/browser:unit_tests", - "//components/invalidation:unittests", - "//components/login:unit_tests", - "//components/metrics:unit_tests", - "//components/omnibox:unit_tests", - "//components/ownership:unit_tests", - "//components/packed_ct_ev_whitelist:unit_tests", - "//components/proximity_auth:unit_tests", - "//components/update_client:unit_tests", - "//components/variations:unit_tests", - "//components/web_resource:unit_tests", - "//components/webdata/common:unit_tests", + # Add only ":unit_tests" dependencies here. If your tests have dependencies + # (this would at least include the component itself), they should be on the + # test source set and not here. + deps = [ + "//components/auto_login_parser:unit_tests", + "//components/autofill/content/browser:unit_tests", + "//components/autofill/core/browser:unit_tests", + "//components/autofill/core/common:unit_tests", + "//components/bookmarks/browser:unit_tests", + "//components/captive_portal:unit_tests", + "//components/cloud_devices/common:unit_tests", + "//components/content_settings/core/browser:unit_tests", + "//components/content_settings/core/common:unit_tests", + "//components/crx_file:unit_tests", + "//components/data_reduction_proxy/content/browser:unit_tests", + "//components/data_reduction_proxy/core/browser:unit_tests", + "//components/data_reduction_proxy/core/common:unit_tests", + "//components/device_event_log:unit_tests", + "//components/dom_distiller/core:unit_tests", + "//components/domain_reliability:unit_tests", + "//components/favicon_base:unit_tests", + "//components/google/core/browser:unit_tests", + "//components/invalidation:unittests", + "//components/login:unit_tests", + "//components/metrics:unit_tests", + "//components/omnibox:unit_tests", + "//components/ownership:unit_tests", + "//components/packed_ct_ev_whitelist:unit_tests", + "//components/proximity_auth:unit_tests", + "//components/update_client:unit_tests", + "//components/variations:unit_tests", + "//components/web_resource:unit_tests", + "//components/webdata/common:unit_tests", - # These are the deps required by the code in this target. - "//base", - "//base/test:test_support", - "//content/test:test_support", - "//ui/base", - ] - data_deps = [ ":components_tests_pak" ] + # These are the deps required by the code in this target. + "//base", + "//base/test:test_support", + "//content/test:test_support", + "//ui/base", + ] + data_deps = [ ":components_tests_pak" ] - if (is_android) { - deps += [ "//components/data_reduction_proxy/content/browser:unit_tests" ] - } + # TODO(GYP) need this target. + #'breakpad/app/crash_keys_win_unittest.cc', - # TODO(GYP) need this target. - #'breakpad/app/crash_keys_win_unittest.cc', + # Precache tests need these defines. + #configs += [ "//components/precache/core:precache_config" ] - # Precache tests need these defines. - #configs += [ "//components/precache/core:precache_config" ] - - if (toolkit_views) { - # TODO(GYP) enable this as above. - #deps += [ "//components/constrained_window:unit_tests" ] - } - if (is_win) { - deps += [ "//components/browser_watcher:unit_tests" ] - } + if (toolkit_views) { + # TODO(GYP) enable this as above. + #deps += [ "//components/constrained_window:unit_tests" ] } - - repack("components_tests_pak") { - sources = [ - "$root_gen_dir/components/components_resources.pak", - "$root_gen_dir/components/strings/components_strings_en-US.pak", - "$root_gen_dir/ui/resources/ui_resources_100_percent.pak", - "$root_gen_dir/ui/resources/webui_resources.pak", - "$root_gen_dir/ui/strings/app_locale_settings_en-US.pak", - "$root_gen_dir/ui/strings/ui_strings_en-US.pak", - ] - - output = "$root_out_dir/components_tests_resources.pak" - - deps = [ - "//components/resources", - "//components/strings", - "//ui/resources", - "//ui/strings", - ] + if (is_win) { + deps += [ "//components/browser_watcher:unit_tests" ] } } + +repack("components_tests_pak") { + sources = [ + "$root_gen_dir/components/components_resources.pak", + "$root_gen_dir/components/strings/components_strings_en-US.pak", + "$root_gen_dir/ui/resources/ui_resources_100_percent.pak", + "$root_gen_dir/ui/resources/webui_resources.pak", + "$root_gen_dir/ui/strings/app_locale_settings_en-US.pak", + "$root_gen_dir/ui/strings/ui_strings_en-US.pak", + ] + + output = "$root_out_dir/components_tests_resources.pak" + + deps = [ + "//components/resources", + "//components/strings", + "//ui/resources", + "//ui/strings", + ] +}
diff --git a/components/OWNERS b/components/OWNERS index 7e08c1c..89bfbf50 100644 --- a/components/OWNERS +++ b/components/OWNERS
@@ -280,6 +280,9 @@ per-file web_resource.gypi=rsesek@chromium.org per-file web_resource.gypi=stevet@chromium.org +per-file webui_generator.gypi=dzhioev@chromium.org +per-file webui_generator_strings.grdp=dzhioev@chromium.org + per-file wifi.gypi=mef@chromium.org per-file *.isolate=csharp@chromium.org
diff --git a/components/audio_modem/audio_recorder_unittest.cc b/components/audio_modem/audio_recorder_unittest.cc index 0dd089ae..598a5c3 100644 --- a/components/audio_modem/audio_recorder_unittest.cc +++ b/components/audio_modem/audio_recorder_unittest.cc
@@ -196,7 +196,15 @@ content::TestBrowserThreadBundle thread_bundle_; }; -TEST_F(AudioRecorderTest, BasicRecordAndStop) { + +// http://crbug.com/463854 +#if defined(OS_MACOSX) +#define MAYBE_BasicRecordAndStop DISABLED_BasicRecordAndStop +#else +#define MAYBE_BasicRecordAndStop BasicRecordAndStop +#endif + +TEST_F(AudioRecorderTest, MAYBE_BasicRecordAndStop) { CreateSimpleRecorder(); recorder_->Record();
diff --git a/components/autofill.gypi b/components/autofill.gypi index 21d98fd..e8c6d153 100644 --- a/components/autofill.gypi +++ b/components/autofill.gypi
@@ -459,5 +459,26 @@ }, ], }], + ['OS == "ios"', { + 'targets': [ + { + 'target_name': 'autofill_ios_browser', + 'type': 'static_library', + 'include_dirs': [ + '..', + ], + 'dependencies': [ + 'autofill_core_browser', + '../ios/provider/ios_provider_web.gyp:ios_provider_web', + '../ios/web/ios_web.gyp:ios_web', + ], + 'sources': [ + 'autofill/ios/browser/autofill_driver_ios.h', + 'autofill/ios/browser/autofill_driver_ios.mm', + 'autofill/ios/browser/autofill_driver_ios_bridge.h', + ], + }, + ], + }], ], }
diff --git a/components/autofill/content/renderer/form_cache.cc b/components/autofill/content/renderer/form_cache.cc index 3f27c39..9bc97e2f 100644 --- a/components/autofill/content/renderer/form_cache.cc +++ b/components/autofill/content/renderer/form_cache.cc
@@ -119,10 +119,41 @@ parsed_forms_.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 synthetic_form; + if (!UnownedFormElementsAndFieldSetsToFormData(fieldsets, control_elements, + nullptr, document.url(), + REQUIRE_NONE, extract_mask, + &synthetic_form, nullptr)) { + return forms; + } + + num_fields_seen += synthetic_form.fields.size(); + if (num_fields_seen > kMaxParseableFields) + return forms; + + if (synthetic_form.fields.size() >= kRequiredAutofillFields && + !parsed_forms_.count(synthetic_form)) { + forms.push_back(synthetic_form); + parsed_forms_.insert(synthetic_form); + synthetic_form_ = synthetic_form; + } return forms; } void FormCache::Reset() { + synthetic_form_ = FormData(); parsed_forms_.clear(); initial_select_values_.clear(); initial_checked_state_.clear(); @@ -191,7 +222,15 @@ std::vector<WebFormControlElement> control_elements; + // First check the synthetic form. bool found_synthetic_form = false; + if (form.data.SameFormAs(synthetic_form_)) { + found_synthetic_form = true; + WebDocument document = frame_.document(); + control_elements = + GetUnownedAutofillableFormFieldElements(document.all(), nullptr); + } + if (!found_synthetic_form) { // Find the real form by searching through the WebDocuments. bool found_form = false;
diff --git a/components/autofill/content/renderer/form_cache.h b/components/autofill/content/renderer/form_cache.h index f37a981..d0c29cd 100644 --- a/components/autofill/content/renderer/form_cache.h +++ b/components/autofill/content/renderer/form_cache.h
@@ -64,6 +64,10 @@ // The cached forms. Used to prevent re-extraction of forms. std::set<FormData> parsed_forms_; + // The synthetic FormData is for all the fieldsets in the document without a + // form owner. + FormData synthetic_form_; + // The cached initial values for <select> elements. std::map<const blink::WebSelectElement, base::string16> initial_select_values_;
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc index af3cbd8..3918ef2d 100644 --- a/components/autofill/content/renderer/password_form_conversion_utils.cc +++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -60,6 +60,9 @@ if (!current_password->isNull() || !new_password->isNull()) return true; + if (passwords.empty()) + return false; + switch (passwords.size()) { case 1: // Single password, easy. @@ -77,7 +80,7 @@ *new_password = passwords[1]; } break; - case 3: + default: if (!passwords[0].value().isEmpty() && passwords[0].value() == passwords[1].value() && passwords[0].value() == passwords[2].value()) { @@ -91,17 +94,15 @@ *new_password = passwords[1]; } else if (passwords[0].value() == passwords[1].value()) { // It is strange that the new password comes first, but trust more which - // fields are duplicated than the ordering of fields. - *current_password = passwords[2]; + // fields are duplicated than the ordering of fields. Assume that + // any password fields after the new password contain sensitive + // information that isn't actually a password (security hint, SSN, etc.) *new_password = passwords[0]; } else { // Three different passwords, or first and last match with middle // different. No idea which is which, so no luck. return false; } - break; - default: - return false; } return true; }
diff --git a/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc b/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc index 5a72daf..05dc714 100644 --- a/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc +++ b/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
@@ -342,7 +342,10 @@ {{"alpha", "", ""}, "password1", "alpha", "password2", ""}, {{"", "beta", "beta"}, "password1", "", "password2", "beta"}, {{"alpha", "beta", "beta"}, "password1", "alpha", "password2", "beta"}, - {{"beta", "beta", "alpha"}, "password3", "alpha", "password1", "beta"}, + // If confirmed password comes first, assume that the third password + // field is related to security question, SSN, or credit card and ignore + // it. + {{"beta", "beta", "alpha"}, "", "", "password1", "beta"}, // If the fields are yet empty, we speculate that we will identify them as // (current + new + new) once they are filled out, so we should classify // them the same for now to keep our abstract interpretation less flaky.
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h index 534aa68..ef3039b 100644 --- a/components/autofill/core/browser/autofill_client.h +++ b/components/autofill/core/browser/autofill_client.h
@@ -55,6 +55,21 @@ AutocompleteResultErrorInvalid, }; + enum GetRealPanResult { + // Request succeeded. + SUCCESS, + + // Request failed; try again. + TRY_AGAIN_FAILURE, + + // Request failed; don't try again. + PERMANENT_FAILURE, + + // Unable to connect to Wallet servers. Prompt user to check internet + // connection. + NETWORK_ERROR, + }; + typedef base::Callback<void(RequestAutocompleteResult, const base::string16&, const FormStructure*)> ResultCallback; @@ -87,7 +102,7 @@ // information to proceed. virtual void ShowUnmaskPrompt(const CreditCard& card, base::WeakPtr<CardUnmaskDelegate> delegate) = 0; - virtual void OnUnmaskVerificationResult(bool success) = 0; + virtual void OnUnmaskVerificationResult(GetRealPanResult result) = 0; // Run |save_card_callback| if the credit card should be imported as personal // data. |metric_logger| can be used to log user actions.
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc index ca6399a..20121fc 100644 --- a/components/autofill/core/browser/autofill_manager.cc +++ b/components/autofill/core/browser/autofill_manager.cc
@@ -778,8 +778,10 @@ return client()->GetIdentityProvider(); } -void AutofillManager::OnDidGetRealPan(const std::string& real_pan) { +void AutofillManager::OnDidGetRealPan(AutofillClient::GetRealPanResult result, + const std::string& real_pan) { if (!real_pan.empty()) { + DCHECK_EQ(AutofillClient::SUCCESS, result); credit_card_form_event_logger_->OnDidFillSuggestion(unmasking_card_); unmasking_card_.set_record_type(CreditCard::FULL_SERVER_CARD); unmasking_card_.SetNumber(base::UTF8ToUTF16(real_pan)); @@ -790,7 +792,7 @@ unmasking_card_); } - client()->OnUnmaskVerificationResult(!real_pan.empty()); + client()->OnUnmaskVerificationResult(result); } void AutofillManager::OnDidEndTextFieldEditing() {
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h index e9bbb44..5f8b67b 100644 --- a/components/autofill/core/browser/autofill_manager.h +++ b/components/autofill/core/browser/autofill_manager.h
@@ -237,7 +237,8 @@ // wallet::RealPanWalletClient::Delegate: IdentityProvider* GetIdentityProvider() override; - void OnDidGetRealPan(const std::string& real_pan) override; + void OnDidGetRealPan(AutofillClient::GetRealPanResult result, + const std::string& real_pan) override; // Returns false if Autofill is disabled or if no Autofill data is available. bool RefreshDataModels();
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc index f249d08..04ff306 100644 --- a/components/autofill/core/browser/autofill_metrics_unittest.cc +++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -1186,7 +1186,8 @@ AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(), autofill_manager_->MakeFrontendID(guid, SuggestionBackendID())); - autofill_manager_->OnDidGetRealPan("6011000990139424"); + autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS, + "6011000990139424"); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1); @@ -1348,7 +1349,8 @@ AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(), autofill_manager_->MakeFrontendID(guid, SuggestionBackendID())); - autofill_manager_->OnDidGetRealPan("6011000990139424"); + autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS, + "6011000990139424"); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc index 9b6504e..8b96c654 100644 --- a/components/autofill/core/browser/autofill_profile.cc +++ b/components/autofill/core/browser/autofill_profile.cc
@@ -567,28 +567,26 @@ ServerFieldTypeSet types; GetNonEmptyTypes(app_locale, &types); - for (ServerFieldTypeSet::const_iterator it = types.begin(); it != types.end(); - ++it) { - if (*it == NAME_FULL || *it == ADDRESS_HOME_STREET_ADDRESS) { + for (ServerFieldType type : types) { + if (type == NAME_FULL || type == ADDRESS_HOME_STREET_ADDRESS) { // Ignore the compound "full name" field type. We are only interested in // comparing the constituent parts. For example, if |this| has a middle // name saved, but |profile| lacks one, |profile| could still be a subset // of |this|. Likewise, ignore the compound "street address" type, as we // are only interested in matching line-by-line. continue; - } else if (AutofillType(*it).group() == PHONE_HOME) { + } else if (AutofillType(type).group() == PHONE_HOME) { // Phone numbers should be canonicalized prior to being compared. - if (*it != PHONE_HOME_WHOLE_NUMBER) { + if (type != PHONE_HOME_WHOLE_NUMBER) { continue; } else if (!i18n::PhoneNumbersMatch( - GetRawInfo(*it), - profile.GetRawInfo(*it), - base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)), - app_locale)) { + GetRawInfo(type), profile.GetRawInfo(type), + base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)), + app_locale)) { return false; } - } else if (base::StringToLowerASCII(GetRawInfo(*it)) != - base::StringToLowerASCII(profile.GetRawInfo(*it))) { + } else if (base::StringToLowerASCII(GetRawInfo(type)) != + base::StringToLowerASCII(profile.GetRawInfo(type))) { return false; } }
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc index 0bf83516..aa1658bc9 100644 --- a/components/autofill/core/browser/personal_data_manager.cc +++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -1123,7 +1123,7 @@ CancelPendingQuery(&pending_server_profiles_query_); pending_profiles_query_ = database_->GetAutofillProfiles(this); - pending_server_profiles_query_ = database_->GetAutofillServerProfiles(this); + pending_server_profiles_query_ = database_->GetServerProfiles(this); } // Win, Linux, Android and iOS implementations do nothing. Mac implementation @@ -1164,12 +1164,16 @@ return std::string(); // Don't save a web profile if the data in the profile is a subset of an - // auxiliary profile. - for (std::vector<AutofillProfile*>::const_iterator iter = - auxiliary_profiles_.begin(); - iter != auxiliary_profiles_.end(); ++iter) { - if (imported_profile.IsSubsetOf(**iter, app_locale_)) - return (*iter)->guid(); + // auxiliary profile... + for (AutofillProfile* profile : auxiliary_profiles_) { + if (imported_profile.IsSubsetOf(*profile, app_locale_)) + return profile->guid(); + } + + // ...or server profile. + for (AutofillProfile* profile : server_profiles_) { + if (imported_profile.IsSubsetOf(*profile, app_locale_)) + return profile->guid(); } std::vector<AutofillProfile> profiles;
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc index 5955670..ae899cc 100644 --- a/components/autofill/core/browser/personal_data_manager_unittest.cc +++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -185,6 +185,45 @@ ExpectSameElements(profiles, personal_data_->GetProfiles()); } +TEST_F(PersonalDataManagerTest, DontDuplicateServerProfile) { + EnableWalletCardImport(); + + std::vector<AutofillProfile> server_profiles; + server_profiles.push_back( + AutofillProfile(AutofillProfile::SERVER_PROFILE, "a123")); + test::SetProfileInfo(&server_profiles.back(), "John", "", "Doe", "", + "ACME Corp", "500 Oak View", "Apt 8", "Houston", "TX", + "77401", "US", ""); + // Wallet only provides a full name, so the above first and last names + // will be ignored when the profile is written to the DB. + server_profiles.back().SetRawInfo(NAME_FULL, ASCIIToUTF16("John Doe")); + autofill_table_->SetServerProfiles(server_profiles); + personal_data_->Refresh(); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .WillOnce(QuitMainMessageLoop()); + base::MessageLoop::current()->Run(); + EXPECT_EQ(1U, personal_data_->GetProfiles().size()); + + // Add profile with identical values. Duplicates should not get saved. + AutofillProfile scraped_profile(base::GenerateGUID(), + "https://www.example.com"); + test::SetProfileInfo(&scraped_profile, "John", "", "Doe", "", "ACME Corp", + "500 Oak View", "Apt 8", "Houston", "TX", "77401", "US", + ""); + EXPECT_TRUE(scraped_profile.IsSubsetOf(server_profiles.back(), "en-US")); + std::string saved_guid = personal_data_->SaveImportedProfile(scraped_profile); + EXPECT_NE(scraped_profile.guid(), saved_guid); + + personal_data_->Refresh(); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .WillOnce(QuitMainMessageLoop()); + base::MessageLoop::current()->Run(); + + // Verify the non-addition. + EXPECT_EQ(1U, personal_data_->GetProfiles().size()); + EXPECT_EQ(0U, personal_data_->web_profiles().size()); +} + TEST_F(PersonalDataManagerTest, AddUpdateRemoveProfiles) { AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com"); test::SetProfileInfo(&profile0,
diff --git a/components/autofill/core/browser/test_autofill_client.cc b/components/autofill/core/browser/test_autofill_client.cc index abcfb53..eef879d 100644 --- a/components/autofill/core/browser/test_autofill_client.cc +++ b/components/autofill/core/browser/test_autofill_client.cc
@@ -42,7 +42,7 @@ base::WeakPtr<CardUnmaskDelegate> delegate) { } -void TestAutofillClient::OnUnmaskVerificationResult(bool success) { +void TestAutofillClient::OnUnmaskVerificationResult(GetRealPanResult result) { } void TestAutofillClient::ConfirmSaveCreditCard(
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h index 1d5ab7ae..fcafd98 100644 --- a/components/autofill/core/browser/test_autofill_client.h +++ b/components/autofill/core/browser/test_autofill_client.h
@@ -30,7 +30,7 @@ void ShowAutofillSettings() override; void ShowUnmaskPrompt(const CreditCard& card, base::WeakPtr<CardUnmaskDelegate> delegate) override; - void OnUnmaskVerificationResult(bool success) override; + void OnUnmaskVerificationResult(GetRealPanResult result) override; void ConfirmSaveCreditCard(const base::Closure& save_card_callback) override; bool HasCreditCardScanFeature() override; void ScanCreditCard(const CreditCardScanCallback& callback) override;
diff --git a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc index 37083c8..3934685 100644 --- a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc +++ b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
@@ -129,8 +129,8 @@ std::string data; source->GetResponseAsString(&data); - // TODO(estade): OAuth2 may fail due to an expired access token, in which case - // we should invalidate the token and try again. How is that failure reported? + std::string real_pan; + AutofillClient::GetRealPanResult result = AutofillClient::SUCCESS; switch (response_code) { // Valid response. @@ -140,24 +140,19 @@ message_value->IsType(base::Value::TYPE_DICTIONARY)) { response_dict.reset( static_cast<base::DictionaryValue*>(message_value.release())); + response_dict->GetString("pan", &real_pan); + if (real_pan.empty()) + result = AutofillClient::TRY_AGAIN_FAILURE; + // TODO(estade): check response for allow_retry. } break; } - // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying. - case net::HTTP_BAD_REQUEST: { - break; - } - - // Response contains an error to show the user. - case net::HTTP_FORBIDDEN: - case net::HTTP_INTERNAL_SERVER_ERROR: { - break; - } - case net::HTTP_UNAUTHORIZED: { - if (has_retried_authorization_) + if (has_retried_authorization_) { + result = AutofillClient::PERMANENT_FAILURE; break; + } has_retried_authorization_ = true; CreateRequest(); @@ -165,21 +160,27 @@ return; } - // Handle anything else as a generic error. - default: + // TODO(estade): is this actually how network connectivity issues are + // reported? + case net::HTTP_REQUEST_TIMEOUT: { + result = AutofillClient::NETWORK_ERROR; break; - } + } - std::string real_pan; - if (response_dict) - response_dict->GetString("pan", &real_pan); + // Handle anything else as a generic (permanent) failure. + default: { + result = AutofillClient::PERMANENT_FAILURE; + break; + } + } if (real_pan.empty()) { - NOTIMPLEMENTED() << "Unhandled error: " << response_code - << " with data: " << data; + LOG(ERROR) << "Wallet returned error: " << response_code + << " with data: " << data; } - delegate_->OnDidGetRealPan(real_pan); + DCHECK_EQ(result != AutofillClient::SUCCESS, real_pan.empty()); + delegate_->OnDidGetRealPan(result, real_pan); } void RealPanWalletClient::OnGetTokenSuccess( @@ -198,13 +199,12 @@ const OAuth2TokenService::Request* request, const GoogleServiceAuthError& error) { DCHECK_EQ(request, access_token_request_.get()); + LOG(ERROR) << "Unhandled OAuth2 error: " << error.ToString(); if (request_) { request_.reset(); - delegate_->OnDidGetRealPan(std::string()); + delegate_->OnDidGetRealPan(AutofillClient::PERMANENT_FAILURE, + std::string()); } - // TODO(estade): what do we do in the failure case? - NOTIMPLEMENTED() << "Unhandled OAuth2 error: " << error.ToString(); - access_token_request_.reset(); } @@ -257,7 +257,7 @@ void RealPanWalletClient::SetOAuth2TokenAndStartRequest() { request_->AddExtraRequestHeader(net::HttpRequestHeaders::kAuthorization + - std::string(": Bearer ") + access_token_); + std::string(": Bearer ") + access_token_); request_->Start(); }
diff --git a/components/autofill/core/browser/wallet/real_pan_wallet_client.h b/components/autofill/core/browser/wallet/real_pan_wallet_client.h index 82dc0b72d..6dd7a2d7 100644 --- a/components/autofill/core/browser/wallet/real_pan_wallet_client.h +++ b/components/autofill/core/browser/wallet/real_pan_wallet_client.h
@@ -7,6 +7,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/card_unmask_delegate.h" #include "components/autofill/core/browser/credit_card.h" #include "google_apis/gaia/oauth2_token_service.h" @@ -36,7 +37,8 @@ // Returns the real PAN retrieved from Wallet. |real_pan| will be empty // on failure. - virtual void OnDidGetRealPan(const std::string& real_pan) = 0; + virtual void OnDidGetRealPan(AutofillClient::GetRealPanResult result, + const std::string& real_pan) = 0; }; // |context_getter| is reference counted so it has no lifetime or ownership
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc index 14fd62e..f05a739e 100644 --- a/components/autofill/core/browser/webdata/autofill_table.cc +++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -189,37 +189,6 @@ return credit_card.Pass(); } -// Obsolete version of AddAutofillProfileNamesToProfile, but still needed -// for MigrateToVersion37MergeAndCullOlderProfiles(). -bool AddAutofillProfileNamesToProfileForVersion37(sql::Connection* db, - AutofillProfile* profile) { - sql::Statement s(db->GetUniqueStatement( - "SELECT guid, first_name, middle_name, last_name " - "FROM autofill_profile_names " - "WHERE guid=?")); - s.BindString(0, profile->guid()); - - if (!s.is_valid()) - return false; - - std::vector<base::string16> first_names; - std::vector<base::string16> middle_names; - std::vector<base::string16> last_names; - while (s.Step()) { - DCHECK_EQ(profile->guid(), s.ColumnString(0)); - first_names.push_back(s.ColumnString16(1)); - middle_names.push_back(s.ColumnString16(2)); - last_names.push_back(s.ColumnString16(3)); - } - if (!s.Succeeded()) - return false; - - profile->SetRawMultiInfo(NAME_FIRST, first_names); - profile->SetRawMultiInfo(NAME_MIDDLE, middle_names); - profile->SetRawMultiInfo(NAME_LAST, last_names); - return true; -} - bool AddAutofillProfileNamesToProfile(sql::Connection* db, AutofillProfile* profile) { sql::Statement s(db->GetUniqueStatement( @@ -298,38 +267,6 @@ return true; } -// Obsolete version of AddAutofillProfileNames needed for -// MigrateToVersion33ProfilesBasedOnFirstName() and -// MigrateToVersion37MergeAndCullOlderProfiles(). -bool AddAutofillProfileNamesForVersion3x( - const AutofillProfile& profile, - sql::Connection* db) { - std::vector<base::string16> first_names; - profile.GetRawMultiInfo(NAME_FIRST, &first_names); - std::vector<base::string16> middle_names; - profile.GetRawMultiInfo(NAME_MIDDLE, &middle_names); - std::vector<base::string16> last_names; - profile.GetRawMultiInfo(NAME_LAST, &last_names); - DCHECK_EQ(first_names.size(), middle_names.size()); - DCHECK_EQ(first_names.size(), last_names.size()); - - for (size_t i = 0; i < first_names.size(); ++i) { - // Add the new name. - sql::Statement s(db->GetUniqueStatement( - "INSERT INTO autofill_profile_names" - " (guid, first_name, middle_name, last_name) " - "VALUES (?,?,?,?)")); - s.BindString(0, profile.guid()); - s.BindString16(1, first_names[i]); - s.BindString16(2, middle_names[i]); - s.BindString16(3, last_names[i]); - - if (!s.Run()) - return false; - } - return true; -} - bool AddAutofillProfileNames(const AutofillProfile& profile, sql::Connection* db) { std::vector<base::string16> first_names; @@ -511,48 +448,6 @@ bool* update_compatible_version) { // Migrate if necessary. switch (version) { - case 22: - return MigrateToVersion22ClearAutofillEmptyValueElements(); - case 23: - return MigrateToVersion23AddCardNumberEncryptedColumn(); - case 24: - return MigrateToVersion24CleanupOversizedStringFields(); - case 27: - *update_compatible_version = true; - return MigrateToVersion27UpdateLegacyCreditCards(); - case 30: - *update_compatible_version = true; - return MigrateToVersion30AddDateModifed(); - case 31: - *update_compatible_version = true; - return MigrateToVersion31AddGUIDToCreditCardsAndProfiles(); - case 32: - *update_compatible_version = true; - return MigrateToVersion32UpdateProfilesAndCreditCards(); - case 33: - *update_compatible_version = true; - return MigrateToVersion33ProfilesBasedOnFirstName(); - case 34: - *update_compatible_version = true; - return MigrateToVersion34ProfilesBasedOnCountryCode(); - case 35: - *update_compatible_version = true; - return MigrateToVersion35GreatBritainCountryCodes(); - // Combine migrations 36 and 37. This is due to enhancements to the merge - // step when migrating profiles. The original migration from 35 to 36 did - // not merge profiles with identical addresses, but the migration from 36 to - // 37 does. The step from 35 to 36 should only happen on the Chrome 12 dev - // channel. Chrome 12 beta and release users will jump from 35 to 37 - // directly getting the full benefits of the multi-valued merge as well as - // the culling of bad data. - case 37: - *update_compatible_version = true; - return MigrateToVersion37MergeAndCullOlderProfiles(); - case 51: - // Combine migrations 50 and 51. The migration code from version 49 to 50 - // worked correctly for users with existing 'origin' columns, but failed - // to create these columns for new users. - return MigrateToVersion51AddOriginColumn(); case 54: *update_compatible_version = true; return MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields(); @@ -574,6 +469,9 @@ case 62: *update_compatible_version = false; return MigrateToVersion62AddUsageStatsForUnmaskedCards(); + case 63: + *update_compatible_version = false; + return MigrateToVersion63AddServerRecipientName(); } return true; } @@ -997,13 +895,13 @@ return s.Succeeded(); } -bool AutofillTable::GetAutofillServerProfiles( - std::vector<AutofillProfile*>* profiles) { +bool AutofillTable::GetServerProfiles(std::vector<AutofillProfile*>* profiles) { profiles->clear(); sql::Statement s(db_->GetUniqueStatement( "SELECT " "id," + "recipient_name," "company_name," "street_address," "address_1," // ADDRESS_HOME_STATE @@ -1021,6 +919,7 @@ scoped_ptr<AutofillProfile> profile(new AutofillProfile( AutofillProfile::SERVER_PROFILE, s.ColumnString(index++))); + base::string16 recipient_name = s.ColumnString16(index++); profile->SetRawInfo(COMPANY_NAME, s.ColumnString16(index++)); profile->SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, s.ColumnString16(index++)); profile->SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(index++)); @@ -1033,13 +932,18 @@ profile->SetRawInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(index++)); profile->set_language_code(s.ColumnString(index++)); + // SetInfo instead of SetRawInfo on the name so the constituent pieces will + // be parsed. + profile->SetInfo(AutofillType(NAME_FULL), recipient_name, + profile->language_code()); + profiles->push_back(profile.release()); } return s.Succeeded(); } -void AutofillTable::SetAutofillServerProfiles( +void AutofillTable::SetServerProfiles( const std::vector<AutofillProfile>& profiles) { // Delete all old ones first. sql::Statement delete_old(db_->GetUniqueStatement( @@ -1049,6 +953,7 @@ sql::Statement insert(db_->GetUniqueStatement( "INSERT INTO server_addresses(" "id," + "recipient_name," "company_name," "street_address," "address_1," // ADDRESS_HOME_STATE @@ -1059,12 +964,13 @@ "sorting_code," // ADDRESS_HOME_SORTING_CODE "country_code," // ADDRESS_HOME_COUNTRY "language_code) " - "VALUES (?,?,?,?,?,?,?,?,?,?,?)")); + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)")); for (const auto& profile : profiles) { DCHECK(profile.record_type() == AutofillProfile::SERVER_PROFILE); int index = 0; insert.BindString(index++, profile.server_id()); + insert.BindString16(index++, profile.GetRawInfo(NAME_FULL)); insert.BindString16(index++, profile.GetRawInfo(COMPANY_NAME)); insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)); @@ -1776,6 +1682,8 @@ bool AutofillTable::InitServerAddressesTable() { if (!db_->DoesTableExist("server_addresses")) { + // The space after language_code is necessary to match what sqlite does + // when it appends the column in migration. if (!db_->Execute("CREATE TABLE server_addresses (" "id VARCHAR," "company_name VARCHAR," @@ -1787,7 +1695,8 @@ "postal_code VARCHAR," "sorting_code VARCHAR," "country_code VARCHAR," - "language_code VARCHAR)")) { + "language_code VARCHAR, " // Space required. + "recipient_name VARCHAR)")) { NOTREACHED(); return false; } @@ -1795,778 +1704,6 @@ return true; } -bool AutofillTable::MigrateToVersion22ClearAutofillEmptyValueElements() { - if (!db_->DoesTableExist("autofill") && - (!db_->Execute("CREATE TABLE autofill (" - " name VARCHAR," - " value VARCHAR," - " value_lower VARCHAR," - " pair_id INTEGER PRIMARY KEY," - " count INTEGER DEFAULT 1)") || - !db_->Execute("CREATE INDEX autofill_name ON autofill (name)") || - !db_->Execute("CREATE INDEX autofill_name_value_lower ON" - " autofill (name, value_lower)") || - !db_->Execute("CREATE TABLE autofill_dates (" - " pair_id INTEGER DEFAULT 0," - " date_created INTEGER DEFAULT 0)") || - !db_->Execute("CREATE INDEX autofill_dates_pair_id ON" - " autofill (pair_id)"))) - return false; - - - sql::Statement s(db_->GetUniqueStatement( - "SELECT pair_id FROM autofill WHERE TRIM(value) = \"\"")); - if (!s.is_valid()) - return false; - - std::set<int64> ids; - while (s.Step()) - ids.insert(s.ColumnInt64(0)); - if (!s.Succeeded()) - return false; - - if (!db_->Execute("DELETE FROM autofill WHERE TRIM(value) = \"\"")) - return false; - - for (std::set<int64>::const_iterator it = ids.begin(); it != ids.end(); - ++it) { - sql::Statement s(db_->GetUniqueStatement( - "DELETE FROM autofill_dates WHERE pair_id = ?")); - s.BindInt64(0, *it); - if (!s.Run()) - return false; - } - - return true; -} - -// Add the card_number_encrypted column if credit card table was not -// created in this build (otherwise the column already exists). -// WARNING: Do not change the order of the execution of the SQL -// statements in this case! Profile corruption and data migration -// issues WILL OCCUR. See http://crbug.com/10913 -// -// The problem is that if a user has a profile which was created before -// r37036, when the credit_cards table was added, and then failed to -// update this profile between the credit card addition and the addition -// of the "encrypted" columns (44963), the next data migration will put -// the user's profile in an incoherent state: The user will update from -// a data profile set to be earlier than 22, and therefore pass through -// this update case. But because the user did not have a credit_cards -// table before starting Chrome, it will have just been initialized -// above, and so already have these columns -- and thus this data -// update step will have failed. -// -// The false assumption in this case is that at this step in the -// migration, the user has a credit card table, and that this -// table does not include encrypted columns! -// Because this case does not roll back the complete set of SQL -// transactions properly in case of failure (that is, it does not -// roll back the table initialization done above), the incoherent -// profile will now see itself as being at version 22 -- but include a -// fully initialized credit_cards table. Every time Chrome runs, it -// will try to update the web database and fail at this step, unless -// we allow for the faulty assumption described above by checking for -// the existence of the columns only AFTER we've executed the commands -// to add them. -bool AutofillTable::MigrateToVersion23AddCardNumberEncryptedColumn() { - if (!db_->DoesTableExist("autofill_profiles") && - (!db_->Execute("CREATE TABLE autofill_profiles ( " - "label VARCHAR, " - "unique_id INTEGER PRIMARY KEY, " - "first_name VARCHAR, " - "middle_name VARCHAR, " - "last_name VARCHAR, " - "email VARCHAR, " - "company_name VARCHAR, " - "address_line_1 VARCHAR, " - "address_line_2 VARCHAR, " - "city VARCHAR, " - "state VARCHAR, " - "zipcode VARCHAR, " - "country VARCHAR, " - "phone VARCHAR, " - "fax VARCHAR)") || - !db_->Execute("CREATE INDEX autofill_profiles_label_index" - " ON autofill_profiles (label)"))) - return false; - - if (!db_->DoesTableExist("credit_cards") && - (!db_->Execute("CREATE TABLE credit_cards ( " - "label VARCHAR, " - "unique_id INTEGER PRIMARY KEY, " - "name_on_card VARCHAR, " - "type VARCHAR, " - "card_number VARCHAR, " - "expiration_month INTEGER, " - "expiration_year INTEGER, " - "verification_code VARCHAR, " - "billing_address VARCHAR, " - "shipping_address VARCHAR)") || - !db_->Execute("CREATE INDEX credit_cards_label_index" - " ON credit_cards (label)"))) - return false; - - if (!db_->DoesColumnExist("credit_cards", "card_number_encrypted")) { - if (!db_->Execute("ALTER TABLE credit_cards ADD COLUMN " - "card_number_encrypted BLOB DEFAULT NULL")) { - return false; - } - } - - if (!db_->DoesColumnExist("credit_cards", "verification_code_encrypted")) { - if (!db_->Execute("ALTER TABLE credit_cards ADD COLUMN " - "verification_code_encrypted BLOB DEFAULT NULL")) { - return false; - } - } - - return true; -} - -// One-time cleanup for http://crbug.com/38364 - In the presence of -// multi-byte UTF-8 characters, that bug could cause Autofill strings -// to grow larger and more corrupt with each save. The cleanup removes -// any row with a string field larger than a reasonable size. The string -// fields examined here are precisely the ones that were subject to -// corruption by the original bug. -bool AutofillTable::MigrateToVersion24CleanupOversizedStringFields() { - const std::string autofill_is_too_big = - "max(length(name), length(value)) > 500"; - - const std::string credit_cards_is_too_big = - "max(length(label), length(name_on_card), length(type), " - " length(expiration_month), length(expiration_year), " - " length(billing_address), length(shipping_address) " - ") > 500"; - - const std::string autofill_profiles_is_too_big = - "max(length(label), length(first_name), " - " length(middle_name), length(last_name), length(email), " - " length(company_name), length(address_line_1), " - " length(address_line_2), length(city), length(state), " - " length(zipcode), length(country), length(phone)) > 500"; - - std::string query = "DELETE FROM autofill_dates WHERE pair_id IN (" - "SELECT pair_id FROM autofill WHERE " + autofill_is_too_big + ")"; - - if (!db_->Execute(query.c_str())) - return false; - - query = "DELETE FROM autofill WHERE " + autofill_is_too_big; - - if (!db_->Execute(query.c_str())) - return false; - - // Only delete from legacy credit card tables where specific columns exist. - if (db_->DoesColumnExist("credit_cards", "label") && - db_->DoesColumnExist("credit_cards", "name_on_card") && - db_->DoesColumnExist("credit_cards", "type") && - db_->DoesColumnExist("credit_cards", "expiration_month") && - db_->DoesColumnExist("credit_cards", "expiration_year") && - db_->DoesColumnExist("credit_cards", "billing_address") && - db_->DoesColumnExist("credit_cards", "shipping_address") && - db_->DoesColumnExist("autofill_profiles", "label")) { - query = "DELETE FROM credit_cards WHERE (" + credit_cards_is_too_big + - ") OR label IN (SELECT label FROM autofill_profiles WHERE " + - autofill_profiles_is_too_big + ")"; - - if (!db_->Execute(query.c_str())) - return false; - } - - if (db_->DoesColumnExist("autofill_profiles", "label")) { - query = "DELETE FROM autofill_profiles WHERE " + - autofill_profiles_is_too_big; - - if (!db_->Execute(query.c_str())) - return false; - } - - return true; -} - -// Change the credit_cards.billing_address column from a string to an -// int. The stored string is the label of an address, so we have to -// select the unique ID of this address using the label as a foreign -// key into the |autofill_profiles| table. -bool AutofillTable::MigrateToVersion27UpdateLegacyCreditCards() { - // Only migrate from legacy credit card tables where specific columns - // exist. - if (!(db_->DoesColumnExist("credit_cards", "unique_id") && - db_->DoesColumnExist("credit_cards", "billing_address") && - db_->DoesColumnExist("autofill_profiles", "unique_id"))) { - return true; - } - - std::string stmt = - "SELECT credit_cards.unique_id, autofill_profiles.unique_id " - "FROM autofill_profiles, credit_cards " - "WHERE credit_cards.billing_address = autofill_profiles.label"; - sql::Statement s(db_->GetUniqueStatement(stmt.c_str())); - - std::map<int, int> cc_billing_map; - while (s.Step()) - cc_billing_map[s.ColumnInt(0)] = s.ColumnInt(1); - if (!s.Succeeded()) - return false; - - // Windows already stores the IDs as strings in |billing_address|. Try - // to convert those. - if (cc_billing_map.empty()) { - std::string stmt = "SELECT unique_id,billing_address FROM credit_cards"; - sql::Statement s(db_->GetUniqueStatement(stmt.c_str())); - - while (s.Step()) { - int id = 0; - if (base::StringToInt(s.ColumnString(1), &id)) - cc_billing_map[s.ColumnInt(0)] = id; - } - if (!s.Succeeded()) - return false; - } - - if (!db_->Execute("CREATE TABLE credit_cards_temp ( " - "label VARCHAR, " - "unique_id INTEGER PRIMARY KEY, " - "name_on_card VARCHAR, " - "type VARCHAR, " - "card_number VARCHAR, " - "expiration_month INTEGER, " - "expiration_year INTEGER, " - "verification_code VARCHAR, " - "billing_address INTEGER, " - "shipping_address VARCHAR, " - "card_number_encrypted BLOB, " - "verification_code_encrypted BLOB)")) { - return false; - } - - if (!db_->Execute( - "INSERT INTO credit_cards_temp " - "SELECT label,unique_id,name_on_card,type,card_number," - "expiration_month,expiration_year,verification_code,0," - "shipping_address,card_number_encrypted," - "verification_code_encrypted FROM credit_cards")) { - return false; - } - - if (!db_->Execute("DROP TABLE credit_cards")) - return false; - - if (!db_->Execute("ALTER TABLE credit_cards_temp RENAME TO credit_cards")) - return false; - - for (std::map<int, int>::const_iterator iter = cc_billing_map.begin(); - iter != cc_billing_map.end(); ++iter) { - sql::Statement s(db_->GetCachedStatement( - SQL_FROM_HERE, - "UPDATE credit_cards SET billing_address=? WHERE unique_id=?")); - s.BindInt(0, (*iter).second); - s.BindInt(1, (*iter).first); - - if (!s.Run()) - return false; - } - - return true; -} - -bool AutofillTable::MigrateToVersion30AddDateModifed() { - // Add date_modified to autofill_profiles. - if (!db_->DoesColumnExist("autofill_profiles", "date_modified")) { - if (!db_->Execute("ALTER TABLE autofill_profiles ADD COLUMN " - "date_modified INTEGER NON NULL DEFAULT 0")) { - return false; - } - - sql::Statement s(db_->GetUniqueStatement( - "UPDATE autofill_profiles SET date_modified=?")); - s.BindInt64(0, Time::Now().ToTimeT()); - - if (!s.Run()) - return false; - } - - // Add date_modified to credit_cards. - if (!db_->DoesColumnExist("credit_cards", "date_modified")) { - if (!db_->Execute("ALTER TABLE credit_cards ADD COLUMN " - "date_modified INTEGER NON NULL DEFAULT 0")) { - return false; - } - - sql::Statement s(db_->GetUniqueStatement( - "UPDATE credit_cards SET date_modified=?")); - s.BindInt64(0, Time::Now().ToTimeT()); - - if (!s.Run()) - return false; - } - - return true; -} - -bool AutofillTable::MigrateToVersion31AddGUIDToCreditCardsAndProfiles() { - // Note that we need to check for the guid column's existence due to the - // fact that for a version 22 database the |autofill_profiles| table - // gets created fresh with |InitAutofillProfilesTable|. - if (!db_->DoesColumnExist("autofill_profiles", "guid")) { - if (!db_->Execute("ALTER TABLE autofill_profiles ADD COLUMN " - "guid VARCHAR NOT NULL DEFAULT \"\"")) { - return false; - } - - // Set all the |guid| fields to valid values. - - sql::Statement s(db_->GetUniqueStatement("SELECT unique_id " - "FROM autofill_profiles")); - - while (s.Step()) { - sql::Statement update_s( - db_->GetUniqueStatement("UPDATE autofill_profiles " - "SET guid=? WHERE unique_id=?")); - update_s.BindString(0, base::GenerateGUID()); - update_s.BindInt(1, s.ColumnInt(0)); - - if (!update_s.Run()) - return false; - } - if (!s.Succeeded()) - return false; - } - - // Note that we need to check for the guid column's existence due to the - // fact that for a version 22 database the |autofill_profiles| table - // gets created fresh with |InitAutofillProfilesTable|. - if (!db_->DoesColumnExist("credit_cards", "guid")) { - if (!db_->Execute("ALTER TABLE credit_cards ADD COLUMN " - "guid VARCHAR NOT NULL DEFAULT \"\"")) { - return false; - } - - // Set all the |guid| fields to valid values. - - sql::Statement s(db_->GetUniqueStatement("SELECT unique_id " - "FROM credit_cards")); - - while (s.Step()) { - sql::Statement update_s( - db_->GetUniqueStatement("UPDATE credit_cards " - "set guid=? WHERE unique_id=?")); - update_s.BindString(0, base::GenerateGUID()); - update_s.BindInt(1, s.ColumnInt(0)); - - if (!update_s.Run()) - return false; - } - if (!s.Succeeded()) - return false; - } - - return true; -} - -bool AutofillTable::MigrateToVersion32UpdateProfilesAndCreditCards() { - if (db_->DoesColumnExist("autofill_profiles", "unique_id")) { - if (!db_->Execute("CREATE TABLE autofill_profiles_temp ( " - "guid VARCHAR PRIMARY KEY, " - "label VARCHAR, " - "first_name VARCHAR, " - "middle_name VARCHAR, " - "last_name VARCHAR, " - "email VARCHAR, " - "company_name VARCHAR, " - "address_line_1 VARCHAR, " - "address_line_2 VARCHAR, " - "city VARCHAR, " - "state VARCHAR, " - "zipcode VARCHAR, " - "country VARCHAR, " - "phone VARCHAR, " - "date_modified INTEGER NOT NULL DEFAULT 0)")) { - return false; - } - - if (!db_->Execute( - "INSERT INTO autofill_profiles_temp " - "SELECT guid, label, first_name, middle_name, last_name, email, " - "company_name, address_line_1, address_line_2, city, state, " - "zipcode, country, phone, date_modified " - "FROM autofill_profiles")) { - return false; - } - - if (!db_->Execute("DROP TABLE autofill_profiles")) - return false; - - if (!db_->Execute( - "ALTER TABLE autofill_profiles_temp RENAME TO autofill_profiles")) { - return false; - } - } - - if (db_->DoesColumnExist("credit_cards", "unique_id")) { - if (!db_->Execute("CREATE TABLE credit_cards_temp ( " - "guid VARCHAR PRIMARY KEY, " - "label VARCHAR, " - "name_on_card VARCHAR, " - "expiration_month INTEGER, " - "expiration_year INTEGER, " - "card_number_encrypted BLOB, " - "date_modified INTEGER NOT NULL DEFAULT 0)")) { - return false; - } - - if (!db_->Execute( - "INSERT INTO credit_cards_temp " - "SELECT guid, label, name_on_card, expiration_month, " - "expiration_year, card_number_encrypted, date_modified " - "FROM credit_cards")) { - return false; - } - - if (!db_->Execute("DROP TABLE credit_cards")) - return false; - - if (!db_->Execute("ALTER TABLE credit_cards_temp RENAME TO credit_cards")) - return false; - } - - return true; -} - -// Test the existence of the |first_name| column as an indication that -// we need a migration. It is possible that the new |autofill_profiles| -// schema is in place because the table was newly created when migrating -// from a pre-version-22 database. -bool AutofillTable::MigrateToVersion33ProfilesBasedOnFirstName() { - if (!db_->DoesTableExist("autofill_profile_names") && - !db_->Execute("CREATE TABLE autofill_profile_names ( " - "guid VARCHAR, " - "first_name VARCHAR, " - "middle_name VARCHAR, " - "last_name VARCHAR)")) - return false; - - if (!db_->DoesTableExist("autofill_profile_emails") && - !db_->Execute("CREATE TABLE autofill_profile_emails ( " - "guid VARCHAR, " - "email VARCHAR)")) - return false; - - if (!db_->DoesTableExist("autofill_profile_phones") && - !db_->Execute("CREATE TABLE autofill_profile_phones ( " - "guid VARCHAR, " - "type INTEGER DEFAULT 0, " - "number VARCHAR)")) - return false; - - if (db_->DoesColumnExist("autofill_profiles", "first_name")) { - // Create autofill_profiles_temp table that will receive the data. - if (!db_->DoesTableExist("autofill_profiles_temp")) { - if (!db_->Execute("CREATE TABLE autofill_profiles_temp ( " - "guid VARCHAR PRIMARY KEY, " - "company_name VARCHAR, " - "address_line_1 VARCHAR, " - "address_line_2 VARCHAR, " - "city VARCHAR, " - "state VARCHAR, " - "zipcode VARCHAR, " - "country VARCHAR, " - "date_modified INTEGER NOT NULL DEFAULT 0)")) { - return false; - } - } - - sql::Statement s(db_->GetUniqueStatement( - "SELECT guid, first_name, middle_name, last_name, email, " - "company_name, address_line_1, address_line_2, city, state, " - "zipcode, country, phone, date_modified " - "FROM autofill_profiles")); - - while (s.Step()) { - AutofillProfile profile; - int index = 0; - profile.set_guid(s.ColumnString(index++)); - DCHECK(base::IsValidGUID(profile.guid())); - - profile.SetRawInfo(NAME_FIRST, s.ColumnString16(index++)); - profile.SetRawInfo(NAME_MIDDLE, s.ColumnString16(index++)); - profile.SetRawInfo(NAME_LAST, s.ColumnString16(index++)); - profile.SetRawInfo(EMAIL_ADDRESS, s.ColumnString16(index++)); - profile.SetRawInfo(COMPANY_NAME, s.ColumnString16(index++)); - profile.SetRawInfo(ADDRESS_HOME_LINE1, s.ColumnString16(index++)); - profile.SetRawInfo(ADDRESS_HOME_LINE2, s.ColumnString16(index++)); - profile.SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(index++)); - profile.SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(index++)); - profile.SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(index++)); - profile.SetInfo(AutofillType(ADDRESS_HOME_COUNTRY), - s.ColumnString16(index++), app_locale_); - profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, s.ColumnString16(index++)); - int64 date_modified = s.ColumnInt64(index++); - - sql::Statement s_insert(db_->GetUniqueStatement( - "INSERT INTO autofill_profiles_temp" - "(guid, company_name, address_line_1, address_line_2, city," - " state, zipcode, country, date_modified)" - "VALUES (?,?,?,?,?,?,?,?,?)")); - index = 0; - s_insert.BindString(index++, profile.guid()); - s_insert.BindString16(index++, profile.GetRawInfo(COMPANY_NAME)); - s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_LINE1)); - s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_LINE2)); - s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_CITY)); - s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_STATE)); - s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_ZIP)); - s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_COUNTRY)); - s_insert.BindInt64(index++, date_modified); - - if (!s_insert.Run()) - return false; - - // Add the other bits: names, emails, and phone numbers. - if (!AddAutofillProfileNamesForVersion3x(profile, db_) || - !AddAutofillProfileEmails(profile, db_) || - !AddAutofillProfilePhones(profile, db_)) { - return false; - } - } // endwhile - if (!s.Succeeded()) - return false; - - if (!db_->Execute("DROP TABLE autofill_profiles")) - return false; - - if (!db_->Execute( - "ALTER TABLE autofill_profiles_temp RENAME TO autofill_profiles")) { - return false; - } - } - - // Remove the labels column from the credit_cards table. - if (db_->DoesColumnExist("credit_cards", "label")) { - if (!db_->Execute("CREATE TABLE credit_cards_temp ( " - "guid VARCHAR PRIMARY KEY, " - "name_on_card VARCHAR, " - "expiration_month INTEGER, " - "expiration_year INTEGER, " - "card_number_encrypted BLOB, " - "date_modified INTEGER NOT NULL DEFAULT 0)")) { - return false; - } - - if (!db_->Execute( - "INSERT INTO credit_cards_temp " - "SELECT guid, name_on_card, expiration_month, " - "expiration_year, card_number_encrypted, date_modified " - "FROM credit_cards")) { - return false; - } - - if (!db_->Execute("DROP TABLE credit_cards")) - return false; - - if (!db_->Execute("ALTER TABLE credit_cards_temp RENAME TO credit_cards")) - return false; - } - - return true; -} - -// Test the existence of the |country_code| column as an indication that -// we need a migration. It is possible that the new |autofill_profiles| -// schema is in place because the table was newly created when migrating -// from a pre-version-22 database. -bool AutofillTable::MigrateToVersion34ProfilesBasedOnCountryCode() { - if (!db_->DoesColumnExist("autofill_profiles", "country_code")) { - if (!db_->Execute("ALTER TABLE autofill_profiles ADD COLUMN " - "country_code VARCHAR")) { - return false; - } - - // Set all the |country_code| fields to match existing |country| values. - sql::Statement s(db_->GetUniqueStatement("SELECT guid, country " - "FROM autofill_profiles")); - - while (s.Step()) { - sql::Statement update_s( - db_->GetUniqueStatement("UPDATE autofill_profiles " - "SET country_code=? WHERE guid=?")); - - base::string16 country = s.ColumnString16(1); - update_s.BindString(0, AutofillCountry::GetCountryCode(country, - app_locale_)); - update_s.BindString(1, s.ColumnString(0)); - - if (!update_s.Run()) - return false; - } - if (!s.Succeeded()) - return false; - } - - return true; -} - -// Correct all country codes with value "UK" to be "GB". This data -// was mistakenly introduced in build 686.0. This migration is to clean -// it up. See http://crbug.com/74511 for details. -bool AutofillTable::MigrateToVersion35GreatBritainCountryCodes() { - sql::Statement s(db_->GetUniqueStatement( - "UPDATE autofill_profiles SET country_code=\"GB\" " - "WHERE country_code=\"UK\"")); - - return s.Run(); -} - -// Merge and cull older profiles where possible. -bool AutofillTable::MigrateToVersion37MergeAndCullOlderProfiles() { - if (!db_->DoesTableExist("autofill_profiles_trash") && - !db_->Execute("CREATE TABLE autofill_profiles_trash (guid VARCHAR)")) - return false; - - sql::Statement s(db_->GetUniqueStatement( - "SELECT guid, date_modified FROM autofill_profiles")); - - // Accumulate the good profiles. - std::vector<AutofillProfile> accumulated_profiles; - std::vector<AutofillProfile*> accumulated_profiles_p; - std::map<std::string, int64> modification_map; - while (s.Step()) { - std::string guid = s.ColumnString(0); - int64 date_modified = s.ColumnInt64(1); - modification_map.insert( - std::pair<std::string, int64>(guid, date_modified)); - - sql::Statement s(db_->GetUniqueStatement( - "SELECT guid, company_name, address_line_1, address_line_2, city, " - " state, zipcode, country, country_code, date_modified " - "FROM autofill_profiles " - "WHERE guid=?")); - s.BindString(0, guid); - - if (!s.Step()) - return false; - - scoped_ptr<AutofillProfile> profile(new AutofillProfile); - int index = 0; - profile->set_guid(s.ColumnString(index++)); - DCHECK(base::IsValidGUID(profile->guid())); - - profile->SetRawInfo(COMPANY_NAME, s.ColumnString16(index++)); - profile->SetRawInfo(ADDRESS_HOME_LINE1, s.ColumnString16(index++)); - profile->SetRawInfo(ADDRESS_HOME_LINE2, s.ColumnString16(index++)); - profile->SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(index++)); - profile->SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(index++)); - profile->SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(index++)); - // Intentionally skip column 7, which stores the localized country name. - index++; - profile->SetRawInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(index++)); - profile->set_modification_date( - base::Time::FromTimeT(s.ColumnInt64(index++))); - profile->set_origin(s.ColumnString(index++)); - - // Get associated name info. - AddAutofillProfileNamesToProfileForVersion37(db_, profile.get()); - - // Get associated email info. - AddAutofillProfileEmailsToProfile(db_, profile.get()); - - // Get associated phone info. - AddAutofillProfilePhonesToProfile(db_, profile.get()); - - if (PersonalDataManager::IsValidLearnableProfile(*profile, app_locale_)) { - std::vector<AutofillProfile> merged_profiles; - std::string merged_guid = PersonalDataManager::MergeProfile( - *profile, accumulated_profiles_p, app_locale_, &merged_profiles); - - std::swap(accumulated_profiles, merged_profiles); - - accumulated_profiles_p.clear(); - accumulated_profiles_p.resize(accumulated_profiles.size()); - std::transform(accumulated_profiles.begin(), - accumulated_profiles.end(), - accumulated_profiles_p.begin(), - address_of<AutofillProfile>); - - // If the profile got merged trash the original. - if (merged_guid != profile->guid()) - AddAutofillGUIDToTrash(profile->guid()); - } else { - // An invalid profile, so trash it. - AddAutofillGUIDToTrash(profile->guid()); - } - } // endwhile - if (!s.Succeeded()) - return false; - - // Drop the current profiles. - if (!ClearAutofillProfiles()) - return false; - - // Add the newly merged profiles back in. - for (std::vector<AutofillProfile>::const_iterator - iter = accumulated_profiles.begin(); - iter != accumulated_profiles.end(); - ++iter) { - // Save the profile with its original modification date. - std::map<std::string, int64>::const_iterator date_item = - modification_map.find(iter->guid()); - if (date_item == modification_map.end()) - return false; - - sql::Statement s(db_->GetUniqueStatement( - "INSERT INTO autofill_profiles" - "(guid, company_name, address_line_1, address_line_2, city, state," - " zipcode, country, country_code, date_modified)" - "VALUES (?,?,?,?,?,?,?,?,?,?)")); - int index = 0; - s.BindString(index++, iter->guid()); - s.BindString16(index++, GetInfo(*iter, COMPANY_NAME)); - s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_LINE1)); - s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_LINE2)); - s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_CITY)); - s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_STATE)); - s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_ZIP)); - s.BindString16(index++, base::string16()); // This column is deprecated. - s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_COUNTRY)); - s.BindInt64(index++, date_item->second); - - if (!s.Run()) - return false; - - if (!AddAutofillProfileNamesForVersion3x(*iter, db_) || - !AddAutofillProfileEmails(*iter, db_) || - !AddAutofillProfilePhones(*iter, db_)) { - return false; - } - } - - return true; -} - -bool AutofillTable::MigrateToVersion51AddOriginColumn() { - sql::Transaction transaction(db_); - if (!transaction.Begin()) - return false; - - // Add origin to autofill_profiles. - if (!db_->DoesColumnExist("autofill_profiles", "origin") && - !db_->Execute("ALTER TABLE autofill_profiles " - "ADD COLUMN origin VARCHAR DEFAULT ''")) { - return false; - } - - // Add origin to credit_cards. - if (!db_->DoesColumnExist("credit_cards", "origin") && - !db_->Execute("ALTER TABLE credit_cards " - "ADD COLUMN origin VARCHAR DEFAULT ''")) { - return false; - } - - return transaction.Commit(); -} - bool AutofillTable::MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields() { sql::Transaction transaction(db_); if (!transaction.Begin()) @@ -2843,4 +1980,13 @@ return transaction.Commit(); } +bool AutofillTable::MigrateToVersion63AddServerRecipientName() { + if (!db_->DoesColumnExist("server_addresses", "recipient_name") && + !db_->Execute("ALTER TABLE server_addresses ADD COLUMN " + "recipient_name VARCHAR")) { + return false; + } + return true; +} + } // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_table.h b/components/autofill/core/browser/webdata/autofill_table.h index a25006a7..3f8093c 100644 --- a/components/autofill/core/browser/webdata/autofill_table.h +++ b/components/autofill/core/browser/webdata/autofill_table.h
@@ -174,6 +174,7 @@ // // id String assigned by the server to identify this address. // This is opaque to the client. +// recipient_name Added in v63. // company_name // street_address The combined lines of the street address. // address_1 Also known as "administrative area". This is normally @@ -280,12 +281,11 @@ // Retrieves local/server profiles in the database. Caller owns the returned // profiles. virtual bool GetAutofillProfiles(std::vector<AutofillProfile*>* profiles); - virtual bool GetAutofillServerProfiles( - std::vector<AutofillProfile*>* profiles); + virtual bool GetServerProfiles(std::vector<AutofillProfile*>* profiles); // Sets the server profiles. All old profiles are deleted and replaced with // the given ones. - void SetAutofillServerProfiles(const std::vector<AutofillProfile>& profiles); + void SetServerProfiles(const std::vector<AutofillProfile>& profiles); // Records a single credit card in the credit_cards table. bool AddCreditCard(const CreditCard& credit_card); @@ -358,20 +358,6 @@ bool ClearAutofillProfiles(); // Table migration functions. - // Removes empty values for autofill that were incorrectly stored in the DB - // See bug http://crbug.com/6111 - bool MigrateToVersion22ClearAutofillEmptyValueElements(); - bool MigrateToVersion23AddCardNumberEncryptedColumn(); - bool MigrateToVersion24CleanupOversizedStringFields(); - bool MigrateToVersion27UpdateLegacyCreditCards(); - bool MigrateToVersion30AddDateModifed(); - bool MigrateToVersion31AddGUIDToCreditCardsAndProfiles(); - bool MigrateToVersion32UpdateProfilesAndCreditCards(); - bool MigrateToVersion33ProfilesBasedOnFirstName(); - bool MigrateToVersion34ProfilesBasedOnCountryCode(); - bool MigrateToVersion35GreatBritainCountryCodes(); - bool MigrateToVersion37MergeAndCullOlderProfiles(); - bool MigrateToVersion51AddOriginColumn(); bool MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields(); bool MigrateToVersion55MergeAutofillDatesTable(); bool MigrateToVersion56AddProfileLanguageCodeForFormatting(); @@ -379,6 +365,7 @@ bool MigrateToVersion60AddServerCards(); bool MigrateToVersion61AddUsageStats(); bool MigrateToVersion62AddUsageStatsForUnmaskedCards(); + bool MigrateToVersion63AddServerRecipientName(); // Max data length saved in the table; static const size_t kMaxDataLength;
diff --git a/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/components/autofill/core/browser/webdata/autofill_table_unittest.cc index 75eec07..2624daa 100644 --- a/components/autofill/core/browser/webdata/autofill_table_unittest.cc +++ b/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -1768,10 +1768,10 @@ AutofillProfile one(AutofillProfile::SERVER_PROFILE, "a123"); std::vector<AutofillProfile> inputs; inputs.push_back(one); - table_->SetAutofillServerProfiles(inputs); + table_->SetServerProfiles(inputs); std::vector<AutofillProfile*> outputs; - table_->GetAutofillServerProfiles(&outputs); + table_->GetServerProfiles(&outputs); ASSERT_EQ(1u, outputs.size()); EXPECT_EQ(one.server_id(), outputs[0]->server_id()); @@ -1781,10 +1781,10 @@ // Set a different profile. AutofillProfile two(AutofillProfile::SERVER_PROFILE, "b456"); inputs[0] = two; - table_->SetAutofillServerProfiles(inputs); + table_->SetServerProfiles(inputs); // The original one should have been replaced. - table_->GetAutofillServerProfiles(&outputs); + table_->GetServerProfiles(&outputs); ASSERT_EQ(1u, outputs.size()); EXPECT_EQ(two.server_id(), outputs[0]->server_id());
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc index a99b3751..4a8e60fd 100644 --- a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc +++ b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
@@ -84,6 +84,7 @@ profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, base::UTF8ToUTF16(JoinString(street_address, '\n'))); + profile.SetRawInfo(NAME_FULL, base::UTF8ToUTF16(address.recipient_name())); profile.SetRawInfo(COMPANY_NAME, base::UTF8ToUTF16(address.company_name())); profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16(address.address_1())); @@ -259,10 +260,8 @@ &AutofillTable::SetServerCreditCards, &prev_card_count); bool changed_addresses = SetDataIfChanged( - table, wallet_addresses, - &AutofillTable::GetAutofillServerProfiles, - &AutofillTable::SetAutofillServerProfiles, - &prev_address_count); + table, wallet_addresses, &AutofillTable::GetServerProfiles, + &AutofillTable::SetServerProfiles, &prev_address_count); syncer::SyncMergeResult merge_result(syncer::AUTOFILL_WALLET_DATA); merge_result.set_num_items_before_association(
diff --git a/components/autofill/core/browser/webdata/autofill_webdata.h b/components/autofill/core/browser/webdata/autofill_webdata.h index 1687357..2cf04ef2 100644 --- a/components/autofill/core/browser/webdata/autofill_webdata.h +++ b/components/autofill/core/browser/webdata/autofill_webdata.h
@@ -75,7 +75,7 @@ // consumer owns the profiles. virtual WebDataServiceBase::Handle GetAutofillProfiles( WebDataServiceConsumer* consumer) = 0; - virtual WebDataServiceBase::Handle GetAutofillServerProfiles( + virtual WebDataServiceBase::Handle GetServerProfiles( WebDataServiceConsumer* consumer) = 0; // Schedules a task to update autofill entries in the web database.
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc index f9a3579..6587745 100644 --- a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc +++ b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
@@ -245,11 +245,11 @@ base::Unretained(this)))); } -scoped_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetAutofillServerProfiles( +scoped_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetServerProfiles( WebDatabase* db) { DCHECK(db_thread_->BelongsToCurrentThread()); std::vector<AutofillProfile*> profiles; - AutofillTable::FromWebDatabase(db)->GetAutofillServerProfiles(&profiles); + AutofillTable::FromWebDatabase(db)->GetServerProfiles(&profiles); return scoped_ptr<WDTypedResult>( new WDDestroyableResult<std::vector<AutofillProfile*> >( AUTOFILL_PROFILES_RESULT,
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h index 6fc052b..027abbf8 100644 --- a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h +++ b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
@@ -112,7 +112,7 @@ // Returns the local/server Autofill profiles from the web database. scoped_ptr<WDTypedResult> GetAutofillProfiles(WebDatabase* db); - scoped_ptr<WDTypedResult> GetAutofillServerProfiles(WebDatabase* db); + scoped_ptr<WDTypedResult> GetServerProfiles(WebDatabase* db); // Updates Autofill entries in the web database. WebDatabase::State UpdateAutofillEntries(
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_service.cc b/components/autofill/core/browser/webdata/autofill_webdata_service.cc index 2296f35..2f0e7e2 100644 --- a/components/autofill/core/browser/webdata/autofill_webdata_service.cc +++ b/components/autofill/core/browser/webdata/autofill_webdata_service.cc
@@ -129,11 +129,11 @@ consumer); } -WebDataServiceBase::Handle AutofillWebDataService::GetAutofillServerProfiles( +WebDataServiceBase::Handle AutofillWebDataService::GetServerProfiles( WebDataServiceConsumer* consumer) { - return wdbs_->ScheduleDBTaskWithResult(FROM_HERE, - Bind(&AutofillWebDataBackendImpl::GetAutofillServerProfiles, - autofill_backend_), + return wdbs_->ScheduleDBTaskWithResult( + FROM_HERE, + Bind(&AutofillWebDataBackendImpl::GetServerProfiles, autofill_backend_), consumer); }
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_service.h b/components/autofill/core/browser/webdata/autofill_webdata_service.h index 501a43c..1b9d5bc2 100644 --- a/components/autofill/core/browser/webdata/autofill_webdata_service.h +++ b/components/autofill/core/browser/webdata/autofill_webdata_service.h
@@ -72,7 +72,7 @@ WebDataServiceConsumer* consumer) override; // Server profiles. - WebDataServiceBase::Handle GetAutofillServerProfiles( + WebDataServiceBase::Handle GetServerProfiles( WebDataServiceConsumer* consumer) override; void UpdateAutofillEntries(
diff --git a/components/autofill/core/common/save_password_progress_logger.cc b/components/autofill/core/common/save_password_progress_logger.cc index 25f9f56..098c6e2 100644 --- a/components/autofill/core/common/save_password_progress_logger.cc +++ b/components/autofill/core/common/save_password_progress_logger.cc
@@ -133,6 +133,8 @@ return "Form manager found, exact match"; case SavePasswordProgressLogger::STRING_MATCH_WITHOUT_ACTION: return "Form manager found, match except for action"; + case SavePasswordProgressLogger::STRING_ORIGINS_MATCH: + return "Form manager found, only origins match"; case SavePasswordProgressLogger::STRING_MATCHING_NOT_COMPLETE: return "No form manager has completed matching"; case SavePasswordProgressLogger::STRING_FORM_BLACKLISTED:
diff --git a/components/autofill/core/common/save_password_progress_logger.h b/components/autofill/core/common/save_password_progress_logger.h index 3706c0b..3dd9098 100644 --- a/components/autofill/core/common/save_password_progress_logger.h +++ b/components/autofill/core/common/save_password_progress_logger.h
@@ -84,6 +84,7 @@ STRING_EMPTY_PASSWORD, STRING_EXACT_MATCH, STRING_MATCH_WITHOUT_ACTION, + STRING_ORIGINS_MATCH, STRING_MATCHING_NOT_COMPLETE, STRING_FORM_BLACKLISTED, STRING_INVALID_FORM,
diff --git a/components/autofill/ios/DEPS b/components/autofill/ios/DEPS new file mode 100644 index 0000000..450c6e9 --- /dev/null +++ b/components/autofill/ios/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+ios/public/provider/web", + "+ios/web/public", +]
diff --git a/components/autofill/ios/OWNERS b/components/autofill/ios/OWNERS new file mode 100644 index 0000000..ca512d20e --- /dev/null +++ b/components/autofill/ios/OWNERS
@@ -0,0 +1 @@ +jdonnelly@chromium.org
diff --git a/components/autofill/ios/browser/autofill_driver_ios.h b/components/autofill/ios/browser/autofill_driver_ios.h new file mode 100644 index 0000000..1b670f7 --- /dev/null +++ b/components/autofill/ios/browser/autofill_driver_ios.h
@@ -0,0 +1,87 @@ +// 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 COMPONENTS_AUTOFILL_CONTENT_BROWSER_AUTOFILL_DRIVER_IOS_H_ +#define COMPONENTS_AUTOFILL_CONTENT_BROWSER_AUTOFILL_DRIVER_IOS_H_ + +#include <string> + +#include "components/autofill/core/browser/autofill_client.h" +#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 "ios/web/public/web_state/web_state_user_data.h" + +namespace web { +class WebState; +} + +@protocol AutofillDriverIOSBridge; + +namespace autofill { + +class AutofillManagerDelegate; + +// Class that drives autofill flow on iOS. There is one instance per +// WebContents. +class AutofillDriverIOS : public AutofillDriver, + public web::WebStateUserData<AutofillDriverIOS> { + public: + static void CreateForWebStateAndDelegate( + web::WebState* web_state, + AutofillClient* client, + id<AutofillDriverIOSBridge> bridge, + const std::string& app_locale, + AutofillManager::AutofillDownloadManagerState enable_download_manager); + + // AutofillDriver: + bool IsOffTheRecord() const override; + net::URLRequestContextGetter* GetURLRequestContext() override; + bool RendererIsAvailable() override; + void SendFormDataToRenderer(int query_id, + 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 RendererShouldClearFilledForm() override; + void RendererShouldClearPreviewedForm() override; + void RendererShouldAcceptDataListSuggestion( + const base::string16& value) override; + base::SequencedWorkerPool* GetBlockingPool() override; + + AutofillManager* autofill_manager() { return &autofill_manager_; } + + void RendererShouldFillFieldWithValue(const base::string16& value) override; + void RendererShouldPreviewFieldWithValue( + const base::string16& value) override; + void PopupHidden() override; + + private: + AutofillDriverIOS( + web::WebState* web_state, + AutofillClient* client, + id<AutofillDriverIOSBridge> bridge, + const std::string& app_locale, + AutofillManager::AutofillDownloadManagerState enable_download_manager); + ~AutofillDriverIOS() override; + + // The WebState with which this object is associated. + web::WebState* web_state_; + + // AutofillDriverIOSBridge instance that is passed in. + id<AutofillDriverIOSBridge> bridge_; + + // AutofillManager instance via which this object drives the shared Autofill + // code. + AutofillManager autofill_manager_; + // AutofillExternalDelegate instance that is passed to the AutofillManager. + AutofillExternalDelegate autofill_external_delegate_; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CONTENT_BROWSER_AUTOFILL_DRIVER_IOS_H_
diff --git a/components/autofill/ios/browser/autofill_driver_ios.mm b/components/autofill/ios/browser/autofill_driver_ios.mm new file mode 100644 index 0000000..1087f9dd --- /dev/null +++ b/components/autofill/ios/browser/autofill_driver_ios.mm
@@ -0,0 +1,104 @@ +// 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 "components/autofill/ios/browser/autofill_driver_ios.h" + +#include "components/autofill/ios/browser/autofill_driver_ios_bridge.h" +#include "ios/web/public/browser_state.h" +#include "ios/web/public/web_state/web_state.h" +#include "ios/web/public/web_thread.h" + +DEFINE_WEB_STATE_USER_DATA_KEY(autofill::AutofillDriverIOS); + +namespace autofill { + +// static +void AutofillDriverIOS::CreateForWebStateAndDelegate( + web::WebState* web_state, + AutofillClient* client, + id<AutofillDriverIOSBridge> bridge, + const std::string& app_locale, + AutofillManager::AutofillDownloadManagerState enable_download_manager) { + if (FromWebState(web_state)) + return; + + web_state->SetUserData( + UserDataKey(), + new AutofillDriverIOS(web_state, client, bridge, app_locale, + enable_download_manager)); +} + +AutofillDriverIOS::AutofillDriverIOS( + web::WebState* web_state, + AutofillClient* client, + id<AutofillDriverIOSBridge> bridge, + const std::string& app_locale, + AutofillManager::AutofillDownloadManagerState enable_download_manager) + : web_state_(web_state), + bridge_(bridge), + autofill_manager_(this, client, app_locale, enable_download_manager), + autofill_external_delegate_(&autofill_manager_, this) { + autofill_manager_.SetExternalDelegate(&autofill_external_delegate_); +} + +AutofillDriverIOS::~AutofillDriverIOS() {} + +bool AutofillDriverIOS::IsOffTheRecord() const { + return web_state_->GetBrowserState()->IsOffTheRecord(); +} + +net::URLRequestContextGetter* AutofillDriverIOS::GetURLRequestContext() { + return web_state_->GetBrowserState()->GetRequestContext(); +} + +base::SequencedWorkerPool* AutofillDriverIOS::GetBlockingPool() { + return web::WebThread::GetBlockingPool(); +} + +bool AutofillDriverIOS::RendererIsAvailable() { + return true; +} + +void AutofillDriverIOS::SendFormDataToRenderer( + int query_id, + RendererFormDataAction action, + const FormData& data) { + [bridge_ onFormDataFilled:query_id result:data]; +} + +void AutofillDriverIOS::PingRenderer() { +} + +void AutofillDriverIOS::DetectAccountCreationForms( + const std::vector<autofill::FormStructure*>& forms) { + autofill_manager_.client()->DetectAccountCreationForms(nullptr, forms); +}; + +void AutofillDriverIOS::SendAutofillTypePredictionsToRenderer( + const std::vector<FormStructure*>& forms) { + [bridge_ sendAutofillTypePredictionsToRenderer:forms]; +} + +void AutofillDriverIOS::RendererShouldAcceptDataListSuggestion( + const base::string16& value) { +} + +void AutofillDriverIOS::RendererShouldClearFilledForm() { +} + +void AutofillDriverIOS::RendererShouldClearPreviewedForm() { +} + +void AutofillDriverIOS::RendererShouldFillFieldWithValue( + const base::string16& value) { +} + +void AutofillDriverIOS::RendererShouldPreviewFieldWithValue( + const base::string16& value) { +} + +void AutofillDriverIOS::PopupHidden() { +} + +} // namespace autofill
diff --git a/components/autofill/ios/browser/autofill_driver_ios_bridge.h b/components/autofill/ios/browser/autofill_driver_ios_bridge.h new file mode 100644 index 0000000..332c40e --- /dev/null +++ b/components/autofill/ios/browser/autofill_driver_ios_bridge.h
@@ -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. + +#ifndef COMPONENTS_AUTOFILL_IOS_BROWSER_AUTOFILL_DRIVER_IOS_BRIDGE_H_ +#define COMPONENTS_AUTOFILL_IOS_BROWSER_AUTOFILL_DRIVER_IOS_BRIDGE_H_ + +#include <vector> + +#include "base/basictypes.h" + +namespace autofill { +struct FormData; +class FormStructure; +} + +@protocol AutofillDriverIOSBridge + +- (void)onFormDataFilled:(uint16)query_id + result:(const autofill::FormData&)result; + +- (void)sendAutofillTypePredictionsToRenderer: + (const std::vector<autofill::FormStructure*>&)forms; + +@end + +#endif // COMPONENTS_AUTOFILL_IOS_BROWSER_AUTOFILL_DRIVER_IOS_BRIDGE_H_
diff --git a/components/bookmarks/browser/bookmark_codec.cc b/components/bookmarks/browser/bookmark_codec.cc index 0392c47..9ea5ae4 100644 --- a/components/bookmarks/browser/bookmark_codec.cc +++ b/components/bookmarks/browser/bookmark_codec.cc
@@ -386,8 +386,8 @@ if (meta_info->IsType(base::Value::TYPE_STRING)) { std::string meta_info_str; meta_info->GetAsString(&meta_info_str); - JSONStringValueSerializer serializer(meta_info_str); - deserialized_holder.reset(serializer.Deserialize(nullptr, nullptr)); + JSONStringValueDeserializer deserializer(meta_info_str); + deserialized_holder.reset(deserializer.Deserialize(nullptr, nullptr)); if (!deserialized_holder) return false; meta_info = deserialized_holder.get();
diff --git a/components/bookmarks/browser/bookmark_codec_unittest.cc b/components/bookmarks/browser/bookmark_codec_unittest.cc index 9d529f8..8c45aea8 100644 --- a/components/bookmarks/browser/bookmark_codec_unittest.cc +++ b/components/bookmarks/browser/bookmark_codec_unittest.cc
@@ -359,8 +359,8 @@ GetTestDataDir().AppendASCII("bookmarks/model_without_sync.json"); ASSERT_TRUE(base::PathExists(test_file)); - JSONFileValueSerializer serializer(test_file); - scoped_ptr<base::Value> root(serializer.Deserialize(NULL, NULL)); + JSONFileValueDeserializer deserializer(test_file); + scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, NULL)); scoped_ptr<BookmarkModel> decoded_model(client_.CreateModel()); BookmarkCodec decoder; @@ -445,8 +445,8 @@ GetTestDataDir().AppendASCII("bookmarks/meta_info_as_string.json"); ASSERT_TRUE(base::PathExists(test_file)); - JSONFileValueSerializer serializer(test_file); - scoped_ptr<base::Value> root(serializer.Deserialize(NULL, NULL)); + JSONFileValueDeserializer deserializer(test_file); + scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, NULL)); scoped_ptr<BookmarkModel> model(client_.CreateModel()); BookmarkCodec decoder;
diff --git a/components/bookmarks/browser/bookmark_storage.cc b/components/bookmarks/browser/bookmark_storage.cc index b377069..daafdbe 100644 --- a/components/bookmarks/browser/bookmark_storage.cc +++ b/components/bookmarks/browser/bookmark_storage.cc
@@ -56,8 +56,8 @@ bool load_index = false; bool bookmark_file_exists = base::PathExists(path); if (bookmark_file_exists) { - JSONFileValueSerializer serializer(path); - scoped_ptr<base::Value> root(serializer.Deserialize(NULL, NULL)); + JSONFileValueDeserializer deserializer(path); + scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, NULL)); if (root.get()) { // Building the index can take a while, so we do it on the background
diff --git a/components/components.gyp b/components/components.gyp index 17e4235b..6fc7aece 100644 --- a/components/components.gyp +++ b/components/components.gyp
@@ -65,8 +65,8 @@ 'user_prefs.gypi', 'variations.gypi', 'wallpaper.gypi', - 'webdata.gypi', 'web_resource.gypi', + 'webdata.gypi', ], 'conditions': [ ['OS != "ios"', { @@ -80,6 +80,7 @@ 'web_cache.gypi', 'web_contents_delegate_android.gypi', 'web_modal.gypi', + 'webui_generator.gypi', ], }], ['OS == "ios"', { @@ -88,11 +89,15 @@ 'webp_transcode.gypi', ], }], + ['OS != "android"', { + 'includes': [ + 'feedback.gypi', + ] + }], ['OS != "ios" and OS != "android"', { 'includes': [ 'audio_modem.gypi', 'copresence.gypi', - 'feedback.gypi', 'proximity_auth.gypi', 'storage_monitor.gypi', ]
diff --git a/components/components_strings.grd b/components/components_strings.grd index e48591a..8996ec1 100644 --- a/components/components_strings.grd +++ b/components/components_strings.grd
@@ -179,6 +179,7 @@ <part file="pdf_strings.grdp" /> <part file="policy_strings.grdp" /> <part file="translate_strings.grdp" /> + <part file="webui_generator_strings.grdp" /> <!-- Generic terms --> <message name="IDS_LEARN_MORE" desc="Learn more text">
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 4f44e2b..d1e68bdc 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp
@@ -8,6 +8,412 @@ # platforms to include source files on (e.g. files ending in # _mac.h or _mac.cc are only compiled on MacOSX). 'chromium_code': 1, + + # Note: sources list duplicated in GN build. In the GN build, + # each component has its own unit tests target defined in its + # directory that are then linked into the final content_unittests. + 'auto_login_parser_unittest_sources': [ + 'auto_login_parser/auto_login_parser_unittest.cc', + ], + 'autofill_unittest_sources': [ + 'autofill/content/browser/content_autofill_driver_unittest.cc', + 'autofill/content/browser/request_autocomplete_manager_unittest.cc', + 'autofill/content/browser/wallet/full_wallet_unittest.cc', + 'autofill/content/browser/wallet/instrument_unittest.cc', + 'autofill/content/browser/wallet/wallet_address_unittest.cc', + 'autofill/content/browser/wallet/wallet_client_unittest.cc', + 'autofill/content/browser/wallet/wallet_items_unittest.cc', + 'autofill/content/browser/wallet/wallet_service_url_unittest.cc', + 'autofill/content/browser/wallet/wallet_signin_helper_unittest.cc', + 'autofill/core/browser/address_field_unittest.cc', + 'autofill/core/browser/address_i18n_unittest.cc', + 'autofill/core/browser/address_unittest.cc', + 'autofill/core/browser/autocomplete_history_manager_unittest.cc', + 'autofill/core/browser/autofill_country_unittest.cc', + 'autofill/core/browser/autofill_data_model_unittest.cc', + 'autofill/core/browser/autofill_download_manager_unittest.cc', + 'autofill/core/browser/autofill_external_delegate_unittest.cc', + 'autofill/core/browser/autofill_field_unittest.cc', + 'autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc', + 'autofill/core/browser/autofill_manager_unittest.cc', + 'autofill/core/browser/autofill_merge_unittest.cc', + 'autofill/core/browser/autofill_metrics_unittest.cc', + 'autofill/core/browser/autofill_profile_unittest.cc', + 'autofill/core/browser/autofill_regexes_unittest.cc', + 'autofill/core/browser/autofill_type_unittest.cc', + 'autofill/core/browser/autofill_xml_parser_unittest.cc', + 'autofill/core/browser/contact_info_unittest.cc', + 'autofill/core/browser/credit_card_field_unittest.cc', + 'autofill/core/browser/credit_card_unittest.cc', + 'autofill/core/browser/form_field_unittest.cc', + 'autofill/core/browser/form_structure_unittest.cc', + 'autofill/core/browser/name_field_unittest.cc', + 'autofill/core/browser/password_generator_unittest.cc', + 'autofill/core/browser/personal_data_manager_unittest.cc', + 'autofill/core/browser/phone_field_unittest.cc', + 'autofill/core/browser/phone_number_i18n_unittest.cc', + 'autofill/core/browser/phone_number_unittest.cc', + 'autofill/core/browser/validation_unittest.cc', + 'autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc', + 'autofill/core/browser/webdata/autofill_table_unittest.cc', + 'autofill/core/browser/webdata/web_data_service_unittest.cc', + 'autofill/core/common/form_data_unittest.cc', + 'autofill/core/common/form_field_data_unittest.cc', + 'autofill/core/common/password_form_fill_data_unittest.cc', + 'autofill/core/common/save_password_progress_logger_unittest.cc', + ], + 'bookmarks_unittest_sources': [ + 'bookmarks/browser/bookmark_codec_unittest.cc', + 'bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc', + 'bookmarks/browser/bookmark_index_unittest.cc', + 'bookmarks/browser/bookmark_model_unittest.cc', + 'bookmarks/browser/bookmark_utils_unittest.cc', + ], + 'browser_watcher_unittest_sources': [ + 'browser_watcher/endsession_watcher_window_win_unittest.cc', + 'browser_watcher/exit_code_watcher_win_unittest.cc', + 'browser_watcher/exit_funnel_win_unittest.cc', + 'browser_watcher/watcher_client_win_unittest.cc', + 'browser_watcher/watcher_metrics_provider_win_unittest.cc', + ], + 'captive_portal_unittest_sources': [ + 'captive_portal/captive_portal_detector_unittest.cc', + ], + 'cloud_devices_unittest_sources': [ + 'cloud_devices/common/cloud_devices_urls_unittest.cc', + 'cloud_devices/common/printer_description_unittest.cc', + ], + 'content_settings_unittest_sources': [ + 'content_settings/core/browser/content_settings_mock_provider.cc', + 'content_settings/core/browser/content_settings_mock_provider.h', + 'content_settings/core/browser/content_settings_provider_unittest.cc', + 'content_settings/core/browser/content_settings_rule_unittest.cc', + 'content_settings/core/browser/content_settings_utils_unittest.cc', + 'content_settings/core/common/content_settings_pattern_parser_unittest.cc', + 'content_settings/core/common/content_settings_pattern_unittest.cc', + ], + 'crash_unittest_sources': [ + 'crash/app/crash_keys_win_unittest.cc', + ], + 'crx_file_unittest_sources': [ + 'crx_file/id_util_unittest.cc', + ], + 'data_reduction_proxy_unittest_sources': [ + 'data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_prefs_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_statistics_prefs_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats_unittest.cc', + 'data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc', + 'data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc', + 'data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc', + ], + 'device_event_log_unittest_sources': [ + 'device_event_log/device_event_log_impl_unittest.cc', + ], + 'dom_distiller_unittest_sources': [ + 'dom_distiller/core/article_entry_unittest.cc', + 'dom_distiller/core/distilled_content_store_unittest.cc', + 'dom_distiller/core/distilled_page_prefs_unittests.cc', + 'dom_distiller/core/distiller_unittest.cc', + 'dom_distiller/core/distiller_url_fetcher_unittest.cc', + 'dom_distiller/core/dom_distiller_model_unittest.cc', + 'dom_distiller/core/dom_distiller_service_unittest.cc', + 'dom_distiller/core/dom_distiller_store_unittest.cc', + 'dom_distiller/core/task_tracker_unittest.cc', + 'dom_distiller/core/url_utils_unittest.cc', + 'dom_distiller/core/viewer_unittest.cc', + ], + 'domain_reliability_unittest_sources': [ + 'domain_reliability/config_unittest.cc', + 'domain_reliability/context_unittest.cc', + 'domain_reliability/dispatcher_unittest.cc', + 'domain_reliability/monitor_unittest.cc', + 'domain_reliability/scheduler_unittest.cc', + 'domain_reliability/test_util.cc', + 'domain_reliability/test_util.h', + 'domain_reliability/uploader_unittest.cc', + 'domain_reliability/util_unittest.cc', + ], + 'favicon_base_unittest_sources': [ + 'favicon_base/select_favicon_frames_unittest.cc', + ], + + # Note: GN tests converted to here, need to do the rest. + 'enhanced_bookmarks_unittest_sources': [ + 'enhanced_bookmarks/enhanced_bookmark_model_unittest.cc', + 'enhanced_bookmarks/image_store_ios_unittest.mm', + 'enhanced_bookmarks/image_store_unittest.cc', + 'enhanced_bookmarks/item_position_unittest.cc', + ], + 'feedback_unittest_sources': [ + 'feedback/feedback_common_unittest.cc', + 'feedback/feedback_data_unittest.cc', + 'feedback/feedback_uploader_chrome_unittest.cc', + 'feedback/feedback_uploader_unittest.cc', + ], + 'gcm_driver_unittest_sources': [ + 'gcm_driver/gcm_account_mapper_unittest.cc', + 'gcm_driver/gcm_channel_status_request_unittest.cc', + 'gcm_driver/gcm_client_impl_unittest.cc', + 'gcm_driver/gcm_delayed_task_controller_unittest.cc', + 'gcm_driver/gcm_driver_desktop_unittest.cc', + 'gcm_driver/gcm_stats_recorder_impl_unittest.cc', + ], + 'google_unittest_sources': [ + 'google/core/browser/google_url_tracker_unittest.cc', + 'google/core/browser/google_util_unittest.cc', + ], + 'history_unittest_sources': [ + 'history/core/browser/android/android_history_types_unittest.cc', + 'history/core/browser/history_types_unittest.cc', + 'history/core/browser/in_memory_url_index_types_unittest.cc', + 'history/core/browser/top_sites_cache_unittest.cc', + 'history/core/browser/top_sites_database_unittest.cc', + 'history/core/browser/url_database_unittest.cc', + 'history/core/browser/url_utils_unittest.cc', + 'history/core/browser/visit_database_unittest.cc', + 'history/core/browser/visit_filter_unittest.cc', + 'history/core/browser/visit_tracker_unittest.cc', + 'history/core/common/thumbnail_score_unittest.cc', + ], + 'invalidation_unittest_sources': [ + 'invalidation/invalidation_logger_unittest.cc', + ], + 'json_schema_unittest_sources': [ + 'json_schema/json_schema_validator_unittest.cc', + 'json_schema/json_schema_validator_unittest_base.cc', + 'json_schema/json_schema_validator_unittest_base.h', + ], + 'keyed_service_unittest_sources': [ + 'keyed_service/content/browser_context_dependency_manager_unittest.cc', + 'keyed_service/core/dependency_graph_unittest.cc', + ], + 'language_usage_metrics_unittest_sources': [ + 'language_usage_metrics/language_usage_metrics_unittest.cc', + ], + 'leveldb_proto_unittest_sources': [ + 'leveldb_proto/proto_database_impl_unittest.cc', + ], + 'login_unittest_sources': [ + 'login/screens/screen_context_unittest.cc', + ], + 'metrics_unittest_sources': [ + 'metrics/compression_utils_unittest.cc', + 'metrics/daily_event_unittest.cc', + 'metrics/histogram_encoder_unittest.cc', + 'metrics/histogram_manager_unittest.cc', + 'metrics/machine_id_provider_win_unittest.cc', + 'metrics/metrics_hashes_unittest.cc', + 'metrics/metrics_log_manager_unittest.cc', + 'metrics/metrics_log_unittest.cc', + 'metrics/metrics_reporting_scheduler_unittest.cc', + 'metrics/metrics_service_unittest.cc', + 'metrics/metrics_state_manager_unittest.cc', + 'metrics/net/net_metrics_log_uploader_unittest.cc', + 'metrics/persisted_logs_unittest.cc', + 'metrics/profiler/profiler_metrics_provider_unittest.cc', + ], + 'navigation_interception_unittest_sources': [ + 'navigation_interception/intercept_navigation_resource_throttle_unittest.cc', + ], + 'network_time_unittest_sources': [ + 'network_time/network_time_tracker_unittest.cc', + ], + 'omnibox_unittest_sources': [ + 'omnibox/answers_cache_unittest.cc', + 'omnibox/autocomplete_input_unittest.cc', + 'omnibox/autocomplete_match_unittest.cc', + 'omnibox/autocomplete_result_unittest.cc', + 'omnibox/base_search_provider_unittest.cc', + 'omnibox/keyword_provider_unittest.cc', + 'omnibox/omnibox_field_trial_unittest.cc', + 'omnibox/suggestion_answer_unittest.cc', + ], + 'os_crypt_unittest_sources': [ + 'os_crypt/ie7_password_win_unittest.cc', + 'os_crypt/keychain_password_mac_unittest.mm', + 'os_crypt/os_crypt_unittest.cc', + ], + 'ownership_unittest_sources': [ + 'ownership/owner_key_util_impl_unittest.cc', + ], + 'packed_ct_ev_whitelist_unittest_sources': [ + 'packed_ct_ev_whitelist/bit_stream_reader_unittest.cc', + 'packed_ct_ev_whitelist/packed_ct_ev_whitelist_unittest.cc', + ], + 'password_manager_unittest_sources': [ + 'password_manager/core/browser/affiliation_backend_unittest.cc', + 'password_manager/core/browser/affiliation_database_unittest.cc', + 'password_manager/core/browser/affiliation_fetch_throttler_unittest.cc', + 'password_manager/core/browser/affiliation_fetcher_unittest.cc', + 'password_manager/core/browser/affiliation_service_unittest.cc', + 'password_manager/core/browser/affiliation_utils_unittest.cc', + 'password_manager/core/browser/browser_save_password_progress_logger_unittest.cc', + 'password_manager/core/browser/export/csv_writer_unittest.cc', + 'password_manager/core/browser/import/csv_reader_unittest.cc', + 'password_manager/core/browser/log_router_unittest.cc', + 'password_manager/core/browser/login_database_unittest.cc', + 'password_manager/core/browser/password_autofill_manager_unittest.cc', + '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_store_default_unittest.cc', + 'password_manager/core/browser/password_store_unittest.cc', + 'password_manager/core/browser/password_syncable_service_unittest.cc', + 'password_manager/core/browser/psl_matching_helper_unittest.cc', + ], + 'precache_unittest_sources': [ + 'precache/content/precache_manager_unittest.cc', + 'precache/core/precache_database_unittest.cc', + 'precache/core/precache_fetcher_unittest.cc', + 'precache/core/precache_url_table_unittest.cc', + ], + 'query_parser_unittest_sources': [ + 'query_parser/query_parser_unittest.cc', + 'query_parser/snippet_unittest.cc', + ], + 'rappor_unittest_sources': [ + 'rappor/bloom_filter_unittest.cc', + 'rappor/byte_vector_utils_unittest.cc', + 'rappor/log_uploader_unittest.cc', + 'rappor/rappor_metric_unittest.cc', + 'rappor/rappor_prefs_unittest.cc', + 'rappor/rappor_service_unittest.cc', + ], + 'search_unittest_sources': [ + 'search/search_android_unittest.cc', + 'search/search_unittest.cc', + 'search_engines/default_search_manager_unittest.cc', + 'search_engines/default_search_policy_handler_unittest.cc', + 'search_engines/keyword_table_unittest.cc', + 'search_engines/search_host_to_urls_map_unittest.cc', + 'search_engines/template_url_prepopulate_data_unittest.cc', + 'search_engines/template_url_service_util_unittest.cc', + 'search_engines/template_url_unittest.cc', + ], + 'search_provider_logos_unittest_sources': [ + 'search_provider_logos/logo_cache_unittest.cc', + 'search_provider_logos/logo_tracker_unittest.cc', + ], + 'sessions_unittest_sources': [ + 'sessions/content/content_serialized_navigation_builder_unittest.cc', + 'sessions/content/content_serialized_navigation_driver_unittest.cc', + 'sessions/ios/ios_serialized_navigation_builder_unittest.cc', + 'sessions/ios/ios_serialized_navigation_driver_unittest.cc', + 'sessions/serialized_navigation_entry_unittest.cc', + 'sessions/session_types_unittest.cc', + ], + 'signin_unittest_sources': [ + 'signin/core/browser/account_tracker_service_unittest.cc', + 'signin/core/browser/mutable_profile_oauth2_token_service_unittest.cc', + 'signin/core/browser/refresh_token_annotation_request_unittest.cc', + 'signin/core/browser/signin_error_controller_unittest.cc', + 'signin/core/browser/webdata/token_service_table_unittest.cc', + 'signin/ios/browser/profile_oauth2_token_service_ios_unittest.mm', + ], + 'storage_monitor_unittest_sources': [ + 'storage_monitor/image_capture_device_manager_unittest.mm', + 'storage_monitor/media_storage_util_unittest.cc', + 'storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc', + 'storage_monitor/storage_info_unittest.cc', + 'storage_monitor/storage_monitor_chromeos_unittest.cc', + 'storage_monitor/storage_monitor_linux_unittest.cc', + 'storage_monitor/storage_monitor_mac_unittest.mm', + 'storage_monitor/storage_monitor_unittest.cc', + 'storage_monitor/storage_monitor_win_unittest.cc', + ], + 'suggestions_unittest_sources': [ + 'suggestions/blacklist_store_unittest.cc', + 'suggestions/image_manager_unittest.cc', + 'suggestions/suggestions_service_unittest.cc', + 'suggestions/suggestions_store_unittest.cc', + ], + 'sync_driver_unittest_sources': [ + 'sync_driver/data_type_manager_impl_unittest.cc', + 'sync_driver/device_info_data_type_controller_unittest.cc', + 'sync_driver/device_info_sync_service_unittest.cc', + 'sync_driver/generic_change_processor_unittest.cc', + 'sync_driver/model_association_manager_unittest.cc', + 'sync_driver/non_blocking_data_type_controller_unittest.cc', + 'sync_driver/non_ui_data_type_controller_unittest.cc', + 'sync_driver/shared_change_processor_unittest.cc', + 'sync_driver/sync_prefs_unittest.cc', + 'sync_driver/system_encryptor_unittest.cc', + 'sync_driver/ui_data_type_controller_unittest.cc', + ], + 'translate_unittest_sources': [ + 'translate/core/browser/language_state_unittest.cc', + 'translate/core/browser/translate_browser_metrics_unittest.cc', + 'translate/core/browser/translate_prefs_unittest.cc', + 'translate/core/browser/translate_script_unittest.cc', + 'translate/core/common/translate_metrics_unittest.cc', + 'translate/core/common/translate_util_unittest.cc', + 'translate/core/language_detection/language_detection_util_unittest.cc', + 'translate/ios/browser/js_translate_manager_unittest.mm', + 'translate/ios/browser/language_detection_controller_unittest.mm', + 'translate/ios/browser/translate_controller_unittest.mm', + ], + 'ui_unittest_sources': [ + 'ui/zoom/page_zoom_unittests.cc', + ], + 'update_client_unittest_sources': [ + 'update_client/test/component_patcher_unittest.cc', + 'update_client/test/crx_downloader_unittest.cc', + 'update_client/test/ping_manager_unittest.cc', + 'update_client/test/request_sender_unittest.cc', + 'update_client/test/update_checker_unittest.cc', + 'update_client/test/update_response_unittest.cc', + 'update_client/update_query_params_unittest.cc', + ], + 'url_fixer_unittest_sources': [ + 'url_fixer/url_fixer_unittest.cc', + ], + 'url_matcher_unittest_sources': [ + 'url_matcher/regex_set_matcher_unittest.cc', + 'url_matcher/string_pattern_unittest.cc', + 'url_matcher/substring_set_matcher_unittest.cc', + 'url_matcher/url_matcher_factory_unittest.cc', + 'url_matcher/url_matcher_unittest.cc', + ], + 'variations_unittest_sources': [ + 'variations/active_field_trials_unittest.cc', + 'variations/caching_permuted_entropy_provider_unittest.cc', + 'variations/entropy_provider_unittest.cc', + 'variations/metrics_util_unittest.cc', + 'variations/net/variations_http_header_provider_unittest.cc', + 'variations/study_filtering_unittest.cc', + 'variations/variations_associated_data_unittest.cc', + 'variations/variations_seed_processor_unittest.cc', + 'variations/variations_seed_simulator_unittest.cc', + ], + 'visitedlink_unittest_sources': [ + 'visitedlink/test/visitedlink_unittest.cc', + ], + 'wallpaper_unittest_sources': [ + 'wallpaper/wallpaper_resizer_unittest.cc', + ], + 'web_cache_unittest_sources': [ + 'web_cache/browser/web_cache_manager_unittest.cc', + ], + 'web_modal_unittest_sources': [ + 'web_modal/web_contents_modal_dialog_manager_unittest.cc', + ], + 'web_resource_unittest_sources': [ + 'web_resource/eula_accepted_notifier_unittest.cc', + 'web_resource/resource_request_allowed_notifier_unittest.cc', + ], + 'webdata_unittest_sources': [ + 'webdata/common/web_database_migration_unittest.cc', + ], }, 'conditions': [ ['android_webview_build == 0', { @@ -50,298 +456,63 @@ 'target_name': 'components_unittests', 'type': '<(gtest_target_type)', 'sources': [ - # Note: sources list duplicated in GN build. In the GN build, - # each component has its own unit tests target defined in its - # directory that are then linked into the final content_unittests. - 'auto_login_parser/auto_login_parser_unittest.cc', - 'autofill/content/browser/content_autofill_driver_unittest.cc', - 'autofill/content/browser/request_autocomplete_manager_unittest.cc', - 'autofill/content/browser/wallet/full_wallet_unittest.cc', - 'autofill/content/browser/wallet/instrument_unittest.cc', - 'autofill/content/browser/wallet/wallet_address_unittest.cc', - 'autofill/content/browser/wallet/wallet_client_unittest.cc', - 'autofill/content/browser/wallet/wallet_items_unittest.cc', - 'autofill/content/browser/wallet/wallet_service_url_unittest.cc', - 'autofill/content/browser/wallet/wallet_signin_helper_unittest.cc', - 'autofill/core/browser/address_field_unittest.cc', - 'autofill/core/browser/address_i18n_unittest.cc', - 'autofill/core/browser/address_unittest.cc', - 'autofill/core/browser/autocomplete_history_manager_unittest.cc', - 'autofill/core/browser/autofill_country_unittest.cc', - 'autofill/core/browser/autofill_data_model_unittest.cc', - 'autofill/core/browser/autofill_download_manager_unittest.cc', - 'autofill/core/browser/autofill_external_delegate_unittest.cc', - 'autofill/core/browser/autofill_field_unittest.cc', - 'autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc', - 'autofill/core/browser/autofill_manager_unittest.cc', - 'autofill/core/browser/autofill_merge_unittest.cc', - 'autofill/core/browser/autofill_metrics_unittest.cc', - 'autofill/core/browser/autofill_profile_unittest.cc', - 'autofill/core/browser/autofill_regexes_unittest.cc', - 'autofill/core/browser/autofill_type_unittest.cc', - 'autofill/core/browser/autofill_xml_parser_unittest.cc', - 'autofill/core/browser/contact_info_unittest.cc', - 'autofill/core/browser/credit_card_field_unittest.cc', - 'autofill/core/browser/credit_card_unittest.cc', - 'autofill/core/browser/form_field_unittest.cc', - 'autofill/core/browser/form_structure_unittest.cc', - 'autofill/core/browser/name_field_unittest.cc', - 'autofill/core/browser/password_generator_unittest.cc', - 'autofill/core/browser/personal_data_manager_unittest.cc', - 'autofill/core/browser/phone_field_unittest.cc', - 'autofill/core/browser/phone_number_i18n_unittest.cc', - 'autofill/core/browser/phone_number_unittest.cc', - 'autofill/core/browser/validation_unittest.cc', - 'autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc', - 'autofill/core/browser/webdata/autofill_table_unittest.cc', - 'autofill/core/browser/webdata/web_data_service_unittest.cc', - 'autofill/core/common/form_data_unittest.cc', - 'autofill/core/common/form_field_data_unittest.cc', - 'autofill/core/common/password_form_fill_data_unittest.cc', - 'autofill/core/common/save_password_progress_logger_unittest.cc', - 'bookmarks/browser/bookmark_codec_unittest.cc', - 'bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc', - 'bookmarks/browser/bookmark_index_unittest.cc', - 'bookmarks/browser/bookmark_model_unittest.cc', - 'bookmarks/browser/bookmark_utils_unittest.cc', - 'browser_watcher/endsession_watcher_window_win_unittest.cc', - 'browser_watcher/exit_code_watcher_win_unittest.cc', - 'browser_watcher/exit_funnel_win_unittest.cc', - 'browser_watcher/watcher_client_win_unittest.cc', - 'browser_watcher/watcher_metrics_provider_win_unittest.cc', - 'captive_portal/captive_portal_detector_unittest.cc', - 'cloud_devices/common/cloud_devices_urls_unittest.cc', - 'cloud_devices/common/printer_description_unittest.cc', - 'content_settings/core/browser/content_settings_mock_provider.cc', - 'content_settings/core/browser/content_settings_mock_provider.h', - 'content_settings/core/browser/content_settings_provider_unittest.cc', - 'content_settings/core/browser/content_settings_rule_unittest.cc', - 'content_settings/core/browser/content_settings_utils_unittest.cc', - 'content_settings/core/common/content_settings_pattern_parser_unittest.cc', - 'content_settings/core/common/content_settings_pattern_unittest.cc', - 'crash/app/crash_keys_win_unittest.cc', - 'crx_file/id_util_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_prefs_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_statistics_prefs_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc', - 'data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats_unittest.cc', - 'data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc', - 'data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc', - 'data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc', - 'device_event_log/device_event_log_impl_unittest.cc', - 'dom_distiller/core/article_entry_unittest.cc', - 'dom_distiller/core/distilled_content_store_unittest.cc', - 'dom_distiller/core/distilled_page_prefs_unittests.cc', - 'dom_distiller/core/distiller_unittest.cc', - 'dom_distiller/core/distiller_url_fetcher_unittest.cc', - 'dom_distiller/core/dom_distiller_model_unittest.cc', - 'dom_distiller/core/dom_distiller_service_unittest.cc', - 'dom_distiller/core/dom_distiller_store_unittest.cc', - 'dom_distiller/core/task_tracker_unittest.cc', - 'dom_distiller/core/url_utils_unittest.cc', - 'dom_distiller/core/viewer_unittest.cc', - 'domain_reliability/config_unittest.cc', - 'domain_reliability/context_unittest.cc', - 'domain_reliability/dispatcher_unittest.cc', - 'domain_reliability/monitor_unittest.cc', - 'domain_reliability/scheduler_unittest.cc', - 'domain_reliability/test_util.cc', - 'domain_reliability/test_util.h', - 'domain_reliability/uploader_unittest.cc', - 'domain_reliability/util_unittest.cc', - 'favicon_base/select_favicon_frames_unittest.cc', - # Note: GN tests converted to here, need to do the rest. - - 'enhanced_bookmarks/enhanced_bookmark_model_unittest.cc', - 'enhanced_bookmarks/image_store_ios_unittest.mm', - 'enhanced_bookmarks/image_store_unittest.cc', - 'enhanced_bookmarks/item_position_unittest.cc', - 'gcm_driver/gcm_account_mapper_unittest.cc', - 'gcm_driver/gcm_channel_status_request_unittest.cc', - 'gcm_driver/gcm_client_impl_unittest.cc', - 'gcm_driver/gcm_delayed_task_controller_unittest.cc', - 'gcm_driver/gcm_driver_desktop_unittest.cc', - 'gcm_driver/gcm_stats_recorder_impl_unittest.cc', - 'google/core/browser/google_url_tracker_unittest.cc', - 'google/core/browser/google_util_unittest.cc', - 'history/core/browser/android/android_history_types_unittest.cc', - 'history/core/browser/history_types_unittest.cc', - 'history/core/browser/in_memory_url_index_types_unittest.cc', - 'history/core/browser/top_sites_cache_unittest.cc', - 'history/core/browser/top_sites_database_unittest.cc', - 'history/core/browser/url_database_unittest.cc', - 'history/core/browser/url_utils_unittest.cc', - 'history/core/browser/visit_database_unittest.cc', - 'history/core/browser/visit_filter_unittest.cc', - 'history/core/browser/visit_tracker_unittest.cc', - 'history/core/common/thumbnail_score_unittest.cc', - 'invalidation/invalidation_logger_unittest.cc', - 'json_schema/json_schema_validator_unittest.cc', - 'json_schema/json_schema_validator_unittest_base.cc', - 'json_schema/json_schema_validator_unittest_base.h', - 'keyed_service/content/browser_context_dependency_manager_unittest.cc', - 'keyed_service/core/dependency_graph_unittest.cc', - 'language_usage_metrics/language_usage_metrics_unittest.cc', - 'leveldb_proto/proto_database_impl_unittest.cc', - 'login/screens/screen_context_unittest.cc', - 'metrics/compression_utils_unittest.cc', - 'metrics/daily_event_unittest.cc', - 'metrics/histogram_encoder_unittest.cc', - 'metrics/histogram_manager_unittest.cc', - 'metrics/machine_id_provider_win_unittest.cc', - 'metrics/metrics_hashes_unittest.cc', - 'metrics/metrics_log_manager_unittest.cc', - 'metrics/metrics_log_unittest.cc', - 'metrics/metrics_reporting_scheduler_unittest.cc', - 'metrics/metrics_service_unittest.cc', - 'metrics/metrics_state_manager_unittest.cc', - 'metrics/net/net_metrics_log_uploader_unittest.cc', - 'metrics/persisted_logs_unittest.cc', - 'metrics/profiler/profiler_metrics_provider_unittest.cc', - 'navigation_interception/intercept_navigation_resource_throttle_unittest.cc', - 'network_time/network_time_tracker_unittest.cc', - 'omnibox/answers_cache_unittest.cc', - 'omnibox/autocomplete_input_unittest.cc', - 'omnibox/autocomplete_match_unittest.cc', - 'omnibox/autocomplete_result_unittest.cc', - 'omnibox/base_search_provider_unittest.cc', - 'omnibox/keyword_provider_unittest.cc', - 'omnibox/omnibox_field_trial_unittest.cc', - 'omnibox/suggestion_answer_unittest.cc', - 'os_crypt/ie7_password_win_unittest.cc', - 'os_crypt/keychain_password_mac_unittest.mm', - 'os_crypt/os_crypt_unittest.cc', - 'ownership/owner_key_util_impl_unittest.cc', - 'packed_ct_ev_whitelist/bit_stream_reader_unittest.cc', - 'packed_ct_ev_whitelist/packed_ct_ev_whitelist_unittest.cc', - 'password_manager/core/browser/affiliation_backend_unittest.cc', - 'password_manager/core/browser/affiliation_database_unittest.cc', - 'password_manager/core/browser/affiliation_fetch_throttler_unittest.cc', - 'password_manager/core/browser/affiliation_fetcher_unittest.cc', - 'password_manager/core/browser/affiliation_service_unittest.cc', - 'password_manager/core/browser/affiliation_utils_unittest.cc', - 'password_manager/core/browser/browser_save_password_progress_logger_unittest.cc', - 'password_manager/core/browser/export/csv_writer_unittest.cc', - 'password_manager/core/browser/import/csv_reader_unittest.cc', - 'password_manager/core/browser/log_router_unittest.cc', - 'password_manager/core/browser/login_database_unittest.cc', - 'password_manager/core/browser/password_autofill_manager_unittest.cc', - '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_store_default_unittest.cc', - 'password_manager/core/browser/password_store_unittest.cc', - 'password_manager/core/browser/password_syncable_service_unittest.cc', - 'password_manager/core/browser/psl_matching_helper_unittest.cc', - 'precache/content/precache_manager_unittest.cc', - 'precache/core/precache_database_unittest.cc', - 'precache/core/precache_fetcher_unittest.cc', - 'precache/core/precache_url_table_unittest.cc', - 'query_parser/query_parser_unittest.cc', - 'query_parser/snippet_unittest.cc', - 'rappor/bloom_filter_unittest.cc', - 'rappor/byte_vector_utils_unittest.cc', - 'rappor/log_uploader_unittest.cc', - 'rappor/rappor_metric_unittest.cc', - 'rappor/rappor_prefs_unittest.cc', - 'rappor/rappor_service_unittest.cc', - 'search/search_android_unittest.cc', - 'search/search_unittest.cc', - 'search_engines/default_search_manager_unittest.cc', - 'search_engines/default_search_policy_handler_unittest.cc', - 'search_engines/keyword_table_unittest.cc', - 'search_engines/search_host_to_urls_map_unittest.cc', - 'search_engines/template_url_prepopulate_data_unittest.cc', - 'search_engines/template_url_service_util_unittest.cc', - 'search_engines/template_url_unittest.cc', - 'search_provider_logos/logo_cache_unittest.cc', - 'search_provider_logos/logo_tracker_unittest.cc', - 'sessions/content/content_serialized_navigation_builder_unittest.cc', - 'sessions/content/content_serialized_navigation_driver_unittest.cc', - 'sessions/ios/ios_serialized_navigation_builder_unittest.cc', - 'sessions/ios/ios_serialized_navigation_driver_unittest.cc', - 'sessions/serialized_navigation_entry_unittest.cc', - 'sessions/session_types_unittest.cc', - 'signin/core/browser/account_tracker_service_unittest.cc', - 'signin/core/browser/mutable_profile_oauth2_token_service_unittest.cc', - 'signin/core/browser/refresh_token_annotation_request_unittest.cc', - 'signin/core/browser/signin_error_controller_unittest.cc', - 'signin/core/browser/webdata/token_service_table_unittest.cc', - 'signin/ios/browser/profile_oauth2_token_service_ios_unittest.mm', - 'storage_monitor/image_capture_device_manager_unittest.mm', - 'storage_monitor/media_storage_util_unittest.cc', - 'storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc', - 'storage_monitor/storage_info_unittest.cc', - 'storage_monitor/storage_monitor_chromeos_unittest.cc', - 'storage_monitor/storage_monitor_linux_unittest.cc', - 'storage_monitor/storage_monitor_mac_unittest.mm', - 'storage_monitor/storage_monitor_unittest.cc', - 'storage_monitor/storage_monitor_win_unittest.cc', - 'suggestions/blacklist_store_unittest.cc', - 'suggestions/image_manager_unittest.cc', - 'suggestions/suggestions_service_unittest.cc', - 'suggestions/suggestions_store_unittest.cc', - 'sync_driver/data_type_manager_impl_unittest.cc', - 'sync_driver/device_info_data_type_controller_unittest.cc', - 'sync_driver/device_info_sync_service_unittest.cc', - 'sync_driver/generic_change_processor_unittest.cc', - 'sync_driver/model_association_manager_unittest.cc', - 'sync_driver/non_blocking_data_type_controller_unittest.cc', - 'sync_driver/non_ui_data_type_controller_unittest.cc', - 'sync_driver/shared_change_processor_unittest.cc', - 'sync_driver/sync_prefs_unittest.cc', - 'sync_driver/system_encryptor_unittest.cc', - 'sync_driver/ui_data_type_controller_unittest.cc', 'test/run_all_unittests.cc', - 'translate/core/browser/language_state_unittest.cc', - 'translate/core/browser/translate_browser_metrics_unittest.cc', - 'translate/core/browser/translate_prefs_unittest.cc', - 'translate/core/browser/translate_script_unittest.cc', - 'translate/core/common/translate_metrics_unittest.cc', - 'translate/core/common/translate_util_unittest.cc', - 'translate/core/language_detection/language_detection_util_unittest.cc', - 'translate/ios/browser/js_translate_manager_unittest.mm', - 'translate/ios/browser/language_detection_controller_unittest.mm', - 'translate/ios/browser/translate_controller_unittest.mm', - 'ui/zoom/page_zoom_unittests.cc', - 'update_client/test/component_patcher_unittest.cc', - 'update_client/test/crx_downloader_unittest.cc', - 'update_client/test/ping_manager_unittest.cc', - 'update_client/test/request_sender_unittest.cc', - 'update_client/test/update_checker_unittest.cc', - 'update_client/test/update_response_unittest.cc', - 'update_client/update_query_params_unittest.cc', - 'url_fixer/url_fixer_unittest.cc', - 'url_matcher/regex_set_matcher_unittest.cc', - 'url_matcher/string_pattern_unittest.cc', - 'url_matcher/substring_set_matcher_unittest.cc', - 'url_matcher/url_matcher_factory_unittest.cc', - 'url_matcher/url_matcher_unittest.cc', - 'variations/active_field_trials_unittest.cc', - 'variations/caching_permuted_entropy_provider_unittest.cc', - 'variations/entropy_provider_unittest.cc', - 'variations/metrics_util_unittest.cc', - 'variations/net/variations_http_header_provider_unittest.cc', - 'variations/study_filtering_unittest.cc', - 'variations/variations_associated_data_unittest.cc', - 'variations/variations_seed_processor_unittest.cc', - 'variations/variations_seed_simulator_unittest.cc', - 'visitedlink/test/visitedlink_unittest.cc', - 'wallpaper/wallpaper_resizer_unittest.cc', - 'web_cache/browser/web_cache_manager_unittest.cc', - 'web_modal/web_contents_modal_dialog_manager_unittest.cc', - 'web_resource/eula_accepted_notifier_unittest.cc', - 'web_resource/resource_request_allowed_notifier_unittest.cc', - 'webdata/common/web_database_migration_unittest.cc', + + '<@(auto_login_parser_unittest_sources)', + '<@(autofill_unittest_sources)', + '<@(bookmarks_unittest_sources)', + '<@(browser_watcher_unittest_sources)', + '<@(captive_portal_unittest_sources)', + '<@(cloud_devices_unittest_sources)', + '<@(content_settings_unittest_sources)', + '<@(crash_unittest_sources)', + '<@(crx_file_unittest_sources)', + '<@(data_reduction_proxy_unittest_sources)', + '<@(device_event_log_unittest_sources)', + '<@(dom_distiller_unittest_sources)', + '<@(domain_reliability_unittest_sources)', + '<@(enhanced_bookmarks_unittest_sources)', + '<@(favicon_base_unittest_sources)', + '<@(feedback_unittest_sources)', + '<@(gcm_driver_unittest_sources)', + '<@(google_unittest_sources)', + '<@(history_unittest_sources)', + '<@(invalidation_unittest_sources)', + '<@(json_schema_unittest_sources)', + '<@(keyed_service_unittest_sources)', + '<@(language_usage_metrics_unittest_sources)', + '<@(leveldb_proto_unittest_sources)', + '<@(login_unittest_sources)', + '<@(metrics_unittest_sources)', + '<@(navigation_interception_unittest_sources)', + '<@(network_time_unittest_sources)', + '<@(omnibox_unittest_sources)', + '<@(os_crypt_unittest_sources)', + '<@(ownership_unittest_sources)', + '<@(packed_ct_ev_whitelist_unittest_sources)', + '<@(password_manager_unittest_sources)', + '<@(precache_unittest_sources)', + '<@(query_parser_unittest_sources)', + '<@(rappor_unittest_sources)', + '<@(search_unittest_sources)', + '<@(search_provider_logos_unittest_sources)', + '<@(sessions_unittest_sources)', + '<@(signin_unittest_sources)', + '<@(storage_monitor_unittest_sources)', + '<@(suggestions_unittest_sources)', + '<@(sync_driver_unittest_sources)', + '<@(translate_unittest_sources)', + '<@(ui_unittest_sources)', + '<@(update_client_unittest_sources)', + '<@(url_fixer_unittest_sources)', + '<@(url_matcher_unittest_sources)', + '<@(variations_unittest_sources)', + '<@(visitedlink_unittest_sources)', + '<@(wallpaper_unittest_sources)', + '<@(web_cache_unittest_sources)', + '<@(web_modal_unittest_sources)', + '<@(web_resource_unittest_sources)', + '<@(webdata_unittest_sources)', ], 'include_dirs': [ '..', @@ -397,6 +568,7 @@ 'components.gyp:enhanced_bookmarks', 'components.gyp:enhanced_bookmarks_test_support', 'components.gyp:favicon_base', + 'components.gyp:feedback_component', 'components.gyp:gcm_driver', 'components.gyp:gcm_driver_test_support', 'components.gyp:google_core_browser', @@ -485,6 +657,7 @@ ['OS != "ios"', { 'sources': [ 'autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc', + 'data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc', 'dom_distiller/content/dom_distiller_viewer_source_unittest.cc', 'dom_distiller/content/web_contents_main_frame_observer_unittest.cc', 'error_page/renderer/net_error_helper_core_unittest.cc', @@ -500,6 +673,7 @@ 'components.gyp:autofill_content_browser', 'components.gyp:autofill_content_renderer', 'components.gyp:autofill_content_test_support', + 'components.gyp:data_reduction_proxy_content_browser', 'components.gyp:dom_distiller_content', 'components.gyp:error_page_renderer', 'components.gyp:history_content_browser', @@ -529,51 +703,97 @@ ], }, { # 'OS == "ios"' 'sources': [ + 'open_from_clipboard/clipboard_recent_content_ios_unittest.mm', 'webp_transcode/webp_decoder_unittest.mm', ], 'sources/': [ + # First start by excluding all tests on iOS. ['exclude', '\\.cc$'], ['exclude', '\\.mm$'], + + # Include the test runner. ['include', '^test/run_all_unittests\\.cc$'], + + # Include tests for all components that are built on iOS. ['include', '^auto_login_parser/'], - ['include', '^autofill/core/'], + ['include', '^autofill/'], ['include', '^bookmarks/'], + ['include', '^captive_portal/'], + ['include', '^cloud_devices/'], ['include', '^component_updater/'], - ['include', '^crash/'], ['include', '^content_settings/'], + ['include', '^crash/'], + ['include', '^cronet/'], + ['include', '^crx_file/'], ['include', '^data_reduction_proxy/'], + ['include', '^device_event_log/'], ['include', '^dom_distiller/'], + ['include', '^domain_reliability/'], ['include', '^enhanced_bookmarks/'], + ['include', '^error_page/'], + ['include', '^favicon/'], + ['include', '^favicon_base/'], ['include', '^gcm_driver/'], ['include', '^google/'], + ['include', '^handoff/'], ['include', '^history/'], + ['include', '^infobars/'], ['include', '^invalidation/'], ['include', '^json_schema/'], - ['include', '^keyed_service/core/'], + ['include', '^keyed_service/'], ['include', '^language_usage_metrics/'], ['include', '^leveldb_proto/'], + ['include', '^login/'], ['include', '^metrics/'], + ['include', '^navigation_metrics/'], + ['include', '^network_hints/'], ['include', '^network_time/'], + ['include', '^omnibox/'], + ['include', '^onc/'], + ['include', '^open_from_clipboard/'], + ['include', '^os_crypt/'], + ['include', '^ownership/'], + ['include', '^packed_ct_ev_whitelist/'], ['include', '^password_manager/'], - ['include', '^precache/core/'], + ['include', '^policy/'], + ['include', '^precache/'], + ['include', '^pref_registry/'], ['include', '^query_parser/'], + ['include', '^rappor/'], + ['include', '^renderer_context_menu/'], ['include', '^search/'], ['include', '^search_engines/'], ['include', '^search_provider_logos/'], - ['include', '^sessions/ios/'], - ['include', '^sessions/serialized_navigation_entry_unittest\\.cc$'], - ['exclude', '^signin/core/browser/mutable_profile_oauth2_token_service_unittest\\.cc$'], + ['include', '^sessions/'], + ['include', '^signin/'], + ['include', '^startup_metric_utils/'], ['include', '^suggestions/'], ['include', '^sync_driver/'], ['include', '^translate/'], + ['include', '^ui_zoom/'], + ['include', '^update_client/'], ['include', '^url_fixer/'], + ['include', '^url_matcher/'], + ['include', '^user_prefs/'], ['include', '^variations/'], + ['include', '^wallpaper/'], + ['include', '^web_resource/'], + ['include', '^webdata/'], + ['include', '^webdata_services/'], ['include', '^webp_transcode/'], + + # Exclude individual tests that are known not to work on iOS. + ['exclude', '^signin/core/browser/mutable_profile_oauth2_token_service_unittest\\.cc$'], + + # Exclude all tests that depends on //content (based on layered- + # component directory structure). + ['exclude', '^[^/]*/content/'], ], 'dependencies': [ '../ios/ios_tests.gyp:test_support_ios', '../ios/web/ios_web.gyp:test_support_ios_web', '../third_party/ocmock/ocmock.gyp:ocmock', + 'components.gyp:open_from_clipboard', 'components.gyp:sessions_ios', 'components.gyp:signin_ios_browser', 'components.gyp:translate_ios_browser', @@ -634,6 +854,10 @@ 'invalidation/invalidation_service_android_unittest.cc', ], 'sources!': [ + 'feedback/feedback_common_unittest.cc', + 'feedback/feedback_data_unittest.cc', + 'feedback/feedback_uploader_chrome_unittest.cc', + 'feedback/feedback_uploader_unittest.cc', 'gcm_driver/gcm_account_mapper_unittest.cc', 'gcm_driver/gcm_channel_status_request_unittest.cc', 'gcm_driver/gcm_client_impl_unittest.cc', @@ -651,6 +875,7 @@ '../testing/android/native_test.gyp:native_test_native_code', ], 'dependencies!': [ + 'components.gyp:feedback_component', 'components.gyp:storage_monitor', 'components.gyp:storage_monitor_test_support', 'components.gyp:web_modal', @@ -688,10 +913,6 @@ 'copresence/rpc/http_post_unittest.cc', 'copresence/rpc/rpc_handler_unittest.cc', 'copresence/timed_map_unittest.cc', - 'feedback/feedback_common_unittest.cc', - 'feedback/feedback_data_unittest.cc', - 'feedback/feedback_uploader_chrome_unittest.cc', - 'feedback/feedback_uploader_unittest.cc', 'proximity_auth/base64url_unittest.cc', 'proximity_auth/bluetooth_connection_finder_unittest.cc', 'proximity_auth/bluetooth_connection_unittest.cc', @@ -713,7 +934,6 @@ 'components.gyp:copresence', 'components.gyp:copresence_test_support', 'components.gyp:cryptauth', - 'components.gyp:feedback_component', 'components.gyp:proximity_auth', ], }],
diff --git a/components/content_settings.gypi b/components/content_settings.gypi index c6700f6..6e7f0b2 100644 --- a/components/content_settings.gypi +++ b/components/content_settings.gypi
@@ -22,6 +22,8 @@ ], 'sources': [ # Note: sources list duplicated in GN build. + 'content_settings/core/browser/content_settings_binary_value_map.cc', + 'content_settings/core/browser/content_settings_binary_value_map.h', 'content_settings/core/browser/content_settings_client.h', 'content_settings/core/browser/content_settings_default_provider.cc', 'content_settings/core/browser/content_settings_default_provider.h',
diff --git a/components/content_settings/core/browser/BUILD.gn b/components/content_settings/core/browser/BUILD.gn index a321cbb..667b5bc 100644 --- a/components/content_settings/core/browser/BUILD.gn +++ b/components/content_settings/core/browser/BUILD.gn
@@ -9,6 +9,8 @@ "content_settings_default_provider.h", "content_settings_details.cc", "content_settings_details.h", + "content_settings_binary_value_map.cc", + "content_settings_binary_value_map.h", "content_settings_observable_provider.cc", "content_settings_observable_provider.h", "content_settings_observer.h",
diff --git a/components/content_settings/core/browser/content_settings_binary_value_map.cc b/components/content_settings/core/browser/content_settings_binary_value_map.cc new file mode 100644 index 0000000..136d3874 --- /dev/null +++ b/components/content_settings/core/browser/content_settings_binary_value_map.cc
@@ -0,0 +1,65 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/content_settings/core/browser/content_settings_binary_value_map.h" + +#include "base/synchronization/lock.h" +#include "components/content_settings/core/browser/content_settings_rule.h" +#include "components/content_settings/core/common/content_settings.h" + +namespace content_settings { + +namespace { + +class RuleIteratorBinary : public RuleIterator { + public: + explicit RuleIteratorBinary(bool is_enabled, + scoped_ptr<base::AutoLock> auto_lock) + : is_done_(is_enabled), auto_lock_(auto_lock.Pass()) {} + + bool HasNext() const override { return !is_done_; } + + Rule Next() override { + DCHECK(!is_done_); + is_done_ = true; + return Rule(ContentSettingsPattern::Wildcard(), + ContentSettingsPattern::Wildcard(), + new base::FundamentalValue(CONTENT_SETTING_BLOCK)); + } + + private: + bool is_done_; + scoped_ptr<base::AutoLock> auto_lock_; +}; + +} // namespace + +BinaryValueMap::BinaryValueMap() { + for (bool& enabled : is_enabled_) { + enabled = true; + } +} + +RuleIterator* BinaryValueMap::GetRuleIterator( + ContentSettingsType content_type, + const ResourceIdentifier& resource_identifier, + scoped_ptr<base::AutoLock> auto_lock) const { + if (resource_identifier.empty()) { + return new RuleIteratorBinary(IsContentSettingEnabled(content_type), + auto_lock.Pass()); + } + return new EmptyRuleIterator(); +} + +void BinaryValueMap::SetContentSettingDisabled(ContentSettingsType content_type, + bool is_disabled) { + is_enabled_[content_type] = !is_disabled; +} + +bool BinaryValueMap::IsContentSettingEnabled( + ContentSettingsType content_type) const { + return is_enabled_[content_type]; +} + +} // namespace content_settings
diff --git a/components/content_settings/core/browser/content_settings_binary_value_map.h b/components/content_settings/core/browser/content_settings_binary_value_map.h new file mode 100644 index 0000000..3416a13 --- /dev/null +++ b/components/content_settings/core/browser/content_settings_binary_value_map.h
@@ -0,0 +1,39 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_BINARY_VALUE_MAP_H_ +#define COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_BINARY_VALUE_MAP_H_ + +#include "components/content_settings/core/browser/content_settings_provider.h" +#include "components/content_settings/core/common/content_settings_types.h" + +namespace base { +class AutoLock; +} // namespace base + +namespace content_settings { + +class RuleIterator; + +// A simplified value map that can be used to disable or enable the entire +// Content Setting. The default behaviour is enabling the Content Setting if +// it is not set explicitly. +class BinaryValueMap { + public: + BinaryValueMap(); + + RuleIterator* GetRuleIterator(ContentSettingsType content_type, + const ResourceIdentifier& resource_identifier, + scoped_ptr<base::AutoLock> lock) const; + void SetContentSettingDisabled(ContentSettingsType content_type, + bool disabled); + bool IsContentSettingEnabled(ContentSettingsType content_type) const; + + private: + bool is_enabled_[CONTENT_SETTINGS_NUM_TYPES]; +}; + +} // namespace content_settings + +#endif // COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_BINARY_VALUE_MAP_H_
diff --git a/components/content_settings/core/browser/content_settings_override_provider.cc b/components/content_settings/core/browser/content_settings_override_provider.cc index edb36a58..ee04dc92 100644 --- a/components/content_settings/core/browser/content_settings_override_provider.cc +++ b/components/content_settings/core/browser/content_settings_override_provider.cc
@@ -10,6 +10,7 @@ #include "base/prefs/pref_service.h" #include "base/prefs/scoped_user_pref_update.h" #include "base/values.h" +#include "components/content_settings/core/browser/content_settings_binary_value_map.h" #include "components/content_settings/core/browser/content_settings_rule.h" #include "components/content_settings/core/browser/content_settings_utils.h" #include "components/content_settings/core/common/content_settings.h" @@ -19,28 +20,6 @@ namespace content_settings { -namespace { - -class OverrideRuleIterator : public RuleIterator { - public: - explicit OverrideRuleIterator(bool is_allowed) : is_done_(is_allowed) {} - - bool HasNext() const override { return !is_done_; } - - Rule Next() override { - DCHECK(!is_done_); - is_done_ = true; - return Rule(ContentSettingsPattern::Wildcard(), - ContentSettingsPattern::Wildcard(), - new base::FundamentalValue(CONTENT_SETTING_BLOCK)); - } - - private: - bool is_done_; -}; - -} // namespace - // static void OverrideProvider::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { @@ -64,11 +43,9 @@ ContentSettingsType content_type, const ResourceIdentifier& resource_identifier, bool incognito) const { - base::AutoLock lock(lock_); - if (resource_identifier.empty()) { - return new OverrideRuleIterator(allowed_settings_[content_type]); - } - return new EmptyRuleIterator(); + scoped_ptr<base::AutoLock> auto_lock(new base::AutoLock(lock_)); + return allowed_settings_.GetRuleIterator(content_type, resource_identifier, + auto_lock.Pass()); } void OverrideProvider::ClearAllContentSettingsRules( @@ -97,23 +74,22 @@ // Disallow incognito to change the state. DCHECK(!is_incognito_); - base::AutoLock lock(lock_); + base::AutoLock auto_lock(lock_); DictionaryPrefUpdate update(prefs_, prefs::kOverrideContentSettings); base::DictionaryValue* default_settings_dictionary = update.Get(); + allowed_settings_.SetContentSettingDisabled(content_type, !enabled); if (enabled) { - allowed_settings_[content_type] = true; default_settings_dictionary->RemoveWithoutPathExpansion( GetTypeName(content_type), NULL); } else { - allowed_settings_[content_type] = false; default_settings_dictionary->SetWithoutPathExpansion( GetTypeName(content_type), new base::FundamentalValue(true)); } } bool OverrideProvider::IsEnabled(ContentSettingsType content_type) const { - base::AutoLock lock(lock_); - return allowed_settings_[content_type]; + base::AutoLock auto_lock(lock_); + return allowed_settings_.IsContentSettingEnabled(content_type); } void OverrideProvider::ReadOverrideSettings() { @@ -121,9 +97,10 @@ prefs_->GetDictionary(prefs::kOverrideContentSettings); for (int type = 0; type < CONTENT_SETTINGS_NUM_TYPES; ++type) { - ContentSettingsType content_setting = ContentSettingsType(type); - allowed_settings_[content_setting] = - !blocked_settings_dictionary->HasKey(GetTypeName(content_setting)); + ContentSettingsType content_type = ContentSettingsType(type); + if (blocked_settings_dictionary->HasKey(GetTypeName(content_type))) { + allowed_settings_.SetContentSettingDisabled(content_type, true); + } } }
diff --git a/components/content_settings/core/browser/content_settings_override_provider.h b/components/content_settings/core/browser/content_settings_override_provider.h index 08f3052..ca61f60 100644 --- a/components/content_settings/core/browser/content_settings_override_provider.h +++ b/components/content_settings/core/browser/content_settings_override_provider.h
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "base/synchronization/lock.h" #include "base/threading/thread_checker.h" +#include "components/content_settings/core/browser/content_settings_binary_value_map.h" #include "components/content_settings/core/browser/content_settings_provider.h" #include "components/content_settings/core/common/content_settings_types.h" @@ -59,7 +60,7 @@ void ReadOverrideSettings(); // Copies of the pref data, so that we can read it on the IO thread. - bool allowed_settings_[CONTENT_SETTINGS_NUM_TYPES]; + BinaryValueMap allowed_settings_; PrefService* prefs_;
diff --git a/components/content_settings/core/browser/content_settings_pref_provider.cc b/components/content_settings/core/browser/content_settings_pref_provider.cc index 1c0dcc35..c506051 100644 --- a/components/content_settings/core/browser/content_settings_pref_provider.cc +++ b/components/content_settings/core/browser/content_settings_pref_provider.cc
@@ -96,7 +96,7 @@ } // Read content settings exceptions. - ReadContentSettingsFromPref(false); + ReadContentSettingsFromPref(); if (!is_incognito_) { UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfExceptions", @@ -352,7 +352,7 @@ } } -void PrefProvider::ReadContentSettingsFromPref(bool overwrite) { +void PrefProvider::ReadContentSettingsFromPref() { // |DictionaryPrefUpdate| sends out notifications when destructed. This // construction order ensures |AutoLock| gets destroyed first and |lock_| is // not held when the notifications are sent. Also, |auto_reset| must be still @@ -365,8 +365,7 @@ const base::DictionaryValue* all_settings_dictionary = prefs_->GetDictionary(prefs::kContentSettingsPatternPairs); - if (overwrite) - value_map_.clear(); + value_map_.clear(); // Careful: The returned value could be NULL if the pref has never been set. if (!all_settings_dictionary) @@ -491,7 +490,7 @@ if (updating_preferences_) return; - ReadContentSettingsFromPref(true); + ReadContentSettingsFromPref(); NotifyObservers(ContentSettingsPattern(), ContentSettingsPattern(),
diff --git a/components/content_settings/core/browser/content_settings_pref_provider.h b/components/content_settings/core/browser/content_settings_pref_provider.h index 9d715897..0727e10 100644 --- a/components/content_settings/core/browser/content_settings_pref_provider.h +++ b/components/content_settings/core/browser/content_settings_pref_provider.h
@@ -68,9 +68,8 @@ private: friend class DeadlockCheckerThread; // For testing. // Reads all content settings exceptions from the preference and load them - // into the |value_map_|. The |value_map_| is cleared first if |overwrite| is - // true. - void ReadContentSettingsFromPref(bool overwrite); + // into the |value_map_|. The |value_map_| is cleared first. + void ReadContentSettingsFromPref(); // Callback for changes in the pref with the same name. void OnContentSettingsPatternPairsChanged();
diff --git a/components/content_settings/core/browser/host_content_settings_map.cc b/components/content_settings/core/browser/host_content_settings_map.cc index 386de0c..fa67b20 100644 --- a/components/content_settings/core/browser/host_content_settings_map.cc +++ b/components/content_settings/core/browser/host_content_settings_map.cc
@@ -38,6 +38,7 @@ const char* kProviderNames[] = { "platform_app", "policy", + "supervised_user", "extension", "override", "preference", @@ -57,6 +58,7 @@ content_settings::SettingSource kProviderSourceMap[] = { content_settings::SETTING_SOURCE_EXTENSION, content_settings::SETTING_SOURCE_POLICY, + content_settings::SETTING_SOURCE_SUPERVISED, content_settings::SETTING_SOURCE_EXTENSION, content_settings::SETTING_SOURCE_USER, content_settings::SETTING_SOURCE_USER,
diff --git a/components/content_settings/core/browser/host_content_settings_map.h b/components/content_settings/core/browser/host_content_settings_map.h index 285aaa8f..547b0e2 100644 --- a/components/content_settings/core/browser/host_content_settings_map.h +++ b/components/content_settings/core/browser/host_content_settings_map.h
@@ -54,6 +54,7 @@ // TODO(mukai): find the solution. INTERNAL_EXTENSION_PROVIDER = 0, POLICY_PROVIDER, + SUPERVISED_PROVIDER, CUSTOM_EXTENSION_PROVIDER, OVERRIDE_PROVIDER, PREF_PROVIDER,
diff --git a/components/content_settings/core/common/content_settings.h b/components/content_settings/core/common/content_settings.h index ae9fb93..7f49a8c 100644 --- a/components/content_settings/core/common/content_settings.h +++ b/components/content_settings/core/common/content_settings.h
@@ -60,15 +60,16 @@ namespace content_settings { // Enum containing the various source for content settings. Settings can be -// set by policy, extension or the user. Certain (internal) schemes are -// whilelisted. For whilelisted schemes the source is -// |SETTING_SOURCE_WHITELIST|. +// set by policy, extension, the user or by the custodian of a supervised user. +// Certain (internal) schemes are whilelisted. For whilelisted schemes the +// source is |SETTING_SOURCE_WHITELIST|. enum SettingSource { SETTING_SOURCE_NONE, SETTING_SOURCE_POLICY, SETTING_SOURCE_EXTENSION, SETTING_SOURCE_USER, SETTING_SOURCE_WHITELIST, + SETTING_SOURCE_SUPERVISED, }; // |SettingInfo| provides meta data for content setting values. |source|
diff --git a/components/data_reduction_proxy.gypi b/components/data_reduction_proxy.gypi index 5184706..5e133e1 100644 --- a/components/data_reduction_proxy.gypi +++ b/components/data_reduction_proxy.gypi
@@ -33,6 +33,39 @@ ], }, { + # GN version: //components/data_reduction_proxy/content/common + 'target_name': 'data_reduction_proxy_content_common', + 'type': 'static_library', + 'dependencies': [ + '../content/content.gyp:content_common', + '../ipc/ipc.gyp:ipc', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + 'data_reduction_proxy/content/common/data_reduction_proxy_messages.cc', + 'data_reduction_proxy/content/common/data_reduction_proxy_messages.h', + ], + }, + { + # GN version: //components/data_reduction_proxy/content/browser + 'target_name': 'data_reduction_proxy_content_browser', + 'type': 'static_library', + 'dependencies': [ + '../content/content.gyp:content_common', + '../ipc/ipc.gyp:ipc', + 'data_reduction_proxy_content_common', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + 'data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc', + 'data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h', + ], + }, + { # GN version: //components/data_reduction_proxy/core/browser 'target_name': 'data_reduction_proxy_core_browser', 'type': 'static_library', @@ -148,6 +181,8 @@ 'data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.cc', 'data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h', ], + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + 'msvs_disabled_warnings': [4267, ], }, { 'target_name': 'data_reduction_proxy_version_header', @@ -181,6 +216,5 @@ }, ], }, - ], }
diff --git a/components/data_reduction_proxy/OWNERS b/components/data_reduction_proxy/OWNERS index 6fe062f7..33ac864a 100644 --- a/components/data_reduction_proxy/OWNERS +++ b/components/data_reduction_proxy/OWNERS
@@ -2,3 +2,17 @@ bolian@chromium.org marq@chromium.org sclittle@chromium.org + +# Changes to IPC messages require a security review to avoid introducing +# new sandbox escapes. +per-file *_messages.*=set noparent +per-file *_messages.*=dcheng@chromium.org +per-file *_messages.*=inferno@chromium.org +per-file *_messages.*=jln@chromium.org +per-file *_messages.*=jschuh@chromium.org +per-file *_messages.*=kenrb@chromium.org +per-file *_messages.*=mkwst@chromium.org +per-file *_messages.*=nasko@chromium.org +per-file *_messages.*=palmer@chromium.org +per-file *_messages.*=tsepez@chromium.org +per-file *_messages.*=wfh@chromium.org
diff --git a/components/data_reduction_proxy/content/browser/BUILD.gn b/components/data_reduction_proxy/content/browser/BUILD.gn index 950e947..43af69b 100644 --- a/components/data_reduction_proxy/content/browser/BUILD.gn +++ b/components/data_reduction_proxy/content/browser/BUILD.gn
@@ -4,40 +4,64 @@ static_library("browser") { sources = [ - "content_data_reduction_proxy_debug_ui_service.cc", - "content_data_reduction_proxy_debug_ui_service.h", - "data_reduction_proxy_debug_blocking_page.cc", - "data_reduction_proxy_debug_blocking_page.h", - "data_reduction_proxy_debug_resource_throttle.cc", - "data_reduction_proxy_debug_resource_throttle.h", - "data_reduction_proxy_debug_ui_manager.cc", - "data_reduction_proxy_debug_ui_manager.h", + "data_reduction_proxy_message_filter.cc", + "data_reduction_proxy_message_filter.h", ] deps = [ "//base", - "//components/resources", - "//components/strings", + "//components/data_reduction_proxy/content/common", "//content/public/browser", - "//skia", - "//ui/base", + "//ipc", + "//net", ] + + if (is_android) { + sources += [ + "content_data_reduction_proxy_debug_ui_service.cc", + "content_data_reduction_proxy_debug_ui_service.h", + "data_reduction_proxy_debug_blocking_page.cc", + "data_reduction_proxy_debug_blocking_page.h", + "data_reduction_proxy_debug_resource_throttle.cc", + "data_reduction_proxy_debug_resource_throttle.h", + "data_reduction_proxy_debug_ui_manager.cc", + "data_reduction_proxy_debug_ui_manager.h", + ] + + deps += [ + "//components/resources", + "//components/strings", + "//skia", + "//ui/base", + ] + } } -if (is_android) { - source_set("unit_tests") { - testonly = true - sources = [ +source_set("unit_tests") { + testonly = true + sources = [ + "data_reduction_proxy_message_filter_unittest.cc", + ] + + deps = [ + ":browser", + "//base", + "//components/data_reduction_proxy/core/browser:test_support", + "//components/data_reduction_proxy/core/common:test_support", + "//net", + "//testing/gtest", + "//testing/gmock", + ] + + if (is_android) { + sources += [ "data_reduction_proxy_debug_blocking_page_unittest.cc", "data_reduction_proxy_debug_resource_throttle_unittest.cc", "data_reduction_proxy_debug_ui_manager_unittest.cc", ] - deps = [ - ":browser", + deps += [ "//skia", - "//testing/gtest", - "//testing/gmock", "//third_party/mojo/src/mojo/public/cpp/bindings", ] }
diff --git a/components/data_reduction_proxy/content/browser/DEPS b/components/data_reduction_proxy/content/browser/DEPS new file mode 100644 index 0000000..897bf2a --- /dev/null +++ b/components/data_reduction_proxy/content/browser/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+ipc", + "+net", +] \ No newline at end of file
diff --git a/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc new file mode 100644 index 0000000..e01c4998 --- /dev/null +++ b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc
@@ -0,0 +1,54 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h" + +#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h" +#include "content/public/browser/browser_thread.h" +#include "ipc/ipc_message_macros.h" +#include "net/base/host_port_pair.h" + +namespace data_reduction_proxy { + +DataReductionProxyMessageFilter::DataReductionProxyMessageFilter( + DataReductionProxySettings* settings) + : BrowserMessageFilter(DataReductionProxyStart), + config_(nullptr) { + DCHECK(settings); + config_ = settings->Config(); +} + +DataReductionProxyMessageFilter::~DataReductionProxyMessageFilter() { +} + +bool DataReductionProxyMessageFilter::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(DataReductionProxyMessageFilter, message) + IPC_MESSAGE_HANDLER(DataReductionProxyViewHostMsg_IsDataReductionProxy, + OnIsDataReductionProxy) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void DataReductionProxyMessageFilter::OverrideThreadForMessage( + const IPC::Message& message, content::BrowserThread::ID* thread) { + if (message.type() == + DataReductionProxyViewHostMsg_IsDataReductionProxy::ID) { + *thread = content::BrowserThread::IO; + } +} + +void DataReductionProxyMessageFilter::OnIsDataReductionProxy( + const net::HostPortPair& proxy_server, bool* response) { + if (config_) + *response = config_->IsDataReductionProxy(proxy_server, nullptr); + else + *response = false; +} + +} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h new file mode 100644 index 0000000..c7b3dcc4 --- /dev/null +++ b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h
@@ -0,0 +1,47 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CONTENT_BROWSER_DATA_REDUCTION_PROXY_MESSAGE_FILTER_H_ +#define COMPONENTS_DATA_REDUCTION_PROXY_CONTENT_BROWSER_DATA_REDUCTION_PROXY_MESSAGE_FILTER_H_ + +#include "base/macros.h" +#include "content/public/browser/browser_message_filter.h" + +namespace net { +class HostPortPair; +} + +namespace data_reduction_proxy { + +class DataReductionProxyConfig; +class DataReductionProxySettings; + +// An IPC listener to handle DataReductionProxy IPC messages from the renderer. +class DataReductionProxyMessageFilter + : public content::BrowserMessageFilter { + public: + DataReductionProxyMessageFilter(DataReductionProxySettings* settings); + + // Sets |response| to true if the |proxy_server| corresponds to a Data + // Reduction Proxy. + void OnIsDataReductionProxy(const net::HostPortPair& proxy_server, + bool* response); + + private: + ~DataReductionProxyMessageFilter() override; + + // BrowserMessageFilter implementation. + bool OnMessageReceived(const IPC::Message& message) override; + void OverrideThreadForMessage(const IPC::Message& message, + content::BrowserThread::ID* thread) override; + + // Must outlive |this|. + DataReductionProxyConfig* config_; + + DISALLOW_COPY_AND_ASSIGN(DataReductionProxyMessageFilter); +}; + +} // namespace data_reduction_proxy + +#endif // COMPONENTS_DATA_REDUCTION_PROXY_CONTENT_BROWSER_DATA_REDUCTION_PROXY_MESSAGE_FILTER_H_
diff --git a/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc new file mode 100644 index 0000000..ab2252b --- /dev/null +++ b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc
@@ -0,0 +1,64 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h" + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h" +#include "net/base/host_port_pair.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace data_reduction_proxy { + +class DataReductionProxyMessageFilterTest : public testing::Test { + public: + void SetUp() override { + test_context_ = + DataReductionProxyTestContext::Builder() + .WithParamsFlags(DataReductionProxyParams::kAllowed) + .WithParamsDefinitions(TestDataReductionProxyParams::HAS_EVERYTHING) + .WithMockConfig() + .Build(); + message_filter_ = new DataReductionProxyMessageFilter( + test_context_->settings()); + } + + protected: + DataReductionProxyMessageFilter* message_filter() const { + return message_filter_.get(); + } + + MockDataReductionProxyConfig* config() const { + return test_context_->mock_config(); + } + + private: + scoped_ptr<DataReductionProxyTestContext> test_context_; + scoped_refptr<DataReductionProxyMessageFilter> message_filter_; +}; + +TEST_F(DataReductionProxyMessageFilterTest, TestOnIsDataReductionProxy) { + net::HostPortPair proxy_server = + net::HostPortPair::FromString("www.google.com:443"); + bool is_data_reduction_proxy = false; + EXPECT_CALL(*config(), IsDataReductionProxy(testing::_, nullptr)) + .Times(1) + .WillOnce(testing::Return(true)); + message_filter()->OnIsDataReductionProxy(proxy_server, + &is_data_reduction_proxy); + EXPECT_TRUE(is_data_reduction_proxy); + + EXPECT_CALL(*config(), IsDataReductionProxy(testing::_, nullptr)) + .Times(1) + .WillOnce(testing::Return(false)); + message_filter()->OnIsDataReductionProxy(proxy_server, + &is_data_reduction_proxy); + EXPECT_FALSE(is_data_reduction_proxy); +} + +} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/content/common/BUILD.gn b/components/data_reduction_proxy/content/common/BUILD.gn new file mode 100644 index 0000000..cb33fbe --- /dev/null +++ b/components/data_reduction_proxy/content/common/BUILD.gn
@@ -0,0 +1,16 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +static_library("common") { + sources = [ + "data_reduction_proxy_messages.cc", + "data_reduction_proxy_messages.h", + ] + + deps = [ + "//content/public/common", + "//ipc", + "//net", + ] +}
diff --git a/components/data_reduction_proxy/content/common/DEPS b/components/data_reduction_proxy/content/common/DEPS new file mode 100644 index 0000000..c3505fa --- /dev/null +++ b/components/data_reduction_proxy/content/common/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+content/public/common", + "+ipc", +]
diff --git a/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.cc b/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.cc new file mode 100644 index 0000000..bfa8356a --- /dev/null +++ b/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.cc
@@ -0,0 +1,33 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Get basic type definitions. +#define IPC_MESSAGE_IMPL +#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h" + +// Generate constructors. +#include "ipc/struct_constructor_macros.h" +#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h" + +// Generate destructors. +#include "ipc/struct_destructor_macros.h" +#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h" + +// Generate param traits write methods. +#include "ipc/param_traits_write_macros.h" +namespace IPC { +#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h" +} // namespace IPC + +// Generate param traits read methods. +#include "ipc/param_traits_read_macros.h" +namespace IPC { +#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h" +} // namespace IPC + +// Generate param traits log methods. +#include "ipc/param_traits_log_macros.h" +namespace IPC { +#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h" +} // namespace IPC
diff --git a/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h b/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h new file mode 100644 index 0000000..c7b852e --- /dev/null +++ b/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h
@@ -0,0 +1,15 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Multiply-included file, no traditional include guard. +#include "content/public/common/common_param_traits.h" +#include "ipc/ipc_message_macros.h" +#include "net/base/host_port_pair.h" + +#define IPC_MESSAGE_START DataReductionProxyStart + +IPC_SYNC_MESSAGE_CONTROL1_1( + DataReductionProxyViewHostMsg_IsDataReductionProxy, + net::HostPortPair /* proxy server */, + bool /* true iff the proxy server is a Data Reduction Proxy */)
diff --git a/components/data_reduction_proxy/core/browser/BUILD.gn b/components/data_reduction_proxy/core/browser/BUILD.gn index c1e75c3..0bc2867 100644 --- a/components/data_reduction_proxy/core/browser/BUILD.gn +++ b/components/data_reduction_proxy/core/browser/BUILD.gn
@@ -64,6 +64,8 @@ "data_reduction_proxy_test_utils.h", ] + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + public_deps = [ ":browser", ]
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.cc index afab0b55..773015c 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.cc
@@ -34,9 +34,23 @@ return nullptr; } +net::URLRequestJob* DataReductionProxyInterceptor::MaybeInterceptRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const GURL& location) const { + return MaybeInterceptResponseOrRedirect(request, network_delegate); +} + net::URLRequestJob* DataReductionProxyInterceptor::MaybeInterceptResponse( net::URLRequest* request, net::NetworkDelegate* network_delegate) const { + return MaybeInterceptResponseOrRedirect(request, network_delegate); +} + +net::URLRequestJob* +DataReductionProxyInterceptor::MaybeInterceptResponseOrRedirect( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const { if (request->response_info().was_cached) return nullptr; DataReductionProxyBypassType bypass_type = BYPASS_EVENT_TYPE_MAX;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h index f78c11e4..0e24814 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h
@@ -15,7 +15,7 @@ class DataReductionProxyUsageStats; // Used to intercept responses that contain explicit and implicit signals -// to bypass the data reduction proxy. If the proxy should be bypassed, +// to bypass the Data Reduction Proxy. If the proxy should be bypassed, // the interceptor returns a new URLRequestHTTPJob that fetches the resource // without use of the proxy. class DataReductionProxyInterceptor : public net::URLRequestInterceptor { @@ -34,15 +34,28 @@ net::URLRequest* request, net::NetworkDelegate* network_delegate) const override; - // Returns a new URLRequestHTTPJob if the response indicates that the data - // reduction proxy should be bypassed according to the rules in |protocol_|. - // Returns NULL otherwise. If a job is returned, the interceptor's - // URLRequestInterceptingJobFactory will restart the request. + // Returns a new URLRequestHTTPJob if the redirect indicates that the Data + // Reduction Proxy should be bypassed. See |MaybeInterceptResponseOrRedirect| + // for more details. + net::URLRequestJob* MaybeInterceptRedirect( + net::URLRequest* request, net::NetworkDelegate* network_delegate, + const GURL& location) const override; + + // Returns a new URLRequestHTTPJob if the response indicates that the Data + // Reduction Proxy should be bypassed. See |MaybeInterceptResponseOrRedirect| + // for more details. net::URLRequestJob* MaybeInterceptResponse( net::URLRequest* request, net::NetworkDelegate* network_delegate) const override; private: + // Returns a new URLRequestHTTPJob if the response or redirect indicates that + // the data reduction proxy should be bypassed according to the rules in + // |bypass_protocol_|. Returns NULL otherwise. If a job is returned, the + // interceptor's URLRequestInterceptingJobFactory will restart the request. + net::URLRequestJob* MaybeInterceptResponseOrRedirect( + net::URLRequest* request, net::NetworkDelegate* network_delegate) const; + // Must outlive |this| if non-NULL. DataReductionProxyUsageStats* usage_stats_;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc index 29c4f9e..2edcff89c 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
@@ -5,23 +5,31 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h" #include <string> +#include <vector> #include "base/files/file_path.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" #include "base/message_loop/message_loop.h" +#include "base/prefs/pref_service.h" #include "base/run_loop.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" #include "net/base/capturing_net_log.h" +#include "net/base/net_errors.h" #include "net/base/request_priority.h" #include "net/http/http_response_headers.h" #include "net/proxy/proxy_server.h" +#include "net/socket/socket_test_util.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/url_request/url_request.h" +#include "net/url_request/url_request_context_storage.h" #include "net/url_request/url_request_intercepting_job_factory.h" #include "net/url_request/url_request_interceptor.h" #include "net/url_request/url_request_job.h" @@ -30,8 +38,12 @@ #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" +using net::MockRead; + namespace data_reduction_proxy { +namespace { + class CountingURLRequestInterceptor : public net::URLRequestInterceptor { public: CountingURLRequestInterceptor() @@ -264,4 +276,206 @@ EXPECT_EQ("hello", delegate.data_received()); } +class DataReductionProxyInterceptorEndToEndTest : public testing::Test { + public: + DataReductionProxyInterceptorEndToEndTest() + : context_(true), context_storage_(&context_) {} + + ~DataReductionProxyInterceptorEndToEndTest() override {} + + void SetUp() override { + drp_test_context_ = + DataReductionProxyTestContext::Builder() + .WithParamsFlags(DataReductionProxyParams::kAllowed | + DataReductionProxyParams::kFallbackAllowed) + .WithParamsDefinitions( + TestDataReductionProxyParams::HAS_EVERYTHING & + ~TestDataReductionProxyParams::HAS_DEV_ORIGIN & + ~TestDataReductionProxyParams::HAS_DEV_FALLBACK_ORIGIN) + .WithURLRequestContext(&context_) + .WithMockClientSocketFactory(&mock_socket_factory_) + .Build(); + drp_test_context_->AttachToURLRequestContext(&context_storage_); + context_.set_client_socket_factory(&mock_socket_factory_); + context_.Init(); + drp_test_context_->EnableDataReductionProxyWithSecureProxyCheckSuccess(); + + // Three proxies should be available for use: primary, fallback, and direct. + const net::ProxyConfig& proxy_config = + drp_test_context_->configurator()->GetProxyConfigOnIOThread(); + EXPECT_EQ(3U, proxy_config.proxy_rules().proxies_for_http.size()); + } + + // Creates a URLRequest using the test's TestURLRequestContext and executes + // it. Returns the created URLRequest. + scoped_ptr<net::URLRequest> CreateAndExecuteRequest(const GURL& url) { + scoped_ptr<net::URLRequest> request( + context_.CreateRequest(url, net::IDLE, &delegate_, NULL)); + request->Start(); + drp_test_context_->RunUntilIdle(); + return request.Pass(); + } + + const net::TestDelegate& delegate() const { + return delegate_; + } + + net::MockClientSocketFactory* mock_socket_factory() { + return &mock_socket_factory_; + } + + DataReductionProxyConfig* config() const { + return drp_test_context_->config(); + } + + private: + net::TestDelegate delegate_; + net::MockClientSocketFactory mock_socket_factory_; + net::TestURLRequestContext context_; + net::URLRequestContextStorage context_storage_; + scoped_ptr<DataReductionProxyTestContext> drp_test_context_; +}; + +const std::string kBody = "response body"; + +TEST_F(DataReductionProxyInterceptorEndToEndTest, ResponseWithoutRetry) { + // The response comes through the proxy and should not be retried. + MockRead mock_reads[] = { + MockRead("HTTP/1.1 200 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n"), + MockRead(kBody.c_str()), + MockRead(net::SYNCHRONOUS, net::OK), + }; + net::StaticSocketDataProvider socket_data_provider( + mock_reads, arraysize(mock_reads), nullptr, 0); + mock_socket_factory()->AddSocketDataProvider(&socket_data_provider); + + scoped_ptr<net::URLRequest> request = + CreateAndExecuteRequest(GURL("http://foo.com")); + + EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status()); + EXPECT_EQ(200, request->GetResponseCode()); + EXPECT_EQ(kBody, delegate().data_received()); + EXPECT_EQ(config()->Origin().host_port_pair().ToString(), + request->proxy_server().ToString()); +} + +TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectWithoutRetry) { + // The redirect comes through the proxy and should not be retried. + MockRead redirect_mock_reads[] = { + MockRead("HTTP/1.1 302 Found\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n" + "Location: http://bar.com/\r\n\r\n"), + MockRead(""), + MockRead(net::SYNCHRONOUS, net::OK), + }; + net::StaticSocketDataProvider redirect_socket_data_provider( + redirect_mock_reads, arraysize(redirect_mock_reads), nullptr, 0); + mock_socket_factory()->AddSocketDataProvider(&redirect_socket_data_provider); + + // The response after the redirect comes through proxy and should not be + // retried. + MockRead response_mock_reads[] = { + MockRead("HTTP/1.1 200 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n"), + MockRead(kBody.c_str()), + MockRead(net::SYNCHRONOUS, net::OK), + }; + net::StaticSocketDataProvider response_socket_data_provider( + response_mock_reads, arraysize(response_mock_reads), nullptr, 0); + mock_socket_factory()->AddSocketDataProvider(&response_socket_data_provider); + + scoped_ptr<net::URLRequest> request = + CreateAndExecuteRequest(GURL("http://foo.com")); + + EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status()); + EXPECT_EQ(200, request->GetResponseCode()); + EXPECT_EQ(kBody, delegate().data_received()); + EXPECT_EQ(config()->Origin().host_port_pair().ToString(), + request->proxy_server().ToString()); + // The redirect should have been processed and followed normally. + EXPECT_EQ(1, delegate().received_redirect_count()); +} + +TEST_F(DataReductionProxyInterceptorEndToEndTest, ResponseWithBypassAndRetry) { + // The first try gives a bypass. + MockRead initial_mock_reads[] = { + MockRead("HTTP/1.1 502 Bad Gateway\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n" + "Chrome-Proxy: block-once\r\n\r\n"), + MockRead(""), + MockRead(net::SYNCHRONOUS, net::OK), + }; + net::StaticSocketDataProvider initial_socket_data_provider( + initial_mock_reads, arraysize(initial_mock_reads), nullptr, 0); + mock_socket_factory()->AddSocketDataProvider(&initial_socket_data_provider); + + // The retry after the bypass is successful. + MockRead retry_mock_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n\r\n"), + MockRead(kBody.c_str()), + MockRead(net::SYNCHRONOUS, net::OK), + }; + net::StaticSocketDataProvider retry_socket_data_provider( + retry_mock_reads, arraysize(retry_mock_reads), nullptr, 0); + mock_socket_factory()->AddSocketDataProvider(&retry_socket_data_provider); + + scoped_ptr<net::URLRequest> request = CreateAndExecuteRequest( + GURL("http://foo.com")); + + EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status()); + EXPECT_EQ(200, request->GetResponseCode()); + EXPECT_EQ(kBody, delegate().data_received()); + EXPECT_FALSE(request->was_fetched_via_proxy()); + // The bypassed response should have been intercepted before the response was + // processed, so only the final response after the retry should have been + // processed. + EXPECT_EQ(1, delegate().response_started_count()); +} + +TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectWithBypassAndRetry) { + MockRead mock_reads_array[][3] = { + // First, get a redirect without a via header, which should be retried + // using the fallback proxy. + { + MockRead("HTTP/1.1 302 Found\r\n" + "Location: http://bar.com/\r\n\r\n"), + MockRead(""), + MockRead(net::SYNCHRONOUS, net::OK), + }, + // Same as before, but through the fallback proxy. Now both proxies are + // bypassed, and the request should be retried over direct. + { + MockRead("HTTP/1.1 302 Found\r\n" + "Location: http://baz.com/\r\n\r\n"), + MockRead(""), + MockRead(net::SYNCHRONOUS, net::OK), + }, + // Finally, a successful response is received. + { + MockRead("HTTP/1.1 200 OK\r\n\r\n"), + MockRead(kBody.c_str()), + MockRead(net::SYNCHRONOUS, net::OK), + }, + }; + ScopedVector<net::SocketDataProvider> socket_data_providers; + for (MockRead* mock_reads : mock_reads_array) { + socket_data_providers.push_back( + new net::StaticSocketDataProvider(mock_reads, 3, nullptr, 0)); + mock_socket_factory()->AddSocketDataProvider(socket_data_providers.back()); + } + + scoped_ptr<net::URLRequest> request = + CreateAndExecuteRequest(GURL("http://foo.com")); + + EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status()); + EXPECT_EQ(200, request->GetResponseCode()); + EXPECT_EQ(kBody, delegate().data_received()); + EXPECT_FALSE(request->was_fetched_via_proxy()); + + // Each of the redirects should have been intercepted before being followed. + EXPECT_EQ(0, delegate().received_redirect_count()); + EXPECT_EQ(std::vector<GURL>(1, GURL("http://foo.com")), request->url_chain()); +} + +} // namespace + } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h index d6fdd48..5570deb 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
@@ -169,6 +169,12 @@ return data_reduction_proxy_service_.get(); } + // Returns the |DataReductionProxyConfig| being used. May be null if + // InitDataReductionProxySettings has not been called. + DataReductionProxyConfig* Config() const { + return config_; + } + // Permits changing the underlying |DataReductionProxyConfig| without running // the initialization loop. void ResetConfigForTest(DataReductionProxyConfig* config) { @@ -176,12 +182,6 @@ } protected: - // Returns the |DataReductionProxyConfig| being used. May be null if - // InitDataReductionProxySettings has not been called. - DataReductionProxyConfig* Config() const { - return config_; - } - void InitPrefMembers(); void UpdateConfigValues();
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc index d688d76..fd41eda 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -9,12 +9,17 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_test_utils.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_statistics_prefs.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h" +#include "net/socket/socket_test_util.h" +#include "net/url_request/url_request_context_storage.h" +#include "net/url_request/url_request_intercepting_job_factory.h" +#include "net/url_request/url_request_job_factory_impl.h" #include "net/url_request/url_request_test_util.h" namespace data_reduction_proxy { @@ -56,6 +61,7 @@ params_definitions_(0), client_(Client::UNKNOWN), request_context_(nullptr), + mock_socket_factory_(nullptr), use_mock_config_(false), use_test_configurator_(false), use_mock_service_(false), @@ -83,6 +89,13 @@ } DataReductionProxyTestContext::Builder& +DataReductionProxyTestContext::Builder::WithMockClientSocketFactory( + net::MockClientSocketFactory* mock_socket_factory) { + mock_socket_factory_ = mock_socket_factory; + return *this; +} + +DataReductionProxyTestContext::Builder& DataReductionProxyTestContext::Builder::WithClient(Client client) { client_ = client; return *this; @@ -127,7 +140,13 @@ request_context_getter = new net::TrivialURLRequestContextGetter( request_context_, task_runner); } else { - request_context_getter = new net::TestURLRequestContextGetter(task_runner); + scoped_ptr<net::TestURLRequestContext> test_request_context( + new net::TestURLRequestContext(true)); + if (mock_socket_factory_) + test_request_context->set_client_socket_factory(mock_socket_factory_); + test_request_context->Init(); + request_context_getter = new net::TestURLRequestContextGetter( + task_runner, test_request_context.Pass()); } scoped_ptr<DataReductionProxyEventStore> event_store( @@ -176,8 +195,8 @@ scoped_ptr<DataReductionProxyTestContext> test_context( new DataReductionProxyTestContext( loop.Pass(), task_runner, pref_service.Pass(), net_log.Pass(), - request_context_getter, io_data.Pass(), settings.Pass(), - test_context_flags)); + request_context_getter, mock_socket_factory_, io_data.Pass(), + settings.Pass(), test_context_flags)); if (!skip_settings_initialization_) test_context->InitSettingsWithoutCheck(); @@ -191,6 +210,7 @@ scoped_ptr<TestingPrefServiceSimple> simple_pref_service, scoped_ptr<net::CapturingNetLog> net_log, scoped_refptr<net::URLRequestContextGetter> request_context_getter, + net::MockClientSocketFactory* mock_socket_factory, scoped_ptr<TestDataReductionProxyIOData> io_data, scoped_ptr<DataReductionProxySettings> settings, unsigned int test_context_flags) @@ -200,6 +220,7 @@ simple_pref_service_(simple_pref_service.Pass()), net_log_(net_log.Pass()), request_context_getter_(request_context_getter), + mock_socket_factory_(mock_socket_factory), io_data_(io_data.Pass()), settings_(settings.Pass()) { } @@ -249,6 +270,51 @@ } } +void DataReductionProxyTestContext::AttachToURLRequestContext( + net::URLRequestContextStorage* request_context_storage) const { + DCHECK(request_context_storage); + + // |request_context_storage| takes ownership of the network delegate. + request_context_storage->set_network_delegate( + io_data()->CreateNetworkDelegate( + scoped_ptr<net::NetworkDelegate>(new net::TestNetworkDelegate()), + true).release()); + + // |request_context_storage| takes ownership of the job factory. + request_context_storage->set_job_factory( + new net::URLRequestInterceptingJobFactory( + scoped_ptr<net::URLRequestJobFactory>( + new net::URLRequestJobFactoryImpl()), + io_data()->CreateInterceptor().Pass())); +} + +void DataReductionProxyTestContext:: + EnableDataReductionProxyWithSecureProxyCheckSuccess() { + DCHECK(mock_socket_factory_); + // This won't actually update the proxy config when using a test configurator. + DCHECK(!(test_context_flags_ & + DataReductionProxyTestContext::USE_TEST_CONFIGURATOR)); + // |settings_| needs to have been initialized, since a + // |DataReductionProxyService| is needed in order to issue the secure proxy + // check. + DCHECK(data_reduction_proxy_service()); + + // Enable the Data Reduction Proxy, simulating a successful secure proxy + // check. + net::MockRead mock_reads[] = { + net::MockRead("HTTP/1.1 200 OK\r\n\r\n"), + net::MockRead("OK"), + net::MockRead(net::SYNCHRONOUS, net::OK), + }; + net::StaticSocketDataProvider socket_data_provider( + mock_reads, arraysize(mock_reads), nullptr, 0); + mock_socket_factory_->AddSocketDataProvider(&socket_data_provider); + + // Set the pref to cause the secure proxy check to be issued. + pref_service()->SetBoolean(prefs::kDataReductionProxyEnabled, true); + RunUntilIdle(); +} + TestDataReductionProxyConfigurator* DataReductionProxyTestContext::test_configurator() const { DCHECK(test_context_flags_ &
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h index 5d03224..37fbabb 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
@@ -21,9 +21,11 @@ } namespace net { +class MockClientSocketFactory; class NetLog; class URLRequestContext; class URLRequestContextGetter; +class URLRequestContextStorage; } namespace data_reduction_proxy { @@ -94,6 +96,15 @@ // owned by the caller. Builder& WithURLRequestContext(net::URLRequestContext* request_context); + // Specifies a |net::MockClientSocketFactory| to use. The + // |mock_socket_factory| is owned by the caller. If a non-NULL + // |request_context_| is also specified, then the caller is responsible for + // attaching |mock_socket_factory| to |request_context_|. Otherwise, + // |mock_socket_factory| will be attached to the dummy + // |net::URLRequestContext| generated during Build(). + Builder& WithMockClientSocketFactory( + net::MockClientSocketFactory* mock_socket_factory); + // Specifies the use of |MockDataReductionProxyConfig| instead of // |TestDataReductionProxyConfig|. Builder& WithMockConfig(); @@ -117,6 +128,7 @@ unsigned int params_definitions_; Client client_; net::URLRequestContext* request_context_; + net::MockClientSocketFactory* mock_socket_factory_; bool use_mock_config_; bool use_test_configurator_; @@ -139,6 +151,19 @@ // SkipSettingsInitialization. scoped_ptr<DataReductionProxyService> CreateDataReductionProxyService(); + // This creates a |DataReductionProxyNetworkDelegate| and + // |DataReductionProxyInterceptor|, using them in the |net::URLRequestContext| + // for |request_context_storage|. |request_context_storage| takes ownership of + // the created objects. + void AttachToURLRequestContext( + net::URLRequestContextStorage* request_context_storage) const; + + // Enable the Data Reduction Proxy, simulating a successful secure proxy + // check. This can only be called if not built with WithTestConfigurator, + // |settings_| has been initialized, and |this| was built with a + // |net::MockClientSocketFactory| specified. + void EnableDataReductionProxyWithSecureProxyCheckSuccess(); + // Returns the underlying |TestDataReductionProxyConfigurator|. This can only // be called if built with WithTestConfigurator. TestDataReductionProxyConfigurator* test_configurator() const; @@ -210,6 +235,7 @@ scoped_ptr<TestingPrefServiceSimple> simple_pref_service, scoped_ptr<net::CapturingNetLog> net_log, scoped_refptr<net::URLRequestContextGetter> request_context_getter, + net::MockClientSocketFactory* mock_socket_factory, scoped_ptr<TestDataReductionProxyIOData> io_data, scoped_ptr<DataReductionProxySettings> settings, unsigned int test_context_flags); @@ -227,6 +253,9 @@ scoped_ptr<TestingPrefServiceSimple> simple_pref_service_; scoped_ptr<net::CapturingNetLog> net_log_; scoped_refptr<net::URLRequestContextGetter> request_context_getter_; + // Non-owned pointer. Will be NULL if |this| was built without specifying a + // |net::MockClientSocketFactory|. + net::MockClientSocketFactory* mock_socket_factory_; scoped_ptr<TestDataReductionProxyIOData> io_data_; scoped_ptr<DataReductionProxySettings> settings_;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats_unittest.cc index 8278b51..51afeba 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats_unittest.cc
@@ -33,6 +33,7 @@ #include "net/socket/socket_test_util.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_context_getter.h" +#include "net/url_request/url_request_context_storage.h" #include "net/url_request/url_request_intercepting_job_factory.h" #include "net/url_request/url_request_interceptor.h" #include "net/url_request/url_request_job_factory_impl.h" @@ -554,11 +555,11 @@ class DataReductionProxyUsageStatsEndToEndTest : public testing::Test { public: DataReductionProxyUsageStatsEndToEndTest() - : context_(true) {} + : context_(true), context_storage_(&context_) {} ~DataReductionProxyUsageStatsEndToEndTest() override { - test_context_->io_data()->ShutdownOnUIThread(); - test_context_->RunUntilIdle(); + drp_test_context_->io_data()->ShutdownOnUIThread(); + drp_test_context_->RunUntilIdle(); } void SetUp() override { @@ -566,33 +567,18 @@ // test bypassed bytes due to proxy fallbacks. This way, a test just needs // to cause one proxy fallback in order for the data reduction proxy to be // fully bypassed. - test_context_ = + drp_test_context_ = DataReductionProxyTestContext::Builder() .WithParamsFlags(DataReductionProxyParams::kAllowed) - .WithParamsDefinitions(TestDataReductionProxyParams::HAS_ORIGIN) + .WithParamsDefinitions( + TestDataReductionProxyParams::HAS_EVERYTHING & + ~TestDataReductionProxyParams::HAS_DEV_ORIGIN & + ~TestDataReductionProxyParams::HAS_DEV_FALLBACK_ORIGIN) .WithURLRequestContext(&context_) - .SkipSettingsInitialization() + .WithMockClientSocketFactory(&mock_socket_factory_) .Build(); - test_context_->pref_service()->SetBoolean(prefs::kDataReductionProxyEnabled, - true); - test_context_->InitSettings(); - - network_delegate_ = test_context_->io_data()->CreateNetworkDelegate( - scoped_ptr<net::NetworkDelegate>(new net::TestNetworkDelegate()), true); - context_.set_network_delegate(network_delegate_.get()); - + drp_test_context_->AttachToURLRequestContext(&context_storage_); context_.set_client_socket_factory(&mock_socket_factory_); - - job_factory_.reset(new net::URLRequestInterceptingJobFactory( - scoped_ptr<net::URLRequestJobFactory>( - new net::URLRequestJobFactoryImpl()), - test_context_->io_data()->CreateInterceptor().Pass())); - context_.set_job_factory(job_factory_.get()); - - test_context_->configurator()->Enable(false, true, - config()->Origin().ToURI(), - std::string(), std::string()); - test_context_->RunUntilIdle(); } // Create and execute a fake request using the data reduction proxy stack. @@ -640,7 +626,7 @@ request->set_method("GET"); request->SetLoadFlags(net::LOAD_NORMAL); request->Start(); - test_context_->RunUntilIdle(); + drp_test_context_->RunUntilIdle(); } void set_proxy_service(net::ProxyService* proxy_service) { @@ -652,11 +638,11 @@ } const DataReductionProxySettings* settings() const { - return test_context_->settings(); + return drp_test_context_->settings(); } DataReductionProxyConfig* config() const { - return test_context_->config(); + return drp_test_context_->config(); } void ClearBadProxies() { @@ -665,6 +651,7 @@ void InitializeContext() { context_.Init(); + drp_test_context_->EnableDataReductionProxyWithSecureProxyCheckSuccess(); } void ExpectOtherBypassedBytesHistogramsEmpty( @@ -723,10 +710,9 @@ private: net::TestDelegate delegate_; net::MockClientSocketFactory mock_socket_factory_; - scoped_ptr<DataReductionProxyNetworkDelegate> network_delegate_; - scoped_ptr<net::URLRequestJobFactory> job_factory_; net::TestURLRequestContext context_; - scoped_ptr<DataReductionProxyTestContext> test_context_; + net::URLRequestContextStorage context_storage_; + scoped_ptr<DataReductionProxyTestContext> drp_test_context_; }; TEST_F(DataReductionProxyUsageStatsEndToEndTest, BypassedBytesNoRetry) {
diff --git a/components/history/core/browser/history_client.cc b/components/history/core/browser/history_client.cc index 194a616..f73ae1f 100644 --- a/components/history/core/browser/history_client.cc +++ b/components/history/core/browser/history_client.cc
@@ -19,6 +19,10 @@ void HistoryClient::GetBookmarks(std::vector<URLAndTitle>* bookmarks) { } +bool HistoryClient::CanAddURL(const GURL& url) { + return true; +} + void HistoryClient::NotifyProfileError(sql::InitStatus init_status) { }
diff --git a/components/history/core/browser/history_client.h b/components/history/core/browser/history_client.h index 9bfb193..9b71814 100644 --- a/components/history/core/browser/history_client.h +++ b/components/history/core/browser/history_client.h
@@ -52,6 +52,10 @@ // If not on the main thread, then BlockUntilBookmarksLoaded must be called. virtual void GetBookmarks(std::vector<URLAndTitle>* bookmarks); + // Returns true if this look like the type of URL that should be added to the + // history. + virtual bool CanAddURL(const GURL& url); + // Notifies the embedder that there was a problem reading the database. // // Must be called from the main thread.
diff --git a/components/json_schema/json_schema_validator_unittest_base.cc b/components/json_schema/json_schema_validator_unittest_base.cc index 8d2859e..6a5f853 100644 --- a/components/json_schema/json_schema_validator_unittest_base.cc +++ b/components/json_schema/json_schema_validator_unittest_base.cc
@@ -36,8 +36,8 @@ EXPECT_TRUE(base::PathExists(path)); std::string error_message; - JSONFileValueSerializer serializer(path); - base::Value* result = serializer.Deserialize(NULL, &error_message); + JSONFileValueDeserializer deserializer(path); + base::Value* result = deserializer.Deserialize(NULL, &error_message); if (!result) ADD_FAILURE() << "Could not parse JSON: " << error_message; return result;
diff --git a/components/keyed_service/core/keyed_service_base_factory.cc b/components/keyed_service/core/keyed_service_base_factory.cc index ddaf497..7157c0e 100644 --- a/components/keyed_service/core/keyed_service_base_factory.cc +++ b/components/keyed_service/core/keyed_service_base_factory.cc
@@ -6,10 +6,13 @@ #include "base/prefs/pref_service.h" #include "base/supports_user_data.h" +#include "base/trace_event/trace_event.h" #include "components/keyed_service/core/dependency_manager.h" void KeyedServiceBaseFactory::RegisterUserPrefsOnContextForTest( base::SupportsUserData* context) { + TRACE_EVENT0("browser,startup", + "KeyedServiceBaseFactory::RegisterUserPrefsOnContextForTest"); // Safe timing for pref registration is hard. Previously, we made // context responsible for all pref registration on every service // that used contexts. Now we don't and there are timing issues.
diff --git a/components/keyed_service/core/keyed_service_factory.cc b/components/keyed_service/core/keyed_service_factory.cc index 261ff29d..1417bab 100644 --- a/components/keyed_service/core/keyed_service_factory.cc +++ b/components/keyed_service/core/keyed_service_factory.cc
@@ -6,6 +6,7 @@ #include "base/logging.h" #include "base/stl_util.h" +#include "base/trace_event/trace_event.h" #include "components/keyed_service/core/dependency_manager.h" #include "components/keyed_service/core/keyed_service.h" @@ -58,6 +59,7 @@ KeyedService* KeyedServiceFactory::GetServiceForContext( base::SupportsUserData* context, bool create) { + TRACE_EVENT0("browser,startup", "KeyedServiceFactory::GetServiceForContext"); context = GetContextToUse(context); if (!context) return nullptr;
diff --git a/components/login.gypi b/components/login.gypi index 9dec0dd7..e8a6bb1 100644 --- a/components/login.gypi +++ b/components/login.gypi
@@ -10,6 +10,9 @@ '<(DEPTH)/base/base.gyp:base', '<(DEPTH)/ui/base/ui_base.gyp:ui_base', ], + 'export_dependent_settings': [ + '<(DEPTH)/base/base.gyp:base', + ], 'defines': [ 'LOGIN_IMPLEMENTATION', ],
diff --git a/components/login/BUILD.gn b/components/login/BUILD.gn index be7525a8..26a28685 100644 --- a/components/login/BUILD.gn +++ b/components/login/BUILD.gn
@@ -15,9 +15,12 @@ defines = [ "LOGIN_IMPLEMENTATION" ] deps = [ - "//base", "//ui/base", ] + + public_deps = [ + "//base", + ] } source_set("unit_tests") {
diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc index b7aa20e3..54e4deb 100644 --- a/components/metrics/metrics_service.cc +++ b/components/metrics/metrics_service.cc
@@ -248,11 +248,6 @@ } } -bool NewInitialMetricsTimingEnabled() { - return base::FieldTrialList::FindFullName("UMAInitialMetricsTiming") == - "Enabled"; -} - void MarkAppCleanShutdownAndCommit(CleanExitBeacon* clean_exit_beacon, PrefService* local_state) { clean_exit_beacon->WriteBeaconValue(true); @@ -889,30 +884,17 @@ return; case INIT_TASK_DONE: - if (NewInitialMetricsTimingEnabled()) { - PrepareInitialMetricsLog(); - // Stage the first log, which could be a stability log (either one - // for created in this session or from a previous session) or the - // initial metrics log that was just created. - log_manager_.StageNextLogForUpload(); - if (has_initial_stability_log_) { - // The initial stability log was just staged. - has_initial_stability_log_ = false; - state_ = SENDING_INITIAL_STABILITY_LOG; - } else { - state_ = SENDING_INITIAL_METRICS_LOG; - } + PrepareInitialMetricsLog(); + // Stage the first log, which could be a stability log (either one + // for created in this session or from a previous session) or the + // initial metrics log that was just created. + log_manager_.StageNextLogForUpload(); + if (has_initial_stability_log_) { + // The initial stability log was just staged. + has_initial_stability_log_ = false; + state_ = SENDING_INITIAL_STABILITY_LOG; } else { - if (has_initial_stability_log_) { - // There's an initial stability log, ready to send. - log_manager_.StageNextLogForUpload(); - has_initial_stability_log_ = false; - state_ = SENDING_INITIAL_STABILITY_LOG; - } else { - PrepareInitialMetricsLog(); - log_manager_.StageNextLogForUpload(); - state_ = SENDING_INITIAL_METRICS_LOG; - } + state_ = SENDING_INITIAL_METRICS_LOG; } break; @@ -1047,8 +1029,6 @@ ResponseCodeToStatus(response_code), NUM_RESPONSE_STATUSES); - bool suppress_reschedule = false; - bool upload_succeeded = response_code == 200; // Provide boolean for error recovery (allow us to ignore response_code). @@ -1074,16 +1054,8 @@ if (!log_manager_.has_staged_log()) { switch (state_) { case SENDING_INITIAL_STABILITY_LOG: - if (NewInitialMetricsTimingEnabled()) { - // The initial metrics log is already in the queue of unsent logs. - state_ = SENDING_OLD_LOGS; - } else { - PrepareInitialMetricsLog(); - log_manager_.StageNextLogForUpload(); - SendStagedLog(); - state_ = SENDING_INITIAL_METRICS_LOG; - suppress_reschedule = true; - } + // The initial metrics log is already in the queue of unsent logs. + state_ = SENDING_OLD_LOGS; break; case SENDING_INITIAL_METRICS_LOG: @@ -1111,13 +1083,7 @@ // Error 400 indicates a problem with the log, not with the server, so // don't consider that a sign that the server is in trouble. bool server_is_healthy = upload_succeeded || response_code == 400; - // Don't notify the scheduler that the upload is finished if we've only just - // sent the initial stability log, but not yet the initial metrics log (treat - // the two as a single unit of work as far as the scheduler is concerned). - if (!suppress_reschedule) { - scheduler_->UploadFinished(server_is_healthy, - log_manager_.has_unsent_logs()); - } + scheduler_->UploadFinished(server_is_healthy, log_manager_.has_unsent_logs()); if (server_is_healthy) client_->OnLogUploadComplete();
diff --git a/components/nacl/renderer/plugin/srpc_client.cc b/components/nacl/renderer/plugin/srpc_client.cc index 58efd1a49..4c9b4c9 100644 --- a/components/nacl/renderer/plugin/srpc_client.cc +++ b/components/nacl/renderer/plugin/srpc_client.cc
@@ -191,9 +191,4 @@ return true; } -void SrpcClient::AttachService(NaClSrpcService* service, void* instance_data) { - srpc_channel_.server = service; - srpc_channel_.server_instance_data = instance_data; -} - } // namespace plugin
diff --git a/components/nacl/renderer/plugin/srpc_client.h b/components/nacl/renderer/plugin/srpc_client.h index 4be0919..7bd4a04 100644 --- a/components/nacl/renderer/plugin/srpc_client.h +++ b/components/nacl/renderer/plugin/srpc_client.h
@@ -23,9 +23,7 @@ namespace plugin { -class ErrorInfo; class MethodInfo; -class Plugin; class SrpcParams; // SrpcClient represents an SRPC connection to a client. @@ -46,12 +44,9 @@ // Invoke an SRPC method. bool Invoke(const std::string& method_name, SrpcParams* params); // Get the error status from that last method invocation - NaClSrpcError GetLastError() { return last_error_; } + NaClSrpcError GetLastError() const { return last_error_; } bool InitParams(const std::string& method_name, SrpcParams* params); - // Attach a service for reverse-direction (from .nexe) RPCs. - void AttachService(NaClSrpcService* service, void* instance_data); - private: NACL_DISALLOW_COPY_AND_ASSIGN(SrpcClient); SrpcClient();
diff --git a/components/nacl/renderer/plugin/srpc_params.h b/components/nacl/renderer/plugin/srpc_params.h index ff24442..1052b6f 100644 --- a/components/nacl/renderer/plugin/srpc_params.h +++ b/components/nacl/renderer/plugin/srpc_params.h
@@ -21,12 +21,6 @@ memset(outs_, 0, sizeof(outs_)); } - SrpcParams(const char* in_types, const char* out_types) { - if (!Init(in_types, out_types)) { - FreeAll(); - } - } - ~SrpcParams() { FreeAll(); }
diff --git a/components/nacl/renderer/pnacl_translation_resource_host.cc b/components/nacl/renderer/pnacl_translation_resource_host.cc index 4e92259..f47f1d4 100644 --- a/components/nacl/renderer/pnacl_translation_resource_host.cc +++ b/components/nacl/renderer/pnacl_translation_resource_host.cc
@@ -116,23 +116,22 @@ DCHECK(io_message_loop_->BelongsToCurrentThread()); base::File base_file = IPC::PlatformFileForTransitToFile(file); CacheRequestInfoMap::iterator it = pending_cache_requests_.find(instance); - int32_t status = PP_ERROR_FAILED; - // Handle the expected successful case first. - PP_FileHandle file_handle = PP_kInvalidFileHandle; - if (it != pending_cache_requests_.end() && base_file.IsValid()) { - file_handle = base_file.TakePlatformFile(); - status = PP_OK; + if (!base_file.IsValid()) { + DLOG(ERROR) << "Got invalid platformfilefortransit"; } - if (it == pending_cache_requests_.end()) { - DLOG(ERROR) << "Could not find pending request for reply"; - } else { + if (it != pending_cache_requests_.end()) { + PP_FileHandle file_handle = PP_kInvalidFileHandle; + int32_t status = PP_ERROR_FAILED; + if (base_file.IsValid()) { + file_handle = base_file.TakePlatformFile(); + status = PP_OK; + } PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask( FROM_HERE, base::Bind(it->second, status, is_hit, file_handle)); pending_cache_requests_.erase(it); - } - if (!base_file.IsValid()) { - DLOG(ERROR) << "Got invalid platformfilefortransit"; + } else { + DLOG(ERROR) << "Could not find pending request for reply"; } }
diff --git a/components/omnibox/search_suggestion_parser.cc b/components/omnibox/search_suggestion_parser.cc index a382c6b..27cc63bc 100644 --- a/components/omnibox/search_suggestion_parser.cc +++ b/components/omnibox/search_suggestion_parser.cc
@@ -351,7 +351,7 @@ // Remove any XSSI guards to allow for JSON parsing. json_data.remove_prefix(response_start_index); - JSONStringValueSerializer deserializer(json_data); + JSONStringValueDeserializer deserializer(json_data); deserializer.set_allow_trailing_comma(true); int error_code = 0; scoped_ptr<base::Value> data(deserializer.Deserialize(&error_code, NULL));
diff --git a/components/open_from_clipboard/clipboard_recent_content_ios.h b/components/open_from_clipboard/clipboard_recent_content_ios.h index 062d0f1b..174166d 100644 --- a/components/open_from_clipboard/clipboard_recent_content_ios.h +++ b/components/open_from_clipboard/clipboard_recent_content_ios.h
@@ -12,6 +12,10 @@ @class NSDate; @class PasteboardNotificationListenerBridge; +namespace test { +class ClipboardRecentContentIOSTestHelper; +} + template <typename T> struct DefaultSingletonTraits; @@ -25,11 +29,15 @@ // ClipboardRecentContent implementation. bool GetRecentURLFromClipboard(GURL* url) const override; - private: - friend struct DefaultSingletonTraits<ClipboardRecentContentIOS>; - + protected: + // Protected for testing. ClipboardRecentContentIOS(); ~ClipboardRecentContentIOS() override; + + private: + friend struct DefaultSingletonTraits<ClipboardRecentContentIOS>; + friend class test::ClipboardRecentContentIOSTestHelper; + // Loads information from the user defaults about the latest pasteboard entry. void LoadFromUserDefaults(); // Saves information to the user defaults about the latest pasteboard entry.
diff --git a/components/open_from_clipboard/clipboard_recent_content_ios.mm b/components/open_from_clipboard/clipboard_recent_content_ios.mm index 4cc2ed57..7b14bff2 100644 --- a/components/open_from_clipboard/clipboard_recent_content_ios.mm +++ b/components/open_from_clipboard/clipboard_recent_content_ios.mm
@@ -100,17 +100,14 @@ } void ClipboardRecentContentIOS::PasteboardChanged() { - if ([UIPasteboard generalPasteboard].changeCount != - lastPasteboardChangeCount_) { - urlFromPasteboardCache_ = URLFromPasteboard(); - if (!urlFromPasteboardCache_.is_empty()) { - base::RecordAction( - base::UserMetricsAction("MobileOmniboxClipboardChanged")); - } - lastPasteboardChangeDate_.reset([[NSDate date] retain]); - lastPasteboardChangeCount_ = [UIPasteboard generalPasteboard].changeCount; - SaveToUserDefaults(); + urlFromPasteboardCache_ = URLFromPasteboard(); + if (!urlFromPasteboardCache_.is_empty()) { + base::RecordAction( + base::UserMetricsAction("MobileOmniboxClipboardChanged")); } + lastPasteboardChangeDate_.reset([[NSDate date] retain]); + lastPasteboardChangeCount_ = [UIPasteboard generalPasteboard].changeCount; + SaveToUserDefaults(); } ClipboardRecentContentIOS::ClipboardRecentContentIOS() @@ -124,7 +121,7 @@ NSInteger changeCount = [UIPasteboard generalPasteboard].changeCount; if (changeCount != lastPasteboardChangeCount_ || DeviceRestartedSincePasteboardChanged()) { - PasteboardChanged(); + PasteboardChanged(); } notificationBridge_.reset( [[PasteboardNotificationListenerBridge alloc] initWithDelegate:this]);
diff --git a/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm b/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm new file mode 100644 index 0000000..d08f16ef5 --- /dev/null +++ b/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm
@@ -0,0 +1,89 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/open_from_clipboard/clipboard_recent_content_ios.h" + +#import <UIKit/UIKit.h> + +#include "base/memory/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace test { +class ClipboardRecentContentIOSTestHelper : public ClipboardRecentContentIOS { + public: + ClipboardRecentContentIOSTestHelper() {} + ~ClipboardRecentContentIOSTestHelper() override {} + void SetStoredPasteboardChangeDate(NSDate* changeDate) { + lastPasteboardChangeDate_.reset([changeDate copy]); + SaveToUserDefaults(); + } +}; +} // namespace test + +namespace { +void SetPasteboardContent(const char* data) { + [[UIPasteboard generalPasteboard] + setValue:[NSString stringWithUTF8String:data] + forPasteboardType:@"public.plain-text"]; +} +const char* kUnrecognizedURL = "ftp://foo/"; +const char* kRecognizedURL = "http://bar/"; +const char* kAppSpecificURL = "test://qux/"; +const char* kAppSpecificScheme = "test"; +NSTimeInterval kSevenHours = 60 * 60 * 7; +} // namespace + +class ClipboardRecentContentIOSTest : public ::testing::Test { + protected: + void SetUp() override { + clipboard_content_.reset(new test::ClipboardRecentContentIOSTestHelper()); + } + void TearDown() override {} + + protected: + scoped_ptr<test::ClipboardRecentContentIOSTestHelper> clipboard_content_; +}; + +TEST_F(ClipboardRecentContentIOSTest, SchemeFiltering) { + GURL gurl; + + // Test unrecognized URL. + SetPasteboardContent(kUnrecognizedURL); + EXPECT_FALSE(clipboard_content_->GetRecentURLFromClipboard(&gurl)); + + // Test recognized URL. + SetPasteboardContent(kRecognizedURL); + EXPECT_TRUE(clipboard_content_->GetRecentURLFromClipboard(&gurl)); + EXPECT_STREQ(kRecognizedURL, gurl.spec().c_str()); + + // Test URL with app specific scheme, before and after configuration. + SetPasteboardContent(kAppSpecificURL); + EXPECT_FALSE(clipboard_content_->GetRecentURLFromClipboard(&gurl)); + clipboard_content_->set_application_scheme(kAppSpecificScheme); + SetPasteboardContent(kAppSpecificURL); + EXPECT_TRUE(clipboard_content_->GetRecentURLFromClipboard(&gurl)); + EXPECT_STREQ(kAppSpecificURL, gurl.spec().c_str()); +} + +TEST_F(ClipboardRecentContentIOSTest, PasteboardURLObsolescence) { + GURL gurl; + SetPasteboardContent(kRecognizedURL); + + // Test that recent pasteboard data is provided. + EXPECT_TRUE(clipboard_content_->GetRecentURLFromClipboard(&gurl)); + EXPECT_STREQ(kRecognizedURL, gurl.spec().c_str()); + + // Test that old pasteboard data is not provided. + clipboard_content_->SetStoredPasteboardChangeDate( + [NSDate dateWithTimeIntervalSinceNow:-kSevenHours]); + EXPECT_FALSE(clipboard_content_->GetRecentURLFromClipboard(&gurl)); + + // Test that pasteboard data is treated as new if the last recorded clipboard + // change dates from before the machine booted. + clipboard_content_->SetStoredPasteboardChangeDate( + [NSDate dateWithTimeIntervalSince1970:0]); + clipboard_content_.reset(new test::ClipboardRecentContentIOSTestHelper()); + EXPECT_TRUE(clipboard_content_->GetRecentURLFromClipboard(&gurl)); + EXPECT_STREQ(kRecognizedURL, gurl.spec().c_str()); +}
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc index 0474431..dc4bf9a 100644 --- a/components/password_manager/core/browser/password_form_manager.cc +++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -154,10 +154,14 @@ StartsWithASCII(new_path, old_path, /*case_sensitive=*/true); } + if (!origins_match) + return result; + + result |= RESULT_ORIGINS_MATCH; + if (form.username_element == observed_form_.username_element && - form.password_element == observed_form_.password_element && - origins_match) { - result |= RESULT_MANDATORY_ATTRIBUTES_MATCH; + form.password_element == observed_form_.password_element) { + result |= RESULT_HTML_ATTRIBUTES_MATCH; } // Note: although saved password forms might actually have an empty action @@ -405,13 +409,12 @@ } bool PasswordFormManager::IsIgnorableChangePasswordForm( - const base::string16& typed_username, - const base::string16& typed_password) const { - bool is_change_password_form = !observed_form_.new_password_element.empty() && - !observed_form_.password_element.empty(); - return is_change_password_form && !observed_form_.username_marked_by_site && - !DoesUsenameAndPasswordMatchCredentials(typed_username, typed_password, - best_matches_); + const PasswordForm& form) const { + bool is_change_password_form = + !form.new_password_element.empty() && !form.password_element.empty(); + return is_change_password_form && !form.username_marked_by_site && + !DoesUsenameAndPasswordMatchCredentials( + form.username_value, form.password_value, best_matches_); } void PasswordFormManager::OnRequestDone(
diff --git a/components/password_manager/core/browser/password_form_manager.h b/components/password_manager/core/browser/password_form_manager.h index 91f53a454..b3629a2 100644 --- a/components/password_manager/core/browser/password_form_manager.h +++ b/components/password_manager/core/browser/password_form_manager.h
@@ -42,12 +42,17 @@ // DoesMatch. Individual flags are only relevant for HTML forms, but // RESULT_COMPLETE_MATCH will also be returned to indicate non-HTML forms // completely matching. + // The ordering of these flags is important. Larger matches are more + // preferred than lower matches. That is, since RESULT_HTML_ATTRIBUTES_MATCH + // is greater than RESULT_ACTION_MATCH, a match of only attributes and not + // actions will be preferred to one of actions and not attributes. enum MatchResultFlags { RESULT_NO_MATCH = 0, - RESULT_MANDATORY_ATTRIBUTES_MATCH = 1 << 0, // Bare minimum to be a match. - RESULT_ACTION_MATCH = 1 << 1, // Action URLs match too. - RESULT_COMPLETE_MATCH = - RESULT_MANDATORY_ATTRIBUTES_MATCH | RESULT_ACTION_MATCH + RESULT_ACTION_MATCH = 1 << 0, + RESULT_HTML_ATTRIBUTES_MATCH = 1 << 1, + RESULT_ORIGINS_MATCH = 1 << 2, + RESULT_COMPLETE_MATCH = RESULT_ACTION_MATCH | RESULT_HTML_ATTRIBUTES_MATCH | + RESULT_ORIGINS_MATCH }; // Use MatchResultMask to contain combinations of MatchResultFlags values. // It's a signed int rather than unsigned to avoid signed/unsigned mismatch @@ -84,18 +89,15 @@ // the same thread! bool HasCompletedMatching() const; - // Returns true if the observed form has both the current and new password - // fields, and the username field was not explicitly marked with - // "autocomplete=username" and the user-typed username and current password - // field values do not match the credentials already stored. In these cases it - // is not clear whether the username field is the right guess (often such - // change password forms do not contain the username at all), and the user - // should not be bothered with saving a potentially malformed credential. Once - // we handle change password forms correctly, this method should be replaced - // accordingly. - bool IsIgnorableChangePasswordForm( - const base::string16& typed_username, - const base::string16& typed_password) const; + // Returns true if |form| has both the current and new password fields, and + // the username field was not explicitly marked with "autocomplete=username" + // and |form.username_value| and |form.password_value| fields do not match + // the credentials already stored. In these cases it is not clear whether + // the username field is the right guess (often such change password forms do + // not contain the username at all), and the user should not be bothered with + // saving a potentially malformed credential. Once we handle change password + // forms correctly, this method should be replaced accordingly. + bool IsIgnorableChangePasswordForm(const autofill::PasswordForm& form) const; // Determines if the user opted to 'never remember' passwords for this form. bool IsBlacklisted() const;
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 1e615e07..bbfdef1 100644 --- a/components/password_manager/core/browser/password_form_manager_unittest.cc +++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -397,7 +397,6 @@ submitted_form.preferred = true; submitted_form.username_value = saved_match()->username_value; submitted_form.password_value = saved_match()->password_value; - submitted_form.origin = saved_match()->origin; form_manager.ProvisionallySave( submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); @@ -405,6 +404,7 @@ expected_saved_form.times_used = 1; expected_saved_form.other_possible_usernames.clear(); expected_saved_form.form_data = saved_match()->form_data; + expected_saved_form.origin = saved_match()->origin; PasswordForm actual_saved_form; EXPECT_CALL(*(client_with_store.mock_driver()->mock_autofill_manager()), @@ -1061,17 +1061,15 @@ ASSERT_EQ(PasswordForm::SCHEME_HTML, observed_form()->scheme); PasswordForm non_html_form(*observed_form()); non_html_form.scheme = PasswordForm::SCHEME_DIGEST; - EXPECT_EQ(0, - manager.DoesManage(non_html_form) & - PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); + EXPECT_EQ(0, manager.DoesManage(non_html_form) & + PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH); // The other way round: observing a non-HTML form, don't match a HTML form. PasswordForm html_form(*observed_form()); PasswordFormManager non_html_manager(nullptr, client(), kNoDriver, non_html_form, false); - EXPECT_EQ(0, - non_html_manager.DoesManage(html_form) & - PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); + EXPECT_EQ(0, non_html_manager.DoesManage(html_form) & + PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH); } TEST_F(PasswordFormManagerTest, OriginCheck_HostsMatchExactly) { @@ -1082,9 +1080,8 @@ PasswordForm form_longer_host(*observed_form()); form_longer_host.origin = GURL("http://accounts.google.com.au/a/LoginAuth"); // Check that accounts.google.com does not match accounts.google.com.au. - EXPECT_EQ(0, - manager.DoesManage(form_longer_host) & - PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); + EXPECT_EQ(0, manager.DoesManage(form_longer_host) & + PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH); } TEST_F(PasswordFormManagerTest, OriginCheck_MoreSecureSchemePathsMatchPrefix) { @@ -1095,9 +1092,8 @@ PasswordForm form_longer_path(*observed_form()); form_longer_path.origin = GURL("https://accounts.google.com/a/LoginAuth/sec"); - EXPECT_NE(0, - manager.DoesManage(form_longer_path) & - PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); + EXPECT_NE(0, manager.DoesManage(form_longer_path) & + PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH); } TEST_F(PasswordFormManagerTest, @@ -1110,9 +1106,8 @@ PasswordForm form_longer_path(*observed_form()); form_longer_path.origin = GURL("http://accounts.google.com/a/LoginAuth/sec"); // Check that /a/LoginAuth does not match /a/LoginAuth/more. - EXPECT_EQ(0, - manager.DoesManage(form_longer_path) & - PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); + EXPECT_EQ(0, manager.DoesManage(form_longer_path) & + PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH); PasswordForm secure_observed_form(*observed_form()); secure_observed_form.origin = GURL("https://accounts.google.com/a/LoginAuth"); @@ -1120,14 +1115,28 @@ secure_observed_form, true); // Also for HTTPS in the observed form, and HTTP in the compared form, an // exact path match is expected. - EXPECT_EQ(0, - secure_manager.DoesManage(form_longer_path) & - PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); + EXPECT_EQ(0, secure_manager.DoesManage(form_longer_path) & + PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH); // Not even upgrade to HTTPS in the compared form should help. form_longer_path.origin = GURL("https://accounts.google.com/a/LoginAuth/sec"); - EXPECT_EQ(0, - secure_manager.DoesManage(form_longer_path) & - PasswordFormManager::RESULT_MANDATORY_ATTRIBUTES_MATCH); + EXPECT_EQ(0, secure_manager.DoesManage(form_longer_path) & + PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH); +} + +TEST_F(PasswordFormManagerTest, OriginCheck_OnlyOriginsMatch) { + // Make sure DoesManage() can distinguish when only origins match. + PasswordFormManager manager(NULL, client(), kNoDriver, *observed_form(), + false); + PasswordForm different_html_attributes(*observed_form()); + different_html_attributes.password_element = ASCIIToUTF16("random_pass"); + different_html_attributes.username_element = ASCIIToUTF16("random_user"); + + EXPECT_EQ(0, manager.DoesManage(different_html_attributes) & + PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH); + + EXPECT_EQ(PasswordFormManager::RESULT_ORIGINS_MATCH, + manager.DoesManage(different_html_attributes) & + PasswordFormManager::RESULT_ORIGINS_MATCH); } TEST_F(PasswordFormManagerTest, CorrectlyUpdatePasswordsWithSameUsername) { @@ -1397,15 +1406,11 @@ credentials.password_value = saved_match()->password_value; credentials.new_password_value = ASCIIToUTF16("NewPassword"); - EXPECT_FALSE(manager.IsIgnorableChangePasswordForm( - credentials.username_value, credentials.password_value)); + EXPECT_FALSE(manager.IsIgnorableChangePasswordForm(credentials)); } TEST_F(PasswordFormManagerTest, IsIngnorableChangePasswordForm_NotMatchingPassword) { - observed_form()->new_password_element = - base::ASCIIToUTF16("new_password_field"); - TestPasswordManagerClient client_with_store(mock_store()); PasswordFormManager manager(nullptr, &client_with_store, client_with_store.driver(), *observed_form(), @@ -1417,15 +1422,14 @@ // the username), and the user-typed password do not match anything already // stored. There is not much confidence in the guess being right, so the // password should not be stored. - EXPECT_TRUE(manager.IsIgnorableChangePasswordForm( - saved_match()->username_value, ASCIIToUTF16("DifferentPassword"))); + saved_match()->password_value = ASCIIToUTF16("DifferentPassword"); + saved_match()->new_password_element = + base::ASCIIToUTF16("new_password_field"); + EXPECT_TRUE(manager.IsIgnorableChangePasswordForm(*saved_match())); } TEST_F(PasswordFormManagerTest, IsIngnorableChangePasswordForm_NotMatchingUsername) { - observed_form()->new_password_element = - base::ASCIIToUTF16("new_password_field"); - TestPasswordManagerClient client_with_store(mock_store()); PasswordFormManager manager(nullptr, &client_with_store, client_with_store.driver(), *observed_form(), @@ -1437,8 +1441,10 @@ // the username), and the user-typed username does not match anything already // stored. There is not much confidence in the guess being right, so the // password should not be stored. - EXPECT_TRUE(manager.IsIgnorableChangePasswordForm( - ASCIIToUTF16("DifferentUsername"), saved_match()->password_value)); + saved_match()->username_value = ASCIIToUTF16("DifferentUsername"); + saved_match()->new_password_element = + base::ASCIIToUTF16("new_password_field"); + EXPECT_TRUE(manager.IsIgnorableChangePasswordForm(*saved_match())); } } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc index 7d8b50ac..3d6111c 100644 --- a/components/password_manager/core/browser/password_manager.cc +++ b/components/password_manager/core/browser/password_manager.cc
@@ -107,6 +107,10 @@ target_domain_differs); } +bool IsSignupForm(const PasswordForm& form) { + return !form.new_password_element.empty() && form.password_element.empty(); +} + } // namespace const char PasswordManager::kOtherPossibleUsernamesExperiment[] = @@ -224,6 +228,8 @@ scoped_ptr<PasswordFormManager> manager; ScopedVector<PasswordFormManager>::iterator matched_manager_it = pending_login_managers_.end(); + PasswordFormManager::MatchResultMask current_match_result = + PasswordFormManager::RESULT_NO_MATCH; // Below, "matching" is in DoesManage-sense and "not ready" in // !HasCompletedMatching sense. We keep track of such PasswordFormManager // instances for UMA. @@ -236,8 +242,7 @@ if (result == PasswordFormManager::RESULT_NO_MATCH) continue; - if ((*iter)->IsIgnorableChangePasswordForm(form.username_value, - form.password_value)) { + if ((*iter)->IsIgnorableChangePasswordForm(form)) { if (logger) logger->LogMessage(Logger::STRING_CHANGE_PASSWORD_FORM); continue; @@ -256,7 +261,8 @@ matched_manager_it = iter; break; } else if (result == (PasswordFormManager::RESULT_COMPLETE_MATCH & - ~PasswordFormManager::RESULT_ACTION_MATCH)) { + ~PasswordFormManager::RESULT_ACTION_MATCH) && + result > current_match_result) { // If the current manager matches the submitted form excluding the action // URL, remember it as a candidate and continue searching for an exact // match. See http://crbug.com/27246 for an example where actions can @@ -264,6 +270,20 @@ if (logger) logger->LogMessage(Logger::STRING_MATCH_WITHOUT_ACTION); matched_manager_it = iter; + current_match_result = result; + } else if (IsSignupForm(form) && result > current_match_result) { + // Signup forms don't require HTML attributes to match because we don't + // need to fill these saved passwords on the same form in the future. + // Prefer the best possible match (e.g. action and origins match instead + // or just origin matching). Don't break in case there exists a better + // match. + // TODO(gcasto): Matching in this way is very imprecise. Having some + // better way to match the same form when the HTML elements change (e.g. + // text element changed to password element) would be useful. + if (logger) + logger->LogMessage(Logger::STRING_ORIGINS_MATCH); + matched_manager_it = iter; + current_match_result = result; } } // If we didn't find a manager, this means a form was submitted without
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc index 1ec170b..a3cc8fc2 100644 --- a/components/password_manager/core/browser/password_manager_unittest.cc +++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -937,4 +937,104 @@ manager()->OnInPageNavigation(&driver_, form); } +TEST_F(PasswordManagerTest, SavingSignupForms_NoHTMLMatch) { + // Signup forms don't require HTML attributes match in order to save. + // Verify that we prefer a better match (action + origin vs. origin). + std::vector<PasswordForm> observed; + PasswordForm expected_form; + PasswordForm form(MakeSimpleForm()); + observed.push_back(form); + form.action = GURL("http://www.google.com/other/action"); + observed.push_back(form); + expected_form = form; + + // The initial load. + manager()->OnPasswordFormsParsed(&driver_, observed); + // The initial layout. + manager()->OnPasswordFormsRendered(&driver_, observed, true); + + // Simulate either form changing or heuristics choosing other fields + // after the user has entered their information. + form.new_password_element = ASCIIToUTF16("new_password"); + form.new_password_value = form.password_value; + form.password_element.clear(); + form.password_value.clear(); + + // Saved signup forms don't have password set. + expected_form.password_element.clear(); + + manager()->ProvisionallySavePassword(form); + + scoped_ptr<PasswordFormManager> form_to_save; + EXPECT_CALL(client_, + PromptUserToSavePasswordPtr( + _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER)) + .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save))); + + // Now the password manager waits for the navigation to complete. + observed.clear(); + manager()->OnPasswordFormsParsed(&driver_, + observed); // The post-navigation load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The post-navigation layout. + + ASSERT_TRUE(form_to_save); + EXPECT_CALL(*store_, AddLogin(FormMatches(expected_form))); + + // Simulate saving the form, as if the info bar was accepted. + form_to_save->Save(); +} + +TEST_F(PasswordManagerTest, SavingSignupForms_NoActionMatch) { + // Signup forms don't require HTML attributes match in order to save. + // Verify that we prefer a better match (HTML attributes + origin vs. origin). + std::vector<PasswordForm> observed; + PasswordForm expected_form; + PasswordForm form(MakeSimpleForm()); + observed.push_back(form); + // Change the submit element so we can track which of the two forms is + // chosen as a better match. + form.submit_element = ASCIIToUTF16("different_signin"); + expected_form = form; + form.new_password_element = ASCIIToUTF16("new_password"); + form.new_password_value = form.password_value; + form.password_element.clear(); + form.password_value.clear(); + observed.push_back(form); + + // The initial load. + manager()->OnPasswordFormsParsed(&driver_, observed); + // The initial layout. + manager()->OnPasswordFormsRendered(&driver_, observed, true); + + // Simulate form changing it's action. Update expectation as well since + // the action is copied during saving. + form.action = GURL("http://www.google.com/other/action"); + expected_form.action = form.action; + + // Signup forms clear password element when saving. + expected_form.password_element.clear(); + + manager()->ProvisionallySavePassword(form); + + scoped_ptr<PasswordFormManager> form_to_save; + EXPECT_CALL(client_, + PromptUserToSavePasswordPtr( + _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER)) + .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save))); + + // Now the password manager waits for the navigation to complete. + observed.clear(); + manager()->OnPasswordFormsParsed(&driver_, + observed); // The post-navigation load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The post-navigation layout. + + ASSERT_TRUE(form_to_save); + EXPECT_CALL(*store_, AddLogin(FormMatches(expected_form))); + + // Simulate saving the form, as if the info bar was accepted. + form_to_save->Save(); +} + } // namespace password_manager
diff --git a/components/policy/core/common/config_dir_policy_loader.cc b/components/policy/core/common/config_dir_policy_loader.cc index c754190..b39d838 100644 --- a/components/policy/core/common/config_dir_policy_loader.cc +++ b/components/policy/core/common/config_dir_policy_loader.cc
@@ -31,11 +31,11 @@ PolicyLoadStatus JsonErrorToPolicyLoadStatus(int status) { switch (status) { - case JSONFileValueSerializer::JSON_ACCESS_DENIED: - case JSONFileValueSerializer::JSON_CANNOT_READ_FILE: - case JSONFileValueSerializer::JSON_FILE_LOCKED: + case JSONFileValueDeserializer::JSON_ACCESS_DENIED: + case JSONFileValueDeserializer::JSON_CANNOT_READ_FILE: + case JSONFileValueDeserializer::JSON_FILE_LOCKED: return POLICY_LOAD_STATUS_READ_ERROR; - case JSONFileValueSerializer::JSON_NO_SUCH_FILE: + case JSONFileValueDeserializer::JSON_NO_SUCH_FILE: return POLICY_LOAD_STATUS_MISSING; case base::JSONReader::JSON_INVALID_ESCAPE: case base::JSONReader::JSON_SYNTAX_ERROR: @@ -138,7 +138,7 @@ for (std::set<base::FilePath>::reverse_iterator config_file_iter = files.rbegin(); config_file_iter != files.rend(); ++config_file_iter) { - JSONFileValueSerializer deserializer(*config_file_iter); + JSONFileValueDeserializer deserializer(*config_file_iter); deserializer.set_allow_trailing_comma(true); int error_code = 0; std::string error_msg;
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 87df92d..da5c833 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: 294 +# For your editing convenience: highest ID currently used: 295 # # Placeholders: # The following placeholder strings are automatically substituted: @@ -1347,6 +1347,28 @@ 'label': '''Clear site data on browser shutdown (deprecated)''', }, { + 'name': 'CaptivePortalAuthenticationIgnoresProxy', + 'type': 'main', + 'schema': { 'type': 'boolean' }, + 'supported_on': ['chrome_os:41-'], + 'features': { + 'can_be_recommended': False, + 'dynamic_refresh': True, + 'per_profile': True, + }, + 'example_value': True, + 'default_for_enterprise_users': False, + 'id': 295, + 'caption': '''Captive portal authentication ignores proxy''', + 'desc': '''This policy allows <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> to bypass any proxy for captive portal authentication. + + This policy only takes effect if a proxy is configured (for example through policy, by the user in chrome://settings, or by extensions). + + If you enable this setting, any captive portal authentication pages (i.e. all web pages starting from captive portal signin page until <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> detects succesful internet connection) will be displayed in a separate window ignoring all policy settings and restrictions for the current user. + + If you disable this setting or leave it unset, any captive portal authentication pages will be shown in a (regular) new browser tab, using the current user's proxy settings.''', + }, + { 'name': 'Proxy', 'type': 'group', 'caption': '''Proxy server''', @@ -1818,7 +1840,11 @@ Users will be unable to uninstall extensions that are specified by this policy. If you remove an extension from this list, then it will be automatically uninstalled by <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>. Extensions specified in this list are also automatically whitelisted for installation; the ExtensionsInstallBlacklist does not affect them. - If this policy is left not set the user can uninstall any extension in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>.''', + Note that the source code of any extension may be altered (potentially + rendering the extension dysfunctional) by using Developer Tools. If + this is a concern, the DeveloperToolsDisabled policy should be set. + + If this policy is left not set the user can uninstall any extension in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>.''', 'label': '''Extension IDs and update URLs to be silently installed''', }, {
diff --git a/components/resources/OWNERS b/components/resources/OWNERS index b2cc238e..4f523eef 100644 --- a/components/resources/OWNERS +++ b/components/resources/OWNERS
@@ -1,4 +1,5 @@ +per-file data_reduction_proxy*=bengr@chromium.org +per-file data_reduction_proxy*=sclittle@chromium.org per-file dom_distiller*=cjhopman@chromium.org per-file dom_distiller*=nyquist@chromium.org -per-file data_reduction_proxy*=bengr@chromium.org -per-file data_reduction_proxy*=sclittle@chromium.org \ No newline at end of file +per-file webui_generator_resources.grdp=dzhioev@chromium.org
diff --git a/components/resources/components_resources.grd b/components/resources/components_resources.grd index 7c2cdfe..099086b 100644 --- a/components/resources/components_resources.grd +++ b/components/resources/components_resources.grd
@@ -12,6 +12,7 @@ <part file="dom_distiller_resources.grdp" /> <part file="printing_resources.grdp" /> <part file="translate_resources.grdp" /> + <part file="webui_generator_resources.grdp" /> </includes> </release> </grit>
diff --git a/components/resources/webui_generator_resources.grdp b/components/resources/webui_generator_resources.grdp new file mode 100644 index 0000000..996a83f --- /dev/null +++ b/components/resources/webui_generator_resources.grdp
@@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<grit-part> + <include name="IDR_WUG_CONTEXT_HTML" file="../webui_generator/resources/context.html" type="chrome_html" /> + <include name="IDR_WUG_CONTEXT_JS" file="../webui_generator/resources/context.js" type="chrome_html" flattenhtml="true" /> + <include name="IDR_WUG_WEBUI_VIEW_HTML" file="../webui_generator/resources/webui-view.html" type="chrome_html" /> + <include name="IDR_WUG_WEBUI_VIEW_JS" file="../webui_generator/resources/webui-view.js" type="chrome_html" /> +</grit-part>
diff --git a/components/search_engines/keyword_table.cc b/components/search_engines/keyword_table.cc index 08dea92..59dff732 100644 --- a/components/search_engines/keyword_table.cc +++ b/components/search_engines/keyword_table.cc
@@ -193,45 +193,6 @@ bool* update_compatible_version) { // Migrate if necessary. switch (version) { - case 21: - *update_compatible_version = true; - return MigrateToVersion21AutoGenerateKeywordColumn(); - case 25: - *update_compatible_version = true; - return MigrateToVersion25AddLogoIDColumn(); - case 26: - *update_compatible_version = true; - return MigrateToVersion26AddCreatedByPolicyColumn(); - case 28: - *update_compatible_version = true; - return MigrateToVersion28SupportsInstantColumn(); - case 29: - *update_compatible_version = true; - return MigrateToVersion29InstantURLToSupportsInstant(); - case 38: - *update_compatible_version = true; - return MigrateToVersion38AddLastModifiedColumn(); - case 39: - *update_compatible_version = true; - return MigrateToVersion39AddSyncGUIDColumn(); - case 44: - *update_compatible_version = true; - return MigrateToVersion44AddDefaultSearchProviderBackup(); - case 45: - *update_compatible_version = true; - return MigrateToVersion45RemoveLogoIDAndAutogenerateColumns(); - case 47: - *update_compatible_version = true; - return MigrateToVersion47AddAlternateURLsColumn(); - case 48: - *update_compatible_version = true; - return MigrateToVersion48RemoveKeywordsBackup(); - case 49: - *update_compatible_version = true; - return MigrateToVersion49AddSearchTermsReplacementKeyColumn(); - case 52: - *update_compatible_version = true; - return MigrateToVersion52AddImageSearchAndPOSTSupport(); case 53: *update_compatible_version = true; return MigrateToVersion53AddNewTabURLColumn(); @@ -315,140 +276,6 @@ return ColumnsForVersion(WebDatabase::kCurrentVersionNumber, false); } -bool KeywordTable::MigrateToVersion21AutoGenerateKeywordColumn() { - return db_->Execute("ALTER TABLE keywords ADD COLUMN autogenerate_keyword " - "INTEGER DEFAULT 0"); -} - -bool KeywordTable::MigrateToVersion25AddLogoIDColumn() { - return db_->Execute( - "ALTER TABLE keywords ADD COLUMN logo_id INTEGER DEFAULT 0"); -} - -bool KeywordTable::MigrateToVersion26AddCreatedByPolicyColumn() { - return db_->Execute("ALTER TABLE keywords ADD COLUMN created_by_policy " - "INTEGER DEFAULT 0"); -} - -bool KeywordTable::MigrateToVersion28SupportsInstantColumn() { - return db_->Execute("ALTER TABLE keywords ADD COLUMN supports_instant " - "INTEGER DEFAULT 0"); -} - -bool KeywordTable::MigrateToVersion29InstantURLToSupportsInstant() { - sql::Transaction transaction(db_); - return transaction.Begin() && - db_->Execute("ALTER TABLE keywords ADD COLUMN instant_url VARCHAR") && - db_->Execute("CREATE TABLE keywords_temp (" - "id INTEGER PRIMARY KEY," - "short_name VARCHAR NOT NULL," - "keyword VARCHAR NOT NULL," - "favicon_url VARCHAR NOT NULL," - "url VARCHAR NOT NULL," - "safe_for_autoreplace INTEGER," - "originating_url VARCHAR," - "date_created INTEGER DEFAULT 0," - "usage_count INTEGER DEFAULT 0," - "input_encodings VARCHAR," - "show_in_default_list INTEGER," - "suggest_url VARCHAR," - "prepopulate_id INTEGER DEFAULT 0," - "autogenerate_keyword INTEGER DEFAULT 0," - "logo_id INTEGER DEFAULT 0," - "created_by_policy INTEGER DEFAULT 0," - "instant_url VARCHAR)") && - db_->Execute("INSERT INTO keywords_temp SELECT id, short_name, keyword, " - "favicon_url, url, safe_for_autoreplace, originating_url, " - "date_created, usage_count, input_encodings, " - "show_in_default_list, suggest_url, prepopulate_id, " - "autogenerate_keyword, logo_id, created_by_policy, " - "instant_url FROM keywords") && - db_->Execute("DROP TABLE keywords") && - db_->Execute("ALTER TABLE keywords_temp RENAME TO keywords") && - transaction.Commit(); -} - -bool KeywordTable::MigrateToVersion38AddLastModifiedColumn() { - return db_->Execute( - "ALTER TABLE keywords ADD COLUMN last_modified INTEGER DEFAULT 0"); -} - -bool KeywordTable::MigrateToVersion39AddSyncGUIDColumn() { - return db_->Execute("ALTER TABLE keywords ADD COLUMN sync_guid VARCHAR"); -} - -bool KeywordTable::MigrateToVersion44AddDefaultSearchProviderBackup() { - std::string query("CREATE TABLE keywords_backup AS SELECT " + - ColumnsForVersion(44, false) + " FROM keywords ORDER BY id ASC"); - sql::Transaction transaction(db_); - return transaction.Begin() && - meta_table_->SetValue("Default Search Provider ID Backup", - GetDefaultSearchProviderID()) && - (!db_->DoesTableExist("keywords_backup") || - db_->Execute("DROP TABLE keywords_backup")) && - db_->Execute(query.c_str()) && - transaction.Commit(); -} - -bool KeywordTable::MigrateToVersion45RemoveLogoIDAndAutogenerateColumns() { - sql::Transaction transaction(db_); - if (!transaction.Begin()) - return false; - - // The version 43 migration should have been written to do this, but since it - // wasn't, we'll do it now. Unfortunately a previous change deleted this for - // some users, so we can't be sure this will succeed (so don't bail on error). - meta_table_->DeleteKey("Default Search Provider Backup"); - - return MigrateKeywordsTableForVersion45("keywords") && - MigrateKeywordsTableForVersion45("keywords_backup") && - meta_table_->SetValue("Default Search Provider ID Backup Signature", - std::string()) && - transaction.Commit(); -} - -bool KeywordTable::MigrateToVersion47AddAlternateURLsColumn() { - sql::Transaction transaction(db_); - return transaction.Begin() && - db_->Execute("ALTER TABLE keywords ADD COLUMN " - "alternate_urls VARCHAR DEFAULT ''") && - db_->Execute("ALTER TABLE keywords_backup ADD COLUMN " - "alternate_urls VARCHAR DEFAULT ''") && - meta_table_->SetValue("Default Search Provider ID Backup Signature", - std::string()) && - transaction.Commit(); -} - -bool KeywordTable::MigrateToVersion48RemoveKeywordsBackup() { - sql::Transaction transaction(db_); - return transaction.Begin() && - meta_table_->DeleteKey("Default Search Provider ID Backup") && - meta_table_->DeleteKey("Default Search Provider ID Backup Signature") && - db_->Execute("DROP TABLE keywords_backup") && - transaction.Commit(); -} - -bool KeywordTable::MigrateToVersion49AddSearchTermsReplacementKeyColumn() { - return db_->Execute("ALTER TABLE keywords ADD COLUMN " - "search_terms_replacement_key VARCHAR DEFAULT ''"); -} - -bool KeywordTable::MigrateToVersion52AddImageSearchAndPOSTSupport() { - sql::Transaction transaction(db_); - return transaction.Begin() && - db_->Execute("ALTER TABLE keywords ADD COLUMN image_url " - "VARCHAR DEFAULT ''") && - db_->Execute("ALTER TABLE keywords ADD COLUMN search_url_post_params " - "VARCHAR DEFAULT ''") && - db_->Execute("ALTER TABLE keywords ADD COLUMN suggest_url_post_params " - "VARCHAR DEFAULT ''") && - db_->Execute("ALTER TABLE keywords ADD COLUMN instant_url_post_params " - "VARCHAR DEFAULT ''") && - db_->Execute("ALTER TABLE keywords ADD COLUMN image_url_post_params " - "VARCHAR DEFAULT ''") && - transaction.Commit(); -} - bool KeywordTable::MigrateToVersion53AddNewTabURLColumn() { return db_->Execute("ALTER TABLE keywords ADD COLUMN new_tab_url " "VARCHAR DEFAULT ''");
diff --git a/components/search_engines/keyword_table.h b/components/search_engines/keyword_table.h index 62e7e79..ef45694 100644 --- a/components/search_engines/keyword_table.h +++ b/components/search_engines/keyword_table.h
@@ -126,19 +126,6 @@ static std::string GetKeywordColumns(); // Table migration functions. - bool MigrateToVersion21AutoGenerateKeywordColumn(); - bool MigrateToVersion25AddLogoIDColumn(); - bool MigrateToVersion26AddCreatedByPolicyColumn(); - bool MigrateToVersion28SupportsInstantColumn(); - bool MigrateToVersion29InstantURLToSupportsInstant(); - bool MigrateToVersion38AddLastModifiedColumn(); - bool MigrateToVersion39AddSyncGUIDColumn(); - bool MigrateToVersion44AddDefaultSearchProviderBackup(); - bool MigrateToVersion45RemoveLogoIDAndAutogenerateColumns(); - bool MigrateToVersion47AddAlternateURLsColumn(); - bool MigrateToVersion48RemoveKeywordsBackup(); - bool MigrateToVersion49AddSearchTermsReplacementKeyColumn(); - bool MigrateToVersion52AddImageSearchAndPOSTSupport(); bool MigrateToVersion53AddNewTabURLColumn(); bool MigrateToVersion59RemoveExtensionKeywords();
diff --git a/components/storage_monitor/storage_monitor_win_unittest.cc b/components/storage_monitor/storage_monitor_win_unittest.cc index 59aefcb2..fd7ee58 100644 --- a/components/storage_monitor/storage_monitor_win_unittest.cc +++ b/components/storage_monitor/storage_monitor_win_unittest.cc
@@ -97,7 +97,6 @@ void StorageMonitorWinTest::TearDown() { RunUntilIdle(); monitor_->RemoveObserver(&observer_); - volume_mount_watcher_->ShutdownWorkerPool(); // Windows storage monitor must be destroyed on the same thread // as construction.
diff --git a/components/storage_monitor/test_media_transfer_protocol_manager_linux.cc b/components/storage_monitor/test_media_transfer_protocol_manager_linux.cc index 42736db..572c626f 100644 --- a/components/storage_monitor/test_media_transfer_protocol_manager_linux.cc +++ b/components/storage_monitor/test_media_transfer_protocol_manager_linux.cc
@@ -66,4 +66,13 @@ callback.Run(MtpFileEntry(), true); } +void TestMediaTransferProtocolManagerLinux::CopyFileFromLocal( + const std::string& storage_handle, + const int source_file_descriptor, + const uint32 parent_id, + const std::string& file_name, + const CopyFileFromLocalCallback& callback) { + callback.Run(true /* error */); +} + } // namespace storage_monitor
diff --git a/components/storage_monitor/test_media_transfer_protocol_manager_linux.h b/components/storage_monitor/test_media_transfer_protocol_manager_linux.h index 195c8914..51d44c9 100644 --- a/components/storage_monitor/test_media_transfer_protocol_manager_linux.h +++ b/components/storage_monitor/test_media_transfer_protocol_manager_linux.h
@@ -39,6 +39,11 @@ void GetFileInfo(const std::string& storage_handle, uint32 file_id, const GetFileInfoCallback& callback) override; + void CopyFileFromLocal(const std::string& storage_handle, + const int source_file_descriptor, + const uint32 parent_id, + const std::string& file_name, + const CopyFileFromLocalCallback& callback) override; DISALLOW_COPY_AND_ASSIGN(TestMediaTransferProtocolManagerLinux); };
diff --git a/components/storage_monitor/test_volume_mount_watcher_win.cc b/components/storage_monitor/test_volume_mount_watcher_win.cc index 77ea57b..234b87f7 100644 --- a/components/storage_monitor/test_volume_mount_watcher_win.cc +++ b/components/storage_monitor/test_volume_mount_watcher_win.cc
@@ -11,6 +11,7 @@ #include "base/files/scoped_temp_dir.h" #include "base/strings/utf_string_conversions.h" #include "components/storage_monitor/storage_info.h" +#include "content/public/browser/browser_thread.h" namespace storage_monitor { @@ -108,7 +109,7 @@ } void TestVolumeMountWatcherWin::FlushWorkerPoolForTesting() { - device_info_worker_pool_->FlushForTesting(); + content::BrowserThread::GetBlockingPool()->FlushForTesting(); } void TestVolumeMountWatcherWin::DeviceCheckComplete( @@ -150,8 +151,4 @@ return base::Bind(&FakeGetSingleAttachedDevice); } -void TestVolumeMountWatcherWin::ShutdownWorkerPool() { - device_info_worker_pool_->Shutdown(); -} - } // namespace storage_monitor
diff --git a/components/storage_monitor/test_volume_mount_watcher_win.h b/components/storage_monitor/test_volume_mount_watcher_win.h index 267d0960..5191997 100644 --- a/components/storage_monitor/test_volume_mount_watcher_win.h +++ b/components/storage_monitor/test_volume_mount_watcher_win.h
@@ -53,10 +53,6 @@ virtual GetDeviceDetailsCallbackType GetDeviceDetailsCallback() const override; - // Should be used by unit tests to make sure the worker pool doesn't survive - // into other test runs. - void ShutdownWorkerPool(); - private: std::vector<base::FilePath> devices_checked_; scoped_ptr<base::WaitableEvent> device_check_complete_event_;
diff --git a/components/storage_monitor/volume_mount_watcher_win.cc b/components/storage_monitor/volume_mount_watcher_win.cc index fd3e6a5..6a89e1a1 100644 --- a/components/storage_monitor/volume_mount_watcher_win.cc +++ b/components/storage_monitor/volume_mount_watcher_win.cc
@@ -34,6 +34,8 @@ const DWORD kMaxPathBufLen = MAX_PATH + 1; +const char kDeviceInfoTaskRunnerName[] = "device-info-task-runner"; + enum DeviceType { FLOPPY, REMOVABLE, @@ -324,18 +326,12 @@ } // namespace -const int kWorkerPoolNumThreads = 3; -const char* kWorkerPoolNamePrefix = "DeviceInfoPool"; - VolumeMountWatcherWin::VolumeMountWatcherWin() - : device_info_worker_pool_(new base::SequencedWorkerPool( - kWorkerPoolNumThreads, kWorkerPoolNamePrefix)), - notifications_(NULL), - weak_factory_(this) { - task_runner_ = - device_info_worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( - device_info_worker_pool_->GetSequenceToken(), - base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); + : notifications_(NULL), weak_factory_(this) { + base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool(); + device_info_task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior( + pool->GetNamedSequenceToken(kDeviceInfoTaskRunnerName), + base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); } // static @@ -361,7 +357,7 @@ // so a posted task from the constructor would never run. Therefore, do all // the initializations here. base::PostTaskAndReplyWithResult( - task_runner_.get(), FROM_HERE, GetAttachedDevicesCallback(), + device_info_task_runner_.get(), FROM_HERE, GetAttachedDevicesCallback(), base::Bind(&VolumeMountWatcherWin::AddDevicesOnUIThread, weak_factory_.GetWeakPtr())); } @@ -374,7 +370,7 @@ if (ContainsKey(pending_device_checks_, removable_devices[i])) continue; pending_device_checks_.insert(removable_devices[i]); - task_runner_->PostTask( + device_info_task_runner_->PostTask( FROM_HERE, base::Bind(&VolumeMountWatcherWin::RetrieveInfoForDeviceAndAdd, removable_devices[i], GetDeviceDetailsCallback(), @@ -503,7 +499,6 @@ VolumeMountWatcherWin::~VolumeMountWatcherWin() { weak_factory_.InvalidateWeakPtrs(); - device_info_worker_pool_->Shutdown(); } void VolumeMountWatcherWin::HandleDeviceAttachEventOnUIThread( @@ -548,9 +543,9 @@ return; } - task_runner_->PostTask( - FROM_HERE, - base::Bind(&EjectDeviceInThreadPool, device, callback, task_runner_, 0)); + device_info_task_runner_->PostTask( + FROM_HERE, base::Bind(&EjectDeviceInThreadPool, device, callback, + device_info_task_runner_, 0)); } } // namespace storage_monitor
diff --git a/components/storage_monitor/volume_mount_watcher_win.h b/components/storage_monitor/volume_mount_watcher_win.h index 48f37416..bf351db6 100644 --- a/components/storage_monitor/volume_mount_watcher_win.h +++ b/components/storage_monitor/volume_mount_watcher_win.h
@@ -16,7 +16,6 @@ #include "base/memory/weak_ptr.h" #include "base/sequenced_task_runner.h" #include "base/strings/string16.h" -#include "base/threading/sequenced_worker_pool.h" #include "components/storage_monitor/storage_info.h" #include "components/storage_monitor/storage_monitor.h" @@ -90,11 +89,8 @@ virtual GetAttachedDevicesCallbackType GetAttachedDevicesCallback() const; virtual GetDeviceDetailsCallbackType GetDeviceDetailsCallback() const; - // Worker pool used to collect device information. Used because some - // devices freeze workers trying to get device info, resulting in - // shutdown hangs. - scoped_refptr<base::SequencedWorkerPool> device_info_worker_pool_; - scoped_refptr<base::SequencedTaskRunner> task_runner_; + // Used for device info calls that may take a long time. + scoped_refptr<base::SequencedTaskRunner> device_info_task_runner_; private: friend class TestVolumeMountWatcherWin;
diff --git a/components/test/data/password_manager/automated_tests/run_tests.py b/components/test/data/password_manager/automated_tests/run_tests.py index 2c0b799..eb2450a 100644 --- a/components/test/data/password_manager/automated_tests/run_tests.py +++ b/components/test/data/password_manager/automated_tests/run_tests.py
@@ -3,21 +3,25 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -"""This file allows the bots to be easily configure and run the tests. +"""This file allows the bots to be easily configured and run the tests. Running this script requires passing --config-path with a path to a config file of the following structure: + [data_files] passwords_path=<path to a file with passwords> [binaries] chrome-path=<chrome binary path> chromedriver-path=<chrome driver path> [run_options] + # |write_to_sheet| is optional, the default value is false. write_to_sheet=[false|true] - tests_in_parrallel=<number of parallel tests> + # |tests_in_parallel| is optional, the default value is 1. + tests_in_parallel=<number of parallel tests> # |tests_to_runs| field is optional, if it is absent all tests will be run. tests_to_run=<test names to run, comma delimited> [output] + # |save-path| is optional, the default value is /dev/null. save-path=<file where to save result> [sheet_info] # This section is required only when write_to_sheet=true @@ -177,14 +181,39 @@ print "Run of test %s started" % self.test_name self.runner_process = subprocess.Popen(self.test_cmd) +def _apply_defaults(config, defaults): + """Adds default values from |defaults| to |config|. + + Note: This differs from ConfigParser's mechanism for providing defaults in + two aspects: + * The "defaults" here become explicit, and are associated with sections. + * Sections get created for the added defaults where needed, that is, if + they do not exist before. + + Args: + config: A ConfigParser instance to be updated + defaults: A dictionary mapping (section_string, option_string) pairs + to string values. For every section/option combination not already + contained in |config|, the value from |defaults| is stored in |config|. + """ + for (section, option) in defaults: + if not config.has_section(section): + config.add_section(section) + if not config.has_option(section, option): + config.set(section, option, defaults[(section, option)]) + def run_tests(config_path): """ Runs automated tests. """ environment = Environment("", "", "", None, False) tests.Tests(environment) + defaults = { ("output", "save-path"): "/dev/null", + ("run_options", "tests_in_parallel"): "1", + ("run_options", "write_to_sheet"): "false" } config = ConfigParser.ConfigParser() + _apply_defaults(config, defaults) config.read(config_path) date = datetime.now().strftime('%Y-%m-%dT%H:%M:%S') - max_tests_in_parrallel = config.getint("run_options", "tests_in_parrallel") + max_tests_in_parallel = config.getint("run_options", "tests_in_parallel") sheet_writer = SheetWriter(config) full_path = os.path.realpath(__file__) tests_dir = os.path.dirname(full_path) @@ -214,7 +243,7 @@ del runners[i] else: i += 1 - while len(runners) < max_tests_in_parrallel and len(tests_to_run) > 0: + while len(runners) < max_tests_in_parallel and len(tests_to_run) > 0: runners.append(TestRunner(general_test_cmd, tests_to_run.pop())) time.sleep(1) # Let us wait for worker process to finish.
diff --git a/components/test/data/web_database/version_20.sql b/components/test/data/web_database/version_20.sql deleted file mode 100644 index c3913ef2..0000000 --- a/components/test/data/web_database/version_20.sql +++ /dev/null
@@ -1,23 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','20'); -INSERT INTO "meta" VALUES('last_compatible_version','20'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','27'); -INSERT INTO "meta" VALUES('Default Search Provider ID','7'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL, keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1); -INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2); -INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3); -INSERT INTO "keywords" VALUES(5,'Wikipedia (en)','en.wikipedia.org','','http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}',1,0,'',1283287335,0,'','',0); -INSERT INTO "keywords" VALUES(6,'NYTimes','query.nytimes.com','','http://query.nytimes.com/gst/handler.html?query={searchTerms}&opensearch=1',1,0,'',1283287335,0,'','',0); -INSERT INTO "keywords" VALUES(7,'eBay','rover.ebay.com','','http://rover.ebay.com/rover/1/711-43047-14818-1/4?satitle={searchTerms}',1,0,'',1283287335,0,'','',0); -INSERT INTO "keywords" VALUES(8,'ff','ff','','http://ff{searchTerms}',0,0,'',1283287356,0,'','',0); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR,signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash); -CREATE INDEX web_apps_url_index ON web_apps (url); -COMMIT;
diff --git a/components/test/data/web_database/version_21.sql b/components/test/data/web_database/version_21.sql deleted file mode 100644 index a77ab7e..0000000 --- a/components/test/data/web_database/version_21.sql +++ /dev/null
@@ -1,40 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','21'); -INSERT INTO "meta" VALUES('last_compatible_version','21'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','27'); -INSERT INTO "meta" VALUES('Default Search Provider ID','7'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL, keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1); -INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0); -INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0); -INSERT INTO "keywords" VALUES(5,'Wikipedia (en)','en.wikipedia.org','','http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}',1,0,'',1283287335,0,'','',0,0); -INSERT INTO "keywords" VALUES(6,'NYTimes','query.nytimes.com','','http://query.nytimes.com/gst/handler.html?query={searchTerms}&opensearch=1',1,0,'',1283287335,0,'','',0,0); -INSERT INTO "keywords" VALUES(7,'eBay','rover.ebay.com','','http://rover.ebay.com/rover/1/711-43047-14818-1/4?satitle={searchTerms}',1,0,'',1283287335,0,'','',0,0); -INSERT INTO "keywords" VALUES(8,'ff','ff','','http://ff{searchTerms}',0,0,'',1283287356,0,'','',0,0); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR,signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -INSERT INTO "autofill" VALUES('Name','John Doe','john doe',10,1); -INSERT INTO "autofill" VALUES('Name','','',11,1); -INSERT INTO "autofill" VALUES('Email','jane@example.com','jane@example.com',20,3); -INSERT INTO "autofill" VALUES('Email','','',21,4); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,date_created INTEGER DEFAULT 0); -INSERT INTO "autofill_dates" VALUES(10,1384299100); -INSERT INTO "autofill_dates" VALUES(11,1384299200); -INSERT INTO "autofill_dates" VALUES(20,1384299300); -INSERT INTO "autofill_dates" VALUES(20,1384299301); -INSERT INTO "autofill_dates" VALUES(21,1384299401); -INSERT INTO "autofill_dates" VALUES(21,1384299400); -INSERT INTO "autofill_dates" VALUES(21,1384299403); -INSERT INTO "autofill_dates" VALUES(21,1384299402); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -COMMIT;
diff --git a/components/test/data/web_database/version_22.sql b/components/test/data/web_database/version_22.sql deleted file mode 100644 index c7cc8b5..0000000 --- a/components/test/data/web_database/version_22.sql +++ /dev/null
@@ -1,28 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','22'); -INSERT INTO "meta" VALUES('last_compatible_version','21'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','27'); -INSERT INTO "meta" VALUES('Default Search Provider ID','7'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL, keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1); -INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0); -INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0); -INSERT INTO "keywords" VALUES(5,'Wikipedia (en)','en.wikipedia.org','','http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}',1,0,'',1283287335,0,'','',0,0); -INSERT INTO "keywords" VALUES(6,'NYTimes','query.nytimes.com','','http://query.nytimes.com/gst/handler.html?query={searchTerms}&opensearch=1',1,0,'',1283287335,0,'','',0,0); -INSERT INTO "keywords" VALUES(7,'eBay','rover.ebay.com','','http://rover.ebay.com/rover/1/711-43047-14818-1/4?satitle={searchTerms}',1,0,'',1283287335,0,'','',0,0); -INSERT INTO "keywords" VALUES(8,'ff','ff','','http://ff{searchTerms}',0,0,'',1283287356,0,'','',0,0); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR,signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,date_created INTEGER DEFAULT 0); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -COMMIT;
diff --git a/components/test/data/web_database/version_22_corrupt.sql b/components/test/data/web_database/version_22_corrupt.sql deleted file mode 100644 index 82d9b3f..0000000 --- a/components/test/data/web_database/version_22_corrupt.sql +++ /dev/null
@@ -1,32 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','22'); -INSERT INTO "meta" VALUES('last_compatible_version','21'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','29'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1); -INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0); -INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0); -INSERT INTO "keywords" VALUES(5,'Wikipedia (en)','en.wikipedia.org','','http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}',1,0,'',1283287335,0,'','',0,0); -INSERT INTO "keywords" VALUES(6,'NYTimes','query.nytimes.com','','http://query.nytimes.com/gst/handler.html?query={searchTerms}&opensearch=1',1,0,'',1283287335,0,'','',0,0); -INSERT INTO "keywords" VALUES(7,'eBay','rover.ebay.com','','http://rover.ebay.com/rover/1/711-43047-14818-1/4?satitle={searchTerms}',1,0,'',1283287335,0,'','',0,0); -INSERT INTO "keywords" VALUES(8,'ff','ff','','http://ff{searchTerms}',0,0,'',1283287356,0,'','',0,0); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL, ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL, date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL, scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB,date_created INTEGER NOT NULL,UNIQUE (url_hash)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( label VARCHAR, unique_id INTEGER PRIMARY KEY, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, email VARCHAR, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR); -CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY, name_on_card VARCHAR, type VARCHAR,card_number VARCHAR, expiration_month INTEGER, expiration_year INTEGER, verification_code VARCHAR, billing_address VARCHAR, shipping_address VARCHAR, card_number_encrypted BLOB, verification_code_encrypted BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label); -CREATE INDEX credit_cards_label_index ON credit_cards (label); -COMMIT;
diff --git a/components/test/data/web_database/version_25.sql b/components/test/data/web_database/version_25.sql deleted file mode 100644 index 986ca9f..0000000 --- a/components/test/data/web_database/version_25.sql +++ /dev/null
@@ -1,23 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','25'); -INSERT INTO "meta" VALUES('last_compatible_version','25'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','29'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR,username_element VARCHAR, username_value VARCHAR,password_element VARCHAR, password_value BLOB, submit_element VARCHAR,signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element,username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR,pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( label VARCHAR,unique_id INTEGER PRIMARY KEY, first_name VARCHAR,middle_name VARCHAR, last_name VARCHAR, email VARCHAR,company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR,city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR,phone VARCHAR, fax VARCHAR); -CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY,name_on_card VARCHAR, type VARCHAR, card_number VARCHAR,expiration_month INTEGER, expiration_year INTEGER,verification_code VARCHAR, billing_address VARCHAR,shipping_address VARCHAR, card_number_encrypted BLOB,verification_code_encrypted BLOB); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label); -CREATE INDEX credit_cards_label_index ON credit_cards (label); -COMMIT;
diff --git a/components/test/data/web_database/version_26.sql b/components/test/data/web_database/version_26.sql deleted file mode 100644 index 5cf1a97..0000000 --- a/components/test/data/web_database/version_26.sql +++ /dev/null
@@ -1,23 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','26'); -INSERT INTO "meta" VALUES('last_compatible_version','26'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','29'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR,username_element VARCHAR, username_value VARCHAR,password_element VARCHAR, password_value BLOB, submit_element VARCHAR,signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element,username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR,pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( label VARCHAR,unique_id INTEGER PRIMARY KEY, first_name VARCHAR,middle_name VARCHAR, last_name VARCHAR, email VARCHAR,company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR,city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR,phone VARCHAR, fax VARCHAR); -CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY,name_on_card VARCHAR, type VARCHAR, card_number VARCHAR,expiration_month INTEGER, expiration_year INTEGER,verification_code VARCHAR, billing_address VARCHAR,shipping_address VARCHAR, card_number_encrypted BLOB,verification_code_encrypted BLOB); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label); -CREATE INDEX credit_cards_label_index ON credit_cards (label); -COMMIT;
diff --git a/components/test/data/web_database/version_27.sql b/components/test/data/web_database/version_27.sql deleted file mode 100644 index 4733afa..0000000 --- a/components/test/data/web_database/version_27.sql +++ /dev/null
@@ -1,26 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','27'); -INSERT INTO "meta" VALUES('last_compatible_version','27'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','29'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6245,0); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( label VARCHAR, unique_id INTEGER PRIMARY KEY, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, email VARCHAR, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR); -CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY, name_on_card VARCHAR, type VARCHAR, card_number VARCHAR, expiration_month INTEGER, expiration_year INTEGER, verification_code VARCHAR, billing_address VARCHAR, shipping_address VARCHAR, card_number_encrypted BLOB, verification_code_encrypted BLOB); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label); -CREATE INDEX credit_cards_label_index ON credit_cards (label); -COMMIT;
diff --git a/components/test/data/web_database/version_29.sql b/components/test/data/web_database/version_29.sql deleted file mode 100644 index ab03275..0000000 --- a/components/test/data/web_database/version_29.sql +++ /dev/null
@@ -1,29 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','29'); -INSERT INTO "meta" VALUES('last_compatible_version','29'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','29'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6245,0,'{google:baseURL}search?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&q={searchTerms}'); -INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6262,0,''); -INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6239,0,''); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( label VARCHAR, unique_id INTEGER PRIMARY KEY, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, email VARCHAR, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR); -INSERT INTO "autofill_profiles" VALUES('Santa Claus, 1 Reindeer Lane',1,'Santa','','Claus','','','1 Reindeer Lane','P.O. Box 56009','North Pole','','H0H 0H0','CANADA','',''); -CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY, name_on_card VARCHAR, type VARCHAR, card_number VARCHAR, expiration_month INTEGER, expiration_year INTEGER, verification_code VARCHAR, billing_address VARCHAR, shipping_address VARCHAR, card_number_encrypted BLOB, verification_code_encrypted BLOB); -INSERT INTO "credit_cards" VALUES('',2,'Kris Kringle','','',12,2020,'','1','',X'',X''); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label); -CREATE INDEX credit_cards_label_index ON credit_cards (label); -COMMIT;
diff --git a/components/test/data/web_database/version_30.sql b/components/test/data/web_database/version_30.sql deleted file mode 100644 index 698605c..0000000 --- a/components/test/data/web_database/version_30.sql +++ /dev/null
@@ -1,31 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','30'); -INSERT INTO "meta" VALUES('last_compatible_version','30'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','30'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6245,0,'{google:baseURL}search?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&q={searchTerms}'); -INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6262,0,''); -INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6239,0,''); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( label VARCHAR, unique_id INTEGER PRIMARY KEY, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, email VARCHAR, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -INSERT INTO "autofill_profiles" VALUES('Jim Johnson, 789 4th Street',1,'Jim','','Johnson','jim@acme.com','Acme Inc.','789 4th Street','Apt. #4','San Francisco','CA','94102','USA','4155512255','4155512233',1287508123); -INSERT INTO "autofill_profiles" VALUES('Billy Jean, 1 Ghost Blvd.',3,'Billy','','Jean','billy@thriller.com','Thriller Inc.','1 Ghost Blvd.','','Santa Monica','CA','98990','USA','4431110000','',1287508123); -CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY, name_on_card VARCHAR, type VARCHAR, card_number VARCHAR, expiration_month INTEGER, expiration_year INTEGER, verification_code VARCHAR, billing_address VARCHAR, shipping_address VARCHAR, card_number_encrypted BLOB, verification_code_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -INSERT INTO "credit_cards" VALUES('',2,'Jim X Johnson','','',1,2011,'','1','',X'763130B83A1BEE0CFD7C447C270685B5E2BFF5EC0BC700B38F4C4DD60CDD5D8D66EB09',X'',1287508123); -INSERT INTO "credit_cards" VALUES('2',4,'Billy X Jean','','',7,2017,'','3','',X'763130EB3DC27FA61AAC9EAC92B303978DD7B62E901B4D9DFB459905E09AAAE7AE7BA1',X'',1287508123); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label); -CREATE INDEX credit_cards_label_index ON credit_cards (label); -COMMIT;
diff --git a/components/test/data/web_database/version_31.sql b/components/test/data/web_database/version_31.sql deleted file mode 100644 index bfa7443..0000000 --- a/components/test/data/web_database/version_31.sql +++ /dev/null
@@ -1,29 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','31'); -INSERT INTO "meta" VALUES('last_compatible_version','31'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','32'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6247,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}'); -INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6264,0,''); -INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6241,0,''); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( label VARCHAR, unique_id INTEGER PRIMARY KEY, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, email VARCHAR, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, guid VARCHAR NOT NULL DEFAULT ""); -INSERT INTO "autofill_profiles" VALUES('Elvis Presley, 1122 PBJ Lane',1,'Elvis','','Presley','elvis@elvis.com','Hip Shake Inc.','1122 PBJ Lane','Suite 1','Memphis','TN','38116','UK','9013323322','',1288642516,'A4FF32F6-EF3F-379A-87F2-40A8811182A7'); -CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY, name_on_card VARCHAR, type VARCHAR, card_number VARCHAR, expiration_month INTEGER, expiration_year INTEGER, verification_code VARCHAR, billing_address VARCHAR, shipping_address VARCHAR, card_number_encrypted BLOB, verification_code_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, guid VARCHAR NOT NULL DEFAULT ""); -INSERT INTO "credit_cards" VALUES('',2,'Jim J Jones','','',1,2011,'','0','',X'7631309863E9F1F33C2BDBFBFC86708448BDD8B37A495B628C8459A60D0CCD1047E69F',X'',1288642516,'B77F749C-8B0E-44B2-D299-3C80A95E0ADD'); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label); -CREATE INDEX credit_cards_label_index ON credit_cards (label); -COMMIT;
diff --git a/components/test/data/web_database/version_32.sql b/components/test/data/web_database/version_32.sql deleted file mode 100644 index 7030608..0000000 --- a/components/test/data/web_database/version_32.sql +++ /dev/null
@@ -1,33 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','32'); -INSERT INTO "meta" VALUES('last_compatible_version','32'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','33'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6256,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1'); -INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6273,0,''); -INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6250,0,''); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, label VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, email VARCHAR, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -INSERT INTO "autofill_profiles" VALUES('00580526-FF81-EE2A-0546-1AC593A32E2F','John Doe, 1 Main St','John','','Doe','john@doe.com','Doe Enterprises','1 Main St','Apt 1','Los Altos','CA','94022','USA','4151112222','4153334444',1297882100); -INSERT INTO "autofill_profiles" VALUES('589636FD-9037-3053-200C-80ABC97D7344','John P. Doe, 1 Main St','John','P.','Doe','john@doe.com','Doe Enterprises','1 Main St','Apt 1','Los Altos','CA','94022','USA','4151112222','4153334444',1297882100); -INSERT INTO "autofill_profiles" VALUES('4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396','Dave Smith, 2 Main Street','Dave','','Smith','','','2 Main Street','','Los Altos','CA','94022','USA','','',1297882100); -INSERT INTO "autofill_profiles" VALUES('722DF5C4-F74A-294A-46F0-31FFDED0D635','Dave Smith, 2 Main St','Dave','','Smith','','','2 Main St','','Los Altos','CA','94022','USA','','',1297882100); -INSERT INTO "autofill_profiles" VALUES('584282AC-5D21-8D73-A2DB-4F892EF61F3F','Alfred E Newman, a@e.com','Alfred','E','Newman','a@e.com','','','','','','','','','',1297882100); -INSERT INTO "autofill_profiles" VALUES('9E5FE298-62C7-83DF-6293-381BC589183F','3 Main St, Los Altos','','','','','','3 Main St','','Los Altos','CA','94022','USA','','',1297882100); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, label VARCHAR, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label); -CREATE INDEX credit_cards_label_index ON credit_cards (label); -COMMIT;
diff --git a/components/test/data/web_database/version_33.sql b/components/test/data/web_database/version_33.sql deleted file mode 100644 index a5eb2ae9..0000000 --- a/components/test/data/web_database/version_33.sql +++ /dev/null
@@ -1,32 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','33'); -INSERT INTO "meta" VALUES('last_compatible_version','33'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','33'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6256,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1'); -INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6273,0,''); -INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6250,0,''); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -INSERT INTO "autofill_profiles" VALUES('45285F35-4A04-5F47-DBCC-CA8C2F2A5944','Hip Shake Inc.','1122 PBJ Lane','Suite 1','Memphis','TN','38116','United States',1298621949); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -INSERT INTO "autofill_profile_names" VALUES('45285F35-4A04-5F47-DBCC-CA8C2F2A5944','Elvis','','Presley'); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -INSERT INTO "autofill_profile_emails" VALUES('45285F35-4A04-5F47-DBCC-CA8C2F2A5944','elvis@elvis.com'); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -INSERT INTO "autofill_profile_phones" VALUES('45285F35-4A04-5F47-DBCC-CA8C2F2A5944',0,'9013323322'); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -COMMIT;
diff --git a/components/test/data/web_database/version_34.sql b/components/test/data/web_database/version_34.sql deleted file mode 100644 index 8a29a95..0000000 --- a/components/test/data/web_database/version_34.sql +++ /dev/null
@@ -1,54 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','33'); -INSERT INTO "meta" VALUES('version','34'); -INSERT INTO "meta" VALUES('last_compatible_version','34'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6256,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1'); -INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6273,0,''); -INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6250,0,''); -INSERT INTO "keywords" VALUES(5,'Search the web (Babylon)','search.babylon.com','','http://search.babylon.com/web/{searchTerms}?babsrc=browsersearch',1,0,'',1299093361,0,'','',0,0,0,0,''); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -INSERT INTO "autofill" VALUES('firstname','David','david',1,1); -INSERT INTO "autofill" VALUES('lastname','Holloway','holloway',2,1); -INSERT INTO "autofill" VALUES('email','d@gmail.com','d@gmail.com',3,1); -INSERT INTO "autofill" VALUES('phone','415-551-2222','415-551-2222',4,1); -INSERT INTO "autofill" VALUES('fax','415-551-2222','415-551-2222',5,1); -INSERT INTO "autofill" VALUES('address','1122 Boogie Boogie Avenue','1122 boogie boogie avenue',6,1); -INSERT INTO "autofill" VALUES('city','San Francisco','san francisco',7,1); -INSERT INTO "autofill" VALUES('zipcode','11001','11001',8,1); -INSERT INTO "autofill" VALUES('country','UK','uk',9,1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -INSERT INTO "autofill_dates" VALUES(1,1299093389); -INSERT INTO "autofill_dates" VALUES(2,1299093389); -INSERT INTO "autofill_dates" VALUES(3,1299093389); -INSERT INTO "autofill_dates" VALUES(4,1299093389); -INSERT INTO "autofill_dates" VALUES(5,1299093389); -INSERT INTO "autofill_dates" VALUES(6,1299093389); -INSERT INTO "autofill_dates" VALUES(7,1299093389); -INSERT INTO "autofill_dates" VALUES(8,1299093389); -INSERT INTO "autofill_dates" VALUES(9,1299093389); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, country_code VARCHAR); -INSERT INTO "autofill_profiles" VALUES('F19484ED-363F-4506-997E-E0F23EA834AB','','1122 Boogie Boogie Avenue','','San Francisco','?','11001','UK',1299093389,'UK'); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -INSERT INTO "autofill_profile_names" VALUES('F19484ED-363F-4506-997E-E0F23EA834AB','David','','Holloway'); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -INSERT INTO "autofill_profile_emails" VALUES('F19484ED-363F-4506-997E-E0F23EA834AB','d@gmail.com'); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -INSERT INTO "autofill_profile_phones" VALUES('F19484ED-363F-4506-997E-E0F23EA834AB',0,'4155512222'); -INSERT INTO "autofill_profile_phones" VALUES('F19484ED-363F-4506-997E-E0F23EA834AB',1,'4155512222'); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -COMMIT;
diff --git a/components/test/data/web_database/version_35.sql b/components/test/data/web_database/version_35.sql deleted file mode 100644 index 2c0738cb..0000000 --- a/components/test/data/web_database/version_35.sql +++ /dev/null
@@ -1,59 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','35'); -INSERT INTO "meta" VALUES('last_compatible_version','35'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','33'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1'); -INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6279,0,''); -INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6256,0,''); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); - -/* A "John Doe" profile with all-valid fields. */ -INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000001','Acme Inc.','1 Main Street','Apt 2','San Francisco','CA','94102','United States','US',1300131704); -INSERT INTO "autofill_profile_names" VALUES('00000000-0000-0000-0000-000000000001','John','','Doe'); -INSERT INTO "autofill_profile_emails" VALUES('00000000-0000-0000-0000-000000000001','john@doe.com'); -INSERT INTO "autofill_profile_phones" VALUES('00000000-0000-0000-0000-000000000001',0,'4151112222'); -INSERT INTO "autofill_profile_phones" VALUES('00000000-0000-0000-0000-000000000001',1,'4151110000'); - -/* A subset of "John Doe". Should get discarded. */ -INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000002','','1 Main Street','Apt 2','San Francisco','CA','94102','United States','US',1300131704); -INSERT INTO "autofill_profile_names" VALUES('00000000-0000-0000-0000-000000000002','John','','Doe'); -INSERT INTO "autofill_profile_emails" VALUES('00000000-0000-0000-0000-000000000002','john@doe.com'); -INSERT INTO "autofill_profile_phones" VALUES('00000000-0000-0000-0000-000000000002',0,'4151112222'); -INSERT INTO "autofill_profile_phones" VALUES('00000000-0000-0000-0000-000000000002',1,'4151110000'); - -/* A profile with incomplete address. Should get discarded. */ -INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000003','','','Apt 3','San Francisco','CA','94102','United States','US',1300131704); -INSERT INTO "autofill_profile_names" VALUES('00000000-0000-0000-0000-000000000003','Jim','','Smith'); - -/* A profile with bad email. Should get discarded. */ -INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000004','Acme Inc.','4 Main Street','Apt 2','San Francisco','CA','94102','United States','US',1300131704); -INSERT INTO "autofill_profile_emails" VALUES('00000000-0000-0000-0000-000000000004','bademail'); - -/* A profile with bad State (country == US). Should get discarded. */ -INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000005','Acme Inc.','6 Main Street','Apt 2','San Francisco','BS','94102','United States','US',1300131704); -INSERT INTO "autofill_profile_names" VALUES('00000000-0000-0000-0000-000000000006','John','','Doe'); - -/* A profile with bad zip (country == US). Should get discarded. */ -INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000006','Acme Inc.','7 Main Street','Apt 2','San Francisco','CA','bogus','United States','US',1300131704); -INSERT INTO "autofill_profile_names" VALUES('00000000-0000-0000-0000-000000000007','John','','Doe'); - -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -COMMIT;
diff --git a/components/test/data/web_database/version_37.sql b/components/test/data/web_database/version_37.sql deleted file mode 100644 index 045450c..0000000 --- a/components/test/data/web_database/version_37.sql +++ /dev/null
@@ -1,26 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','37'); -INSERT INTO "meta" VALUES('last_compatible_version','37'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','33'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1'); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -COMMIT;
diff --git a/components/test/data/web_database/version_38.sql b/components/test/data/web_database/version_38.sql deleted file mode 100644 index 679ad987..0000000 --- a/components/test/data/web_database/version_38.sql +++ /dev/null
@@ -1,26 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','38'); -INSERT INTO "meta" VALUES('last_compatible_version','38'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','33'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -COMMIT;
diff --git a/components/test/data/web_database/version_39.sql b/components/test/data/web_database/version_39.sql deleted file mode 100644 index d8f4c9f1..0000000 --- a/components/test/data/web_database/version_39.sql +++ /dev/null
@@ -1,26 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','39'); -INSERT INTO "meta" VALUES('last_compatible_version','39'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','33'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}'); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -COMMIT;
diff --git a/components/test/data/web_database/version_40.sql b/components/test/data/web_database/version_40.sql deleted file mode 100644 index 5eee626..0000000 --- a/components/test/data/web_database/version_40.sql +++ /dev/null
@@ -1,29 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','40'); -INSERT INTO "meta" VALUES('last_compatible_version','40'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature',''); -INSERT INTO "meta" VALUES('Builtin Keyword Version','33'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}'); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -COMMIT; -
diff --git a/components/test/data/web_database/version_41.sql b/components/test/data/web_database/version_41.sql deleted file mode 100644 index 4804d167..0000000 --- a/components/test/data/web_database/version_41.sql +++ /dev/null
@@ -1,30 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','41'); -INSERT INTO "meta" VALUES('last_compatible_version','41'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature',''); -INSERT INTO "meta" VALUES('Builtin Keyword Version','33'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}'); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -COMMIT; - -
diff --git a/components/test/data/web_database/version_42.sql b/components/test/data/web_database/version_42.sql deleted file mode 100644 index 01b99253..0000000 --- a/components/test/data/web_database/version_42.sql +++ /dev/null
@@ -1,30 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','42'); -INSERT INTO "meta" VALUES('last_compatible_version','42'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature',''); -INSERT INTO "meta" VALUES('Default Search Provider Backup','2Googlegoogle.comhttp://www.google.com/favicon.ico{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}100UTF-81{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}1162620{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=10{1234-5678-90AB-CDEF}'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','33'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}'); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -COMMIT; -
diff --git a/components/test/data/web_database/version_43.sql b/components/test/data/web_database/version_43.sql deleted file mode 100644 index e0bcd549..0000000 --- a/components/test/data/web_database/version_43.sql +++ /dev/null
@@ -1,31 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','43'); -INSERT INTO "meta" VALUES('last_compatible_version','43'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup','3'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature',''); -INSERT INTO "meta" VALUES('Builtin Keyword Version','37'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,1234,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}'); -CREATE TABLE keywords_backup (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR); -INSERT INTO "keywords_backup" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,1234,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}'); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -COMMIT; -
diff --git a/components/test/data/web_database/version_44.sql b/components/test/data/web_database/version_44.sql deleted file mode 100644 index e36ffea8..0000000 --- a/components/test/data/web_database/version_44.sql +++ /dev/null
@@ -1,53 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','44'); -INSERT INTO "meta" VALUES('last_compatible_version','44'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup','0'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature',''); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR); -CREATE TABLE keywords_backup( - id INT, - short_name TEXT, - keyword TEXT, - favicon_url TEXT, - url TEXT, - safe_for_autoreplace INT, - originating_url TEXT, - date_created INT, - usage_count INT, - input_encodings TEXT, - show_in_default_list INT, - suggest_url TEXT, - prepopulate_id INT, - autogenerate_keyword INT, - logo_id INT, - created_by_policy INT, - instant_url TEXT, - last_modified INT, - sync_guid TEXT -); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); -CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash)); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE TABLE web_intents (service_url LONGVARCHAR,action VARCHAR,type VARCHAR,title LONGVARCHAR,disposition VARCHAR,UNIQUE (service_url, action, type)); -CREATE TABLE web_intents_defaults (action VARCHAR,type VARCHAR,url_pattern LONGVARCHAR,user_date INTEGER,suppression INTEGER,service_url LONGVARCHAR,UNIQUE (action, type, url_pattern)); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX logins_signon ON logins (signon_realm); -CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX web_intents_index ON web_intents (action); -CREATE INDEX web_intents_default_index ON web_intents_defaults (action); -COMMIT;
diff --git a/components/test/data/web_database/version_45.sql b/components/test/data/web_database/version_45.sql deleted file mode 100644 index 4b1e70a..0000000 --- a/components/test/data/web_database/version_45.sql +++ /dev/null
@@ -1,53 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('version','45'); -INSERT INTO "meta" VALUES('last_compatible_version','45'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature',''); -INSERT INTO "meta" VALUES('Builtin Keyword Version','39'); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE TABLE web_intents (service_url LONGVARCHAR,action VARCHAR,type VARCHAR,title LONGVARCHAR,disposition VARCHAR,UNIQUE (service_url, action, type)); -CREATE TABLE web_intents_defaults (action VARCHAR,type VARCHAR,url_pattern LONGVARCHAR,user_date INTEGER,suppression INTEGER,service_url LONGVARCHAR,UNIQUE (action, type, url_pattern)); -CREATE TABLE "keywords" (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR); -CREATE TABLE keywords_backup( - id INT, - short_name TEXT, - keyword TEXT, - favicon_url TEXT, - url TEXT, - safe_for_autoreplace INT, - originating_url TEXT, - date_created INT, - usage_count INT, - input_encodings TEXT, - show_in_default_list INT, - suggest_url TEXT, - prepopulate_id INT, - created_by_policy INT, - instant_url TEXT, - last_modified INT, - sync_guid TEXT -); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX web_intents_index ON web_intents (action); -CREATE INDEX web_intents_default_index ON web_intents_defaults (action); --- following statements are required for testing migration to version 46 -INSERT INTO web_intents VALUES ('http://poodles.com/fuzzer', 'fuzz', 'poodle/*', 'Poodle Fuzzer', 'window'); -INSERT INTO web_intents_defaults VALUES ('fuzz', 'poodle/*', '', 0, 0, 'http://poodles.com/fuzzer'); -COMMIT; -
diff --git a/components/test/data/web_database/version_45_compatible.sql b/components/test/data/web_database/version_45_compatible.sql deleted file mode 100644 index 158c40df..0000000 --- a/components/test/data/web_database/version_45_compatible.sql +++ /dev/null
@@ -1,50 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('version','40'); -INSERT INTO "meta" VALUES('last_compatible_version','45'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature',''); -INSERT INTO "meta" VALUES('Builtin Keyword Version','39'); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE TABLE web_intents (service_url LONGVARCHAR,action VARCHAR,type VARCHAR,title LONGVARCHAR,disposition VARCHAR,UNIQUE (service_url, action, type)); -CREATE TABLE web_intents_defaults (action VARCHAR,type VARCHAR,url_pattern LONGVARCHAR,user_date INTEGER,suppression INTEGER,service_url LONGVARCHAR,UNIQUE (action, type, url_pattern)); -CREATE TABLE "keywords" (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR); -CREATE TABLE keywords_backup( - id INT, - short_name TEXT, - keyword TEXT, - favicon_url TEXT, - url TEXT, - safe_for_autoreplace INT, - originating_url TEXT, - date_created INT, - usage_count INT, - input_encodings TEXT, - show_in_default_list INT, - suggest_url TEXT, - prepopulate_id INT, - created_by_policy INT, - instant_url TEXT, - last_modified INT, - sync_guid TEXT -); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX web_intents_index ON web_intents (action); -CREATE INDEX web_intents_default_index ON web_intents_defaults (action); -COMMIT; -
diff --git a/components/test/data/web_database/version_45_invalid.sql b/components/test/data/web_database/version_45_invalid.sql deleted file mode 100644 index ff2b94b..0000000 --- a/components/test/data/web_database/version_45_invalid.sql +++ /dev/null
@@ -1,50 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('version','45'); -INSERT INTO "meta" VALUES('last_compatible_version','45'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature',''); -INSERT INTO "meta" VALUES('Builtin Keyword Version','39'); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE TABLE web_intents (INTEGER blabbity); -CREATE TABLE web_intents_defaults (VARCHAR hammy); -CREATE TABLE "keywords" (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR); -CREATE TABLE keywords_backup( - id INT, - short_name TEXT, - keyword TEXT, - favicon_url TEXT, - url TEXT, - safe_for_autoreplace INT, - originating_url TEXT, - date_created INT, - usage_count INT, - input_encodings TEXT, - show_in_default_list INT, - suggest_url TEXT, - prepopulate_id INT, - created_by_policy INT, - instant_url TEXT, - last_modified INT, - sync_guid TEXT -); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX web_apps_url_index ON web_apps (url); --- following statements are required for testing migration to version 46 -INSERT INTO web_intents VALUES (11); -INSERT INTO web_intents_defaults VALUES ('fuzz'); -COMMIT;
diff --git a/components/test/data/web_database/version_46.sql b/components/test/data/web_database/version_46.sql deleted file mode 100644 index 8dcf7cb..0000000 --- a/components/test/data/web_database/version_46.sql +++ /dev/null
@@ -1,31 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); -INSERT INTO "meta" VALUES('Default Search Provider ID','0'); -INSERT INTO "meta" VALUES('version','46'); -INSERT INTO "meta" VALUES('last_compatible_version','46'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup','0'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature',''); -INSERT INTO "meta" VALUES('Builtin Keyword Version','39'); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE TABLE web_intents (service_url LONGVARCHAR,action VARCHAR,type VARCHAR,title LONGVARCHAR,disposition VARCHAR,scheme VARCHAR,UNIQUE (service_url, action, type)); -CREATE TABLE web_intents_defaults (action VARCHAR,type VARCHAR,url_pattern LONGVARCHAR,user_date INTEGER,suppression INTEGER,service_url LONGVARCHAR,scheme VARCHAR,UNIQUE (action, type, url_pattern)); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR); -CREATE TABLE keywords_backup(id INT,short_name TEXT,keyword TEXT,favicon_url TEXT,url TEXT,safe_for_autoreplace INT,originating_url TEXT,date_created INT,usage_count INT,input_encodings TEXT,show_in_default_list INT,suggest_url TEXT,prepopulate_id INT,created_by_policy INT,instant_url TEXT,last_modified INT,sync_guid TEXT); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX web_intents_index ON web_intents (action); -CREATE INDEX web_intents_default_index ON web_intents_defaults (action); -COMMIT;
diff --git a/components/test/data/web_database/version_47.sql b/components/test/data/web_database/version_47.sql deleted file mode 100644 index aae06e8..0000000 --- a/components/test/data/web_database/version_47.sql +++ /dev/null
@@ -1,50 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','47'); -INSERT INTO "meta" VALUES('last_compatible_version','47'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','46'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2'); -INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature',''); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR); -CREATE TABLE keywords_backup( - id INT, - short_name TEXT, - keyword TEXT, - favicon_url TEXT, - url TEXT, - safe_for_autoreplace INT, - originating_url TEXT, - date_created INT, - usage_count INT, - input_encodings TEXT, - show_in_default_list INT, - suggest_url TEXT, - prepopulate_id INT, - created_by_policy INT, - instant_url TEXT, - last_modified INT, - sync_guid TEXT, - alternate_urls TEXT -); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE TABLE web_intents ( service_url LONGVARCHAR, action VARCHAR, type VARCHAR, title LONGVARCHAR, disposition VARCHAR, scheme VARCHAR, UNIQUE (service_url, action, scheme, type)); -CREATE TABLE web_intents_defaults ( action VARCHAR, type VARCHAR, url_pattern LONGVARCHAR, user_date INTEGER, suppression INTEGER, service_url LONGVARCHAR, scheme VARCHAR, UNIQUE (action, scheme, type, url_pattern)); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX web_intents_index ON web_intents (action); -CREATE INDEX web_intents_default_index ON web_intents_defaults (action); -COMMIT;
diff --git a/components/test/data/web_database/version_48.sql b/components/test/data/web_database/version_48.sql deleted file mode 100644 index 53a9ed7..0000000 --- a/components/test/data/web_database/version_48.sql +++ /dev/null
@@ -1,28 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','48'); -INSERT INTO "meta" VALUES('last_compatible_version','48'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','48'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE TABLE web_intents ( service_url LONGVARCHAR, action VARCHAR, type VARCHAR, title LONGVARCHAR, disposition VARCHAR, scheme VARCHAR, UNIQUE (service_url, action, scheme, type)); -CREATE TABLE web_intents_defaults ( action VARCHAR, type VARCHAR, url_pattern LONGVARCHAR, user_date INTEGER, suppression INTEGER, service_url LONGVARCHAR, scheme VARCHAR, UNIQUE (action, scheme, type, url_pattern)); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX web_intents_index ON web_intents (action); -CREATE INDEX web_intents_default_index ON web_intents_defaults (action); -COMMIT;
diff --git a/components/test/data/web_database/version_49.sql b/components/test/data/web_database/version_49.sql deleted file mode 100644 index 02a4fd9..0000000 --- a/components/test/data/web_database/version_49.sql +++ /dev/null
@@ -1,31 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); -INSERT INTO "meta" VALUES('version','49'); -INSERT INTO "meta" VALUES('last_compatible_version','48'); -INSERT INTO "meta" VALUES('Builtin Keyword Version','54'); -INSERT INTO "meta" VALUES('Default Search Provider ID','2'); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR); -CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,search_terms_replacement_key VARCHAR); -INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}ie={inputEncoding}',1,'',0,0,'UTF-8',1,'{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client=chrome&q={searchTerms}&{google:cursorPosition}sugkey={google:suggestAPIKeyParameter}',1,0,'{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:instantEnabledParameter}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}',0,'711AEC98-A563-FD8B-87D5-427C60828A43','["{google:baseURL}#q={searchTerms}","{google:baseURL}search#q={searchTerms}","{google:baseURL}webhp#q={searchTerms}"]','espv'); -INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,'',0,0,'UTF-8',1,'http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,'',0,'7A35F8C9-ADD7-2C08-475E-B51151C79514','[]',''); -INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,'',0,0,'UTF-8',1,'http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,'',0,'94DA8067-BC2D-9033-0EDD-2F667874C223','[]',''); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height)); -CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL); -CREATE TABLE web_intents ( service_url LONGVARCHAR, action VARCHAR, type VARCHAR, title LONGVARCHAR, disposition VARCHAR, scheme VARCHAR, UNIQUE (service_url, action, scheme, type)); -CREATE TABLE web_intents_defaults ( action VARCHAR, type VARCHAR, url_pattern LONGVARCHAR, user_date INTEGER, suppression INTEGER, service_url LONGVARCHAR, scheme VARCHAR, UNIQUE (action, scheme, type, url_pattern)); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id); -CREATE INDEX web_apps_url_index ON web_apps (url); -CREATE INDEX web_intents_index ON web_intents (action); -CREATE INDEX web_intents_default_index ON web_intents_defaults (action); -COMMIT;
diff --git a/components/test/data/web_database/version_62.sql b/components/test/data/web_database/version_62.sql new file mode 100644 index 0000000..e23ab8b --- /dev/null +++ b/components/test/data/web_database/version_62.sql
@@ -0,0 +1,26 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); +INSERT INTO "meta" VALUES('version','60'); +INSERT INTO "meta" VALUES('last_compatible_version','59'); +INSERT INTO "meta" VALUES('Builtin Keyword Version','79'); +CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); +CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, date_created INTEGER DEFAULT 0, date_last_used INTEGER DEFAULT 0, count INTEGER DEFAULT 1, PRIMARY KEY (name, value)); +CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT ''); +CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR); +CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR); +CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); +CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profiles_trash ( guid VARCHAR); +CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,type VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0); +CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR); +CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR); +CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,search_terms_replacement_key VARCHAR,image_url VARCHAR,search_url_post_params VARCHAR,suggest_url_post_params VARCHAR,instant_url_post_params VARCHAR,image_url_post_params VARCHAR,new_tab_url VARCHAR); +INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:bookmarkBarPinned}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}{google:omniboxStartMarginParameter}{google:contextualSearchVersion}ie={inputEncoding}',1,'',0,0,'UTF-8',1,'{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client={google:suggestClient}&gs_ri={google:suggestRid}&xssi=t&q={searchTerms}&{google:inputType}{google:cursorPosition}{google:currentPageUrl}{google:pageClassification}{google:searchVersion}{google:sessionToken}{google:prefetchQuery}sugkey={google:suggestAPIKeyParameter}',1,0,'{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:forceInstantResults}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}',0,'EAB7604D-85AD-455A-AA7F-3A1B68CDDA0C','["{google:baseURL}#q={searchTerms}","{google:baseURL}search#q={searchTerms}","{google:baseURL}webhp#q={searchTerms}","{google:baseURL}s?q={searchTerms}"]','espv','{google:baseURL}searchbyimage/upload','','','','encoded_image={google:imageThumbnail},image_url={google:imageURL},sbisrc={google:imageSearchSource},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight}','{google:baseURL}_/chrome/newtab?{google:RLZ}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}ie={inputEncoding}'); +INSERT INTO "keywords" VALUES(3,'Bing','bing.com','https://www.bing.com/s/a/bing_p.ico','https://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,'',0,0,'UTF-8',1,'http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,'',0,'865547E0-515C-482B-A202-F79CA3743BF8','[]','','','','','','','https://www.bing.com/chrome/newtab?setmkt=en-US'); +INSERT INTO "keywords" VALUES(4,'Yahoo!','yahoo.com','https://search.yahoo.com/favicon.ico','https://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,'',0,0,'UTF-8',1,'https://search.yahoo.com/sugg/chrome?output=fxjson&appid=crmas&command={searchTerms}',2,0,'',0,'9C8E4670-5993-46EF-8BEF-8012124C299D','[]','','','','','','',''); +INSERT INTO "keywords" VALUES(5,'AOL','aol.com','http://search.aol.com/favicon.ico','http://search.aol.com/aol/search?q={searchTerms}',1,'',0,0,'UTF-8',1,'http://autocomplete.search.aol.com/autocomplete/get?output=json&it=&q={searchTerms}',35,0,'',0,'946DE8D0-0602-4C1A-BE0C-E44EDE8DCCA3','[]','','','','','','',''); +INSERT INTO "keywords" VALUES(6,'Ask','ask.com','http://sp.ask.com/sh/i/a16/favicon/favicon.ico','http://www.ask.com/web?q={searchTerms}',1,'',0,0,'UTF-8',1,'http://ss.ask.com/query?q={searchTerms}&li=ff',4,0,'',0,'F5C5564A-42A4-432B-A59E-2306689DF48B','[]','','','','','','',''); +CREATE INDEX autofill_name ON autofill (name); +CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); +COMMIT;
diff --git a/components/translate/core/browser/translate_infobar_delegate.cc b/components/translate/core/browser/translate_infobar_delegate.cc index 56bf4de..9552463 100644 --- a/components/translate/core/browser/translate_infobar_delegate.cc +++ b/components/translate/core/browser/translate_infobar_delegate.cc
@@ -262,7 +262,13 @@ } bool TranslateInfoBarDelegate::ShouldShowAlwaysTranslateShortcut() { +#if defined(OS_IOS) + // On mobile, the option to always translate is shown after the translation. + DCHECK_EQ(translate::TRANSLATE_STEP_AFTER_TRANSLATE, step_); +#else + // On desktop, the option to always translate is shown before the translation. DCHECK_EQ(translate::TRANSLATE_STEP_BEFORE_TRANSLATE, step_); +#endif return !is_off_the_record_ && (prefs_->GetTranslationAcceptedCount(original_language_code()) >= kAlwaysTranslateMinCount);
diff --git a/components/update_client/component_patcher.cc b/components/update_client/component_patcher.cc index 3077bc4f..29ce774 100644 --- a/components/update_client/component_patcher.cc +++ b/components/update_client/component_patcher.cc
@@ -30,8 +30,8 @@ if (!base::PathExists(commands)) return NULL; - JSONFileValueSerializer serializer(commands); - scoped_ptr<base::Value> root(serializer.Deserialize(NULL, NULL)); + JSONFileValueDeserializer deserializer(commands); + scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, NULL)); return (root.get() && root->IsType(base::Value::TYPE_LIST)) ? static_cast<base::ListValue*>(root.release())
diff --git a/components/update_client/component_unpacker.cc b/components/update_client/component_unpacker.cc index eb1b2d89..efde910 100644 --- a/components/update_client/component_unpacker.cc +++ b/components/update_client/component_unpacker.cc
@@ -125,9 +125,9 @@ unpack_path.Append(FILE_PATH_LITERAL("manifest.json")); if (!base::PathExists(manifest)) return scoped_ptr<base::DictionaryValue>(); - JSONFileValueSerializer serializer(manifest); + JSONFileValueDeserializer deserializer(manifest); std::string error; - scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error)); + scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, &error)); if (!root.get()) return scoped_ptr<base::DictionaryValue>(); if (!root->IsType(base::Value::TYPE_DICTIONARY))
diff --git a/content/public/android/java/res/drawable-xxhdpi/ic_warning.png b/components/web_contents_delegate_android/android/java/res/drawable-xxhdpi/ic_warning.png similarity index 100% rename from content/public/android/java/res/drawable-xxhdpi/ic_warning.png rename to components/web_contents_delegate_android/android/java/res/drawable-xxhdpi/ic_warning.png Binary files differ
diff --git a/content/public/android/java/res/drawable-xxxhdpi/ic_warning.png b/components/web_contents_delegate_android/android/java/res/drawable-xxxhdpi/ic_warning.png similarity index 100% rename from content/public/android/java/res/drawable-xxxhdpi/ic_warning.png rename to components/web_contents_delegate_android/android/java/res/drawable-xxxhdpi/ic_warning.png Binary files differ
diff --git a/components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java b/components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java index 5ada34bb..1c774f0d 100644 --- a/components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java +++ b/components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java
@@ -8,6 +8,7 @@ import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; +import org.chromium.content_public.browser.InvalidateTypes; import org.chromium.content_public.browser.WebContents; /** @@ -25,16 +26,8 @@ // Equivalent of WebCore::WebConsoleMessage::LevelError. public static final int LOG_LEVEL_ERROR = 3; - // Flags passed to the WebContentsDelegateAndroid.navigationStateChanged to tell it - // what has changed. Should match the values in invalidate_type.h. - // Equivalent of InvalidateTypes::INVALIDATE_TYPE_URL. - public static final int INVALIDATE_TYPE_URL = 1 << 0; - // Equivalent of InvalidateTypes::INVALIDATE_TYPE_TAB. - public static final int INVALIDATE_TYPE_TAB = 1 << 1; - // Equivalent of InvalidateTypes::INVALIDATE_TYPE_LOAD. - public static final int INVALIDATE_TYPE_LOAD = 1 << 2; - // Equivalent of InvalidateTypes::INVALIDATE_TYPE_TITLE. - public static final int INVALIDATE_TYPE_TITLE = 1 << 3; + // TODO(mnaganov): Remove after getting rid of downstream usages. + public static final int INVALIDATE_TYPE_TAB = InvalidateTypes.TAB; // The most recent load progress callback received from WebContents, as a percentage. // Initialize to 100 to indicate that we're not in a loading state.
diff --git a/components/web_modal/native_web_contents_modal_dialog.h b/components/web_modal/native_web_contents_modal_dialog.h index 4bb956a..ef459b1e 100644 --- a/components/web_modal/native_web_contents_modal_dialog.h +++ b/components/web_modal/native_web_contents_modal_dialog.h
@@ -11,21 +11,8 @@ // TODO(gbillock): rename this file -#if defined(OS_MACOSX) -// Use a void* since none of the gfx::Native* types are suitable for -// representing the web contents modal dialog under Cocoa. -typedef void* NativeWebContentsModalDialog; -#else -typedef gfx::NativeView NativeWebContentsModalDialog; -#endif - -#if defined(OS_MACOSX) -// Use a void* since none of the gfx::Native* types are suitable for -// representing a popup window under Cocoa. -typedef void* NativePopup; -#else -typedef gfx::NativeView NativePopup; -#endif +using NativeWebContentsModalDialog = gfx::NativeWindow; +using NativePopup = gfx::NativeWindow; } // namespace web_modal
diff --git a/components/webdata/common/web_database.cc b/components/webdata/common/web_database.cc index 018663da..675f7c5 100644 --- a/components/webdata/common/web_database.cc +++ b/components/webdata/common/web_database.cc
@@ -14,7 +14,9 @@ // corresponding changes must happen in the unit tests, and new migration test // added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|. // static -const int WebDatabase::kCurrentVersionNumber = 62; +const int WebDatabase::kCurrentVersionNumber = 63; + +const int WebDatabase::kDeprecatedVersionNumber = 51; namespace { @@ -87,7 +89,13 @@ if (!db_.Open(db_name)) return sql::INIT_FAILURE; - // Initialize various tables + // Clobber really old databases. + static_assert(kDeprecatedVersionNumber < kCurrentVersionNumber, + "Deprecation version must be less than current"); + sql::MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersionNumber); + + // Scope initialization in a transaction so we can't be partially + // initialized. sql::Transaction transaction(&db_); if (!transaction.Begin()) return sql::INIT_FAILURE; @@ -135,22 +143,7 @@ if (current_version > meta_table_.GetVersionNumber()) ChangeVersion(&meta_table_, current_version, false); - if (current_version < 20) { - // Versions 1 - 19 are unhandled. Version numbers greater than - // kCurrentVersionNumber should have already been weeded out by the caller. - // - // When the version is too old, we return failure error code. The schema - // is too out of date to migrate. - // - // There should not be a released product that makes a database too old to - // migrate. If we do encounter such a legacy database, we will need a - // better solution to handle it (i.e., pop up a dialog to tell the user, - // erase all their prefs and start over, etc.). - LOG(WARNING) << "Web database version " << current_version - << " is too old to handle."; - NOTREACHED(); - return sql::INIT_FAILURE; - } + DCHECK_GT(current_version, kDeprecatedVersionNumber); for (int next_version = current_version + 1; next_version <= kCurrentVersionNumber;
diff --git a/components/webdata/common/web_database.h b/components/webdata/common/web_database.h index 22730fe..c6d0c1d5 100644 --- a/components/webdata/common/web_database.h +++ b/components/webdata/common/web_database.h
@@ -27,6 +27,8 @@ }; // Exposed publicly so the keyword table can access it. static const int kCurrentVersionNumber; + // The newest version of the database Chrome will NOT try to migrate. + static const int kDeprecatedVersionNumber; WebDatabase(); virtual ~WebDatabase();
diff --git a/components/webdata/common/web_database_migration_unittest.cc b/components/webdata/common/web_database_migration_unittest.cc index fbba5cd..765883b 100644 --- a/components/webdata/common/web_database_migration_unittest.cc +++ b/components/webdata/common/web_database_migration_unittest.cc
@@ -38,122 +38,6 @@ namespace { -void AutofillProfile31FromStatement(const sql::Statement& s, - AutofillProfile* profile, - base::string16* label, - int* unique_id, - int64* date_modified) { - DCHECK(profile); - DCHECK(label); - DCHECK(unique_id); - DCHECK(date_modified); - *label = s.ColumnString16(0); - *unique_id = s.ColumnInt(1); - profile->SetRawInfo(autofill::NAME_FIRST, s.ColumnString16(2)); - profile->SetRawInfo(autofill::NAME_MIDDLE, s.ColumnString16(3)); - profile->SetRawInfo(autofill::NAME_LAST, s.ColumnString16(4)); - profile->SetRawInfo(autofill::EMAIL_ADDRESS, s.ColumnString16(5)); - profile->SetRawInfo(autofill::COMPANY_NAME, s.ColumnString16(6)); - profile->SetRawInfo(autofill::ADDRESS_HOME_LINE1, s.ColumnString16(7)); - profile->SetRawInfo(autofill::ADDRESS_HOME_LINE2, s.ColumnString16(8)); - profile->SetRawInfo(autofill::ADDRESS_HOME_CITY, s.ColumnString16(9)); - profile->SetRawInfo(autofill::ADDRESS_HOME_STATE, s.ColumnString16(10)); - profile->SetRawInfo(autofill::ADDRESS_HOME_ZIP, s.ColumnString16(11)); - profile->SetInfo( - autofill::AutofillType(autofill::ADDRESS_HOME_COUNTRY), - s.ColumnString16(12), "en-US"); - profile->SetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER, s.ColumnString16(13)); - *date_modified = s.ColumnInt64(15); - profile->set_guid(s.ColumnString(16)); - EXPECT_TRUE(base::IsValidGUID(profile->guid())); -} - -void AutofillProfile33FromStatement(const sql::Statement& s, - AutofillProfile* profile, - int64* date_modified) { - DCHECK(profile); - DCHECK(date_modified); - profile->set_guid(s.ColumnString(0)); - EXPECT_TRUE(base::IsValidGUID(profile->guid())); - profile->SetRawInfo(autofill::COMPANY_NAME, s.ColumnString16(1)); - profile->SetRawInfo(autofill::ADDRESS_HOME_STREET_ADDRESS, - s.ColumnString16(2)); - profile->SetRawInfo(autofill::ADDRESS_HOME_CITY, s.ColumnString16(3)); - profile->SetRawInfo(autofill::ADDRESS_HOME_STATE, s.ColumnString16(4)); - profile->SetRawInfo(autofill::ADDRESS_HOME_ZIP, s.ColumnString16(5)); - profile->SetInfo( - autofill::AutofillType(autofill::ADDRESS_HOME_COUNTRY), - s.ColumnString16(6), "en-US"); - *date_modified = s.ColumnInt64(7); -} - -void CreditCard31FromStatement(const sql::Statement& s, - CreditCard* credit_card, - base::string16* label, - int* unique_id, - std::string* encrypted_number, - int64* date_modified) { - DCHECK(credit_card); - DCHECK(label); - DCHECK(unique_id); - DCHECK(encrypted_number); - DCHECK(date_modified); - *label = s.ColumnString16(0); - *unique_id = s.ColumnInt(1); - credit_card->SetRawInfo(autofill::CREDIT_CARD_NAME, s.ColumnString16(2)); - credit_card->SetRawInfo(autofill::CREDIT_CARD_TYPE, s.ColumnString16(3)); - credit_card->SetRawInfo(autofill::CREDIT_CARD_EXP_MONTH, s.ColumnString16(5)); - credit_card->SetRawInfo( - autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR, s.ColumnString16(6)); - int encrypted_number_len = s.ColumnByteLength(10); - if (encrypted_number_len) { - encrypted_number->resize(encrypted_number_len); - memcpy(&(*encrypted_number)[0], s.ColumnBlob(10), encrypted_number_len); - } - *date_modified = s.ColumnInt64(12); - credit_card->set_guid(s.ColumnString(13)); - EXPECT_TRUE(base::IsValidGUID(credit_card->guid())); -} - -void CreditCard32FromStatement(const sql::Statement& s, - CreditCard* credit_card, - std::string* encrypted_number, - int64* date_modified) { - DCHECK(credit_card); - DCHECK(encrypted_number); - DCHECK(date_modified); - credit_card->set_guid(s.ColumnString(0)); - EXPECT_TRUE(base::IsValidGUID(credit_card->guid())); - credit_card->SetRawInfo(autofill::CREDIT_CARD_NAME, s.ColumnString16(1)); - credit_card->SetRawInfo(autofill::CREDIT_CARD_EXP_MONTH, s.ColumnString16(2)); - credit_card->SetRawInfo( - autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR, s.ColumnString16(3)); - int encrypted_number_len = s.ColumnByteLength(4); - if (encrypted_number_len) { - encrypted_number->resize(encrypted_number_len); - memcpy(&(*encrypted_number)[0], s.ColumnBlob(4), encrypted_number_len); - } - *date_modified = s.ColumnInt64(5); -} - -void CheckHasBackupData(sql::MetaTable* meta_table) { - std::string value; - EXPECT_TRUE(meta_table->GetValue( - "Default Search Provider ID Backup", &value)); - EXPECT_TRUE(meta_table->GetValue( - "Default Search Provider ID Backup Signature", &value)); -} - -void CheckNoBackupData(const sql::Connection& connection, - sql::MetaTable* meta_table) { - std::string value; - EXPECT_FALSE(meta_table->GetValue( - "Default Search Provider ID Backup", &value)); - EXPECT_FALSE(meta_table->GetValue( - "Default Search Provider ID Backup Signature", &value)); - EXPECT_FALSE(connection.DoesTableExist("keywords_backup")); -} - std::string RemoveQuotes(const std::string& has_quotes) { std::string no_quotes; // SQLite quotes: http://www.sqlite.org/lang_keywords.html @@ -248,7 +132,7 @@ DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest); }; -const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 62; +const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 63; void WebDatabaseMigrationTest::LoadDatabase( const base::FilePath::StringType& file) { @@ -267,15 +151,23 @@ sql::Connection connection; ASSERT_TRUE(connection.Open(GetDatabasePath())); const std::string& expected_schema = RemoveQuotes(connection.GetSchema()); - static const int kFirstVersion = 53; - for (int i = kFirstVersion; i < kCurrentTestedVersionNumber; ++i) { + for (int i = WebDatabase::kDeprecatedVersionNumber + 1; + i < kCurrentTestedVersionNumber; ++i) { + // We don't test version 52 because there's a slight discrepancy in the + // initialization code and the migration code (relating to schema + // formatting). Fixing the bug is possible, but would require updating every + // version_nn.sql file. + if (i == 52) + continue; + connection.Raze(); const base::FilePath& file_name = base::FilePath::FromUTF8Unsafe( "version_" + base::IntToString(i) + ".sql"); ASSERT_NO_FATAL_FAILURE(LoadDatabase(file_name.value())) << "Failed to load " << file_name.MaybeAsASCII(); DoMigration(); - EXPECT_EQ(expected_schema, RemoveQuotes(connection.GetSchema())); + EXPECT_EQ(expected_schema, RemoveQuotes(connection.GetSchema())) + << "For version " << i; } } @@ -314,1851 +206,8 @@ } } -// Tests that absent Autofill tables do not create any problems when migrating -// from a DB written by the earliest publicly released version of Chrome. -TEST_F(WebDatabaseMigrationTest, MigrateVersion20ToCurrent) { - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_20.sql"))); - - // Verify pre-conditions. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - EXPECT_FALSE(connection.DoesTableExist("autofill")); - EXPECT_FALSE(connection.DoesTableExist("autofill_profiles")); - EXPECT_FALSE(connection.DoesTableExist("credit_cards")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // Mostly this test just verifies that no SQL errors occur during migration; - // but might as well verify that the tables were created as well. - EXPECT_TRUE(connection.DoesTableExist("autofill")); - EXPECT_TRUE(connection.DoesTableExist("autofill_profiles")); - EXPECT_TRUE(connection.DoesTableExist("credit_cards")); - } -} - -// Tests that rows with empty values get removed from the autofill tables. -TEST_F(WebDatabaseMigrationTest, MigrateVersion21ToCurrent) { - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_21.sql"))); - - // Verify pre-conditions. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Both empty and non-empty values are allowed in a version 21 database. - sql::Statement s_autofill(connection.GetUniqueStatement( - "SELECT name, value, value_lower, pair_id, count FROM autofill")); - sql::Statement s_dates(connection.GetUniqueStatement( - "SELECT pair_id, date_created FROM autofill_dates")); - - // An entry with a non-empty value. - ASSERT_TRUE(s_autofill.Step()); - EXPECT_EQ(ASCIIToUTF16("Name"), s_autofill.ColumnString16(0)); - EXPECT_EQ(ASCIIToUTF16("John Doe"), s_autofill.ColumnString16(1)); - EXPECT_EQ(ASCIIToUTF16("john doe"), s_autofill.ColumnString16(2)); - EXPECT_EQ(10, s_autofill.ColumnInt(3)); - EXPECT_EQ(1, s_autofill.ColumnInt(4)); - ASSERT_TRUE(s_dates.Step()); - EXPECT_EQ(10, s_dates.ColumnInt(0)); - EXPECT_EQ(1384299100, s_dates.ColumnInt64(1)); - - // An entry with an empty value. - ASSERT_TRUE(s_autofill.Step()); - EXPECT_EQ(ASCIIToUTF16("Name"), s_autofill.ColumnString16(0)); - EXPECT_EQ(base::string16(), s_autofill.ColumnString16(1)); - EXPECT_EQ(base::string16(), s_autofill.ColumnString16(2)); - EXPECT_EQ(11, s_autofill.ColumnInt(3)); - EXPECT_EQ(1, s_autofill.ColumnInt(4)); - ASSERT_TRUE(s_dates.Step()); - EXPECT_EQ(11, s_dates.ColumnInt(0)); - EXPECT_EQ(1384299200, s_dates.ColumnInt64(1)); - - // Another entry with a non-empty value. - ASSERT_TRUE(s_autofill.Step()); - EXPECT_EQ(ASCIIToUTF16("Email"), s_autofill.ColumnString16(0)); - EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s_autofill.ColumnString16(1)); - EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s_autofill.ColumnString16(2)); - EXPECT_EQ(20, s_autofill.ColumnInt(3)); - EXPECT_EQ(3, s_autofill.ColumnInt(4)); - ASSERT_TRUE(s_dates.Step()); - EXPECT_EQ(20, s_dates.ColumnInt(0)); - EXPECT_EQ(1384299300, s_dates.ColumnInt64(1)); - ASSERT_TRUE(s_dates.Step()); - EXPECT_EQ(20, s_dates.ColumnInt(0)); - EXPECT_EQ(1384299301, s_dates.ColumnInt64(1)); - - // Another entry with an empty value. - ASSERT_TRUE(s_autofill.Step()); - EXPECT_EQ(ASCIIToUTF16("Email"), s_autofill.ColumnString16(0)); - EXPECT_EQ(base::string16(), s_autofill.ColumnString16(1)); - EXPECT_EQ(base::string16(), s_autofill.ColumnString16(2)); - EXPECT_EQ(21, s_autofill.ColumnInt(3)); - EXPECT_EQ(4, s_autofill.ColumnInt(4)); - ASSERT_TRUE(s_dates.Step()); - EXPECT_EQ(21, s_dates.ColumnInt(0)); - EXPECT_EQ(1384299401, s_dates.ColumnInt64(1)); - ASSERT_TRUE(s_dates.Step()); - EXPECT_EQ(21, s_dates.ColumnInt(0)); - EXPECT_EQ(1384299400, s_dates.ColumnInt64(1)); - ASSERT_TRUE(s_dates.Step()); - EXPECT_EQ(21, s_dates.ColumnInt(0)); - EXPECT_EQ(1384299403, s_dates.ColumnInt64(1)); - ASSERT_TRUE(s_dates.Step()); - EXPECT_EQ(21, s_dates.ColumnInt(0)); - EXPECT_EQ(1384299402, s_dates.ColumnInt64(1)); - - // No more entries expected. - ASSERT_FALSE(s_autofill.Step()); - ASSERT_FALSE(s_dates.Step()); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // Entries with empty values should have been dropped. The remaining - // entries should have been preserved. - sql::Statement s( - connection.GetUniqueStatement( - "SELECT name, value, value_lower, date_created, date_last_used," - " count " - "FROM autofill " - "ORDER BY name, value ASC")); - - // "jane@example.com" - ASSERT_TRUE(s.Step()); - EXPECT_EQ(ASCIIToUTF16("Email"), s.ColumnString16(0)); - EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s.ColumnString16(1)); - EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s.ColumnString16(2)); - EXPECT_EQ(1384299300, s.ColumnInt64(3)); - EXPECT_EQ(1384299301, s.ColumnInt64(4)); - EXPECT_EQ(3, s.ColumnInt(5)); - - // "John Doe" - ASSERT_TRUE(s.Step()); - EXPECT_EQ(ASCIIToUTF16("Name"), s.ColumnString16(0)); - EXPECT_EQ(ASCIIToUTF16("John Doe"), s.ColumnString16(1)); - EXPECT_EQ(ASCIIToUTF16("john doe"), s.ColumnString16(2)); - EXPECT_EQ(1384299100, s.ColumnInt64(3)); - EXPECT_EQ(1384299100, s.ColumnInt64(4)); - EXPECT_EQ(1, s.ColumnInt(5)); - - // No more entries expected. - ASSERT_FALSE(s.Step()); - } -} - -// Tests that the |credit_card| table gets added to the schema for a version 22 -// database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion22ToCurrent) { - // This schema is taken from a build prior to the addition of the - // |credit_card| table. Version 22 of the schema. Contrast this with the - // corrupt version below. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_22.sql"))); - - // Verify pre-conditions. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // No |credit_card| table prior to version 23. - ASSERT_FALSE(connection.DoesColumnExist("credit_cards", "guid")); - ASSERT_FALSE( - connection.DoesColumnExist("credit_cards", "card_number_encrypted")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // |credit_card| table now exists. - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid")); - EXPECT_TRUE( - connection.DoesColumnExist("credit_cards", "card_number_encrypted")); - } -} - -// Tests that the |credit_card| table gets added to the schema for a corrupt -// version 22 database. The corruption is that the |credit_cards| table exists -// but the schema version number was not set correctly to 23 or later. This -// test exercises code introduced to fix bug http://crbug.com/50699 that -// resulted from the corruption. -TEST_F(WebDatabaseMigrationTest, MigrateVersion22CorruptedToCurrent) { - // This schema is taken from a build after the addition of the |credit_card| - // table. Due to a bug in the migration logic the version is set incorrectly - // to 22 (it should have been updated to 23 at least). - ASSERT_NO_FATAL_FAILURE( - LoadDatabase(FILE_PATH_LITERAL("version_22_corrupt.sql"))); - - // Verify pre-conditions. These are expectations for corrupt version 22 of - // the database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Columns existing and not existing before current version. - ASSERT_TRUE(connection.DoesColumnExist("credit_cards", "unique_id")); - ASSERT_TRUE( - connection.DoesColumnExist("credit_cards", "card_number_encrypted")); - ASSERT_TRUE(connection.DoesColumnExist("keywords", "id")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - - // Columns existing and not existing before version 25. - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "unique_id")); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid")); - EXPECT_TRUE( - connection.DoesColumnExist("credit_cards", "card_number_encrypted")); - EXPECT_TRUE(connection.DoesColumnExist("keywords", "id")); - } -} - -// Tests that the |keywords| |created_by_policy| column gets added to the schema -// for a version 25 database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion25ToCurrent) { - // This schema is taken from a build prior to the addition of the |keywords| - // |created_by_policy| column. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_25.sql"))); - - // Verify pre-conditions. These are expectations for version 25 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // |keywords| |created_by_policy| column should have been added. - EXPECT_TRUE(connection.DoesColumnExist("keywords", "id")); - EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy")); - } -} - -// Tests that the credit_cards.billing_address column is changed from a string -// to an int whilst preserving the associated billing address. This version of -// the test makes sure a stored label is converted to an ID. -TEST_F(WebDatabaseMigrationTest, MigrateVersion26ToCurrentStringLabels) { - // This schema is taken from a build prior to the change of column type for - // credit_cards.billing_address from string to int. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_26.sql"))); - - // Verify pre-conditions. These are expectations for version 26 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Columns existing and not existing before current version. - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address")); - - std::string stmt = "INSERT INTO autofill_profiles" - "(label, unique_id, first_name, middle_name, last_name, email," - " company_name, address_line_1, address_line_2, city, state, zipcode," - " country, phone, fax)" - "VALUES ('Home',1,'','','','','','','','','','','','','')"; - sql::Statement s(connection.GetUniqueStatement(stmt.c_str())); - ASSERT_TRUE(s.Run()); - - // Insert a CC linked to an existing address. - std::string stmt2 = "INSERT INTO credit_cards" - "(label, unique_id, name_on_card, type, card_number," - " expiration_month, expiration_year, verification_code, billing_address," - " shipping_address, card_number_encrypted, verification_code_encrypted)" - "VALUES ('label',2,'Jack','Visa','1234',2,2012,'','Home','','','')"; - sql::Statement s2(connection.GetUniqueStatement(stmt2.c_str())); - ASSERT_TRUE(s2.Run()); - - // |billing_address| is a string. - std::string stmt3 = "SELECT billing_address FROM credit_cards"; - sql::Statement s3(connection.GetUniqueStatement(stmt3.c_str())); - ASSERT_TRUE(s3.Step()); - EXPECT_EQ(s3.ColumnType(0), sql::COLUMN_TYPE_TEXT); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address")); - - // Verify the credit card data is converted. - sql::Statement s(connection.GetUniqueStatement( - "SELECT guid, name_on_card, expiration_month, expiration_year, " - "card_number_encrypted, date_modified " - "FROM credit_cards")); - ASSERT_TRUE(s.Step()); - EXPECT_EQ("Jack", s.ColumnString(1)); - EXPECT_EQ(2, s.ColumnInt(2)); - EXPECT_EQ(2012, s.ColumnInt(3)); - // Column 5 is encrypted number blob. - // Column 6 is date_modified. - } -} - -// Tests that the credit_cards.billing_address column is changed from a string -// to an int whilst preserving the associated billing address. This version of -// the test makes sure a stored string ID is converted to an integer ID. -TEST_F(WebDatabaseMigrationTest, MigrateVersion26ToCurrentStringIDs) { - // This schema is taken from a build prior to the change of column type for - // credit_cards.billing_address from string to int. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_26.sql"))); - - // Verify pre-conditions. These are expectations for version 26 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address")); - - std::string stmt = "INSERT INTO autofill_profiles" - "(label, unique_id, first_name, middle_name, last_name, email," - " company_name, address_line_1, address_line_2, city, state, zipcode," - " country, phone, fax)" - "VALUES ('Home',1,'','','','','','','','','','','','','')"; - sql::Statement s(connection.GetUniqueStatement(stmt.c_str())); - ASSERT_TRUE(s.Run()); - - // Insert a CC linked to an existing address. - std::string stmt2 = "INSERT INTO credit_cards" - "(label, unique_id, name_on_card, type, card_number," - " expiration_month, expiration_year, verification_code, billing_address," - " shipping_address, card_number_encrypted, verification_code_encrypted)" - "VALUES ('label',2,'Jack','Visa','1234',2,2012,'','1','','','')"; - sql::Statement s2(connection.GetUniqueStatement(stmt2.c_str())); - ASSERT_TRUE(s2.Run()); - - // |billing_address| is a string. - std::string stmt3 = "SELECT billing_address FROM credit_cards"; - sql::Statement s3(connection.GetUniqueStatement(stmt3.c_str())); - ASSERT_TRUE(s3.Step()); - EXPECT_EQ(s3.ColumnType(0), sql::COLUMN_TYPE_TEXT); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // |keywords| |created_by_policy| column should have been added. - EXPECT_TRUE(connection.DoesColumnExist("keywords", "id")); - EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy")); - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address")); - - // Verify the credit card data is converted. - sql::Statement s(connection.GetUniqueStatement( - "SELECT guid, name_on_card, expiration_month, expiration_year, " - "card_number_encrypted, date_modified " - "FROM credit_cards")); - ASSERT_TRUE(s.Step()); - EXPECT_EQ("Jack", s.ColumnString(1)); - EXPECT_EQ(2, s.ColumnInt(2)); - EXPECT_EQ(2012, s.ColumnInt(3)); - // Column 5 is encrypted credit card number blo b. - // Column 6 is date_modified. - } -} - -// Makes sure instant_url is added correctly to keywords. -TEST_F(WebDatabaseMigrationTest, MigrateVersion27ToCurrent) { - // Initialize the database. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_27.sql"))); - - // Verify pre-conditions. These are expectations for version 27 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - ASSERT_FALSE(connection.DoesColumnExist("keywords", "instant_url")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // Make sure supports_instant (added in Version 28) was ultimately dropped - // again and instant_url was added. - EXPECT_FALSE(connection.DoesColumnExist("keywords", "supports_instant")); - EXPECT_TRUE(connection.DoesColumnExist("keywords", "instant_url")); - - // Check that instant_url is empty. - std::string stmt = "SELECT instant_url FROM keywords"; - sql::Statement s(connection.GetUniqueStatement(stmt.c_str())); - ASSERT_TRUE(s.Step()); - EXPECT_EQ(std::string(), s.ColumnString(0)); - - // Verify the data made it over. - stmt = "SELECT " + KeywordTable::GetKeywordColumns() + " FROM keywords"; - sql::Statement s2(connection.GetUniqueStatement(stmt.c_str())); - ASSERT_TRUE(s2.Step()); - EXPECT_EQ(2, s2.ColumnInt(0)); - EXPECT_EQ("Google", s2.ColumnString(1)); - EXPECT_EQ("google.com", s2.ColumnString(2)); - EXPECT_EQ("http://www.google.com/favicon.ico", s2.ColumnString(3)); - EXPECT_EQ("{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}"\ - "{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}"\ - "&q={searchTerms}", - s2.ColumnString(4)); - EXPECT_TRUE(s2.ColumnBool(5)); - EXPECT_EQ(std::string(), s2.ColumnString(6)); - EXPECT_EQ(0, s2.ColumnInt(7)); - EXPECT_EQ(0, s2.ColumnInt(8)); - EXPECT_EQ(std::string("UTF-8"), s2.ColumnString(9)); - EXPECT_TRUE(s2.ColumnBool(10)); - EXPECT_EQ(std::string("{google:baseSuggestURL}search?client=chrome&hl=" - "{language}&q={searchTerms}"), s2.ColumnString(11)); - EXPECT_EQ(1, s2.ColumnInt(12)); - EXPECT_FALSE(s2.ColumnBool(13)); - EXPECT_EQ(std::string(), s2.ColumnString(14)); - EXPECT_EQ(0, s2.ColumnInt(15)); - EXPECT_EQ(std::string(), s2.ColumnString(16)); - } -} - -// Makes sure date_modified is added correctly to autofill_profiles and -// credit_cards. -TEST_F(WebDatabaseMigrationTest, MigrateVersion29ToCurrent) { - // Initialize the database. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_29.sql"))); - - // Verify pre-conditions. These are expectations for version 29 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", - "date_modified")); - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", - "date_modified")); - } - - Time pre_creation_time = Time::Now(); - DoMigration(); - Time post_creation_time = Time::Now(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // Check that the columns were created. - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", - "date_modified")); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", - "date_modified")); - - sql::Statement s_profiles(connection.GetUniqueStatement( - "SELECT date_modified FROM autofill_profiles ")); - ASSERT_TRUE(s_profiles.is_valid()); - while (s_profiles.Step()) { - EXPECT_GE(s_profiles.ColumnInt64(0), - pre_creation_time.ToTimeT()); - EXPECT_LE(s_profiles.ColumnInt64(0), - post_creation_time.ToTimeT()); - } - EXPECT_TRUE(s_profiles.Succeeded()); - - sql::Statement s_credit_cards(connection.GetUniqueStatement( - "SELECT date_modified FROM credit_cards ")); - ASSERT_TRUE(s_credit_cards.is_valid()); - while (s_credit_cards.Step()) { - EXPECT_GE(s_credit_cards.ColumnInt64(0), - pre_creation_time.ToTimeT()); - EXPECT_LE(s_credit_cards.ColumnInt64(0), - post_creation_time.ToTimeT()); - } - EXPECT_TRUE(s_credit_cards.Succeeded()); - } -} - -// Makes sure guids are added to autofill_profiles and credit_cards tables. -TEST_F(WebDatabaseMigrationTest, MigrateVersion30ToCurrent) { - // Initialize the database. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_30.sql"))); - - // Verify pre-conditions. These are expectations for version 29 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "guid")); - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "guid")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid")); - ASSERT_TRUE(connection.DoesColumnExist("credit_cards", "guid")); - - // Check that guids are non-null, non-empty, conforms to guid format, and - // are different. - sql::Statement s( - connection.GetUniqueStatement("SELECT guid FROM autofill_profiles")); - - ASSERT_TRUE(s.Step()); - std::string guid1 = s.ColumnString(0); - EXPECT_TRUE(base::IsValidGUID(guid1)); - - ASSERT_TRUE(s.Step()); - std::string guid2 = s.ColumnString(0); - EXPECT_TRUE(base::IsValidGUID(guid2)); - - EXPECT_NE(guid1, guid2); - } -} - -// Removes unique IDs and make GUIDs the primary key. Also removes unused -// columns. -TEST_F(WebDatabaseMigrationTest, MigrateVersion31ToCurrent) { - // Initialize the database. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_31.sql"))); - - // Verify pre-conditions. These are expectations for version 30 of the - // database. - AutofillProfile profile; - base::string16 profile_label; - int profile_unique_id = 0; - int64 profile_date_modified = 0; - CreditCard credit_card; - base::string16 cc_label; - int cc_unique_id = 0; - std::string cc_number_encrypted; - int64 cc_date_modified = 0; - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Verify existence of columns we'll be changing. - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "unique_id")); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid")); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "unique_id")); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "type")); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "card_number")); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", - "verification_code")); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address")); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "shipping_address")); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", - "verification_code_encrypted")); - - // Fetch data in the database prior to migration. - sql::Statement s1( - connection.GetUniqueStatement( - "SELECT label, unique_id, first_name, middle_name, last_name, " - "email, company_name, address_line_1, address_line_2, city, state, " - "zipcode, country, phone, fax, date_modified, guid " - "FROM autofill_profiles")); - ASSERT_TRUE(s1.Step()); - EXPECT_NO_FATAL_FAILURE(AutofillProfile31FromStatement( - s1, &profile, &profile_label, &profile_unique_id, - &profile_date_modified)); - - sql::Statement s2( - connection.GetUniqueStatement( - "SELECT label, unique_id, name_on_card, type, card_number, " - "expiration_month, expiration_year, verification_code, " - "billing_address, shipping_address, card_number_encrypted, " - "verification_code_encrypted, date_modified, guid " - "FROM credit_cards")); - ASSERT_TRUE(s2.Step()); - EXPECT_NO_FATAL_FAILURE(CreditCard31FromStatement(s2, - &credit_card, - &cc_label, - &cc_unique_id, - &cc_number_encrypted, - &cc_date_modified)); - - EXPECT_NE(profile_unique_id, cc_unique_id); - EXPECT_NE(profile.guid(), credit_card.guid()); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // Verify existence of columns we'll be changing. - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid")); - EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "unique_id")); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid")); - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "unique_id")); - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "type")); - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "card_number")); - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", - "verification_code")); - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address")); - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", - "shipping_address")); - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", - "verification_code_encrypted")); - - // Verify data in the database after the migration. - sql::Statement s1( - connection.GetUniqueStatement( - "SELECT guid, company_name, street_address, city, state, zipcode," - " country_code, date_modified " - "FROM autofill_profiles")); - ASSERT_TRUE(s1.Step()); - - AutofillProfile profile_a; - int64 profile_date_modified_a = 0; - EXPECT_NO_FATAL_FAILURE(AutofillProfile33FromStatement( - s1, &profile_a, &profile_date_modified_a)); - EXPECT_EQ(profile.guid(), profile_a.guid()); - EXPECT_EQ(profile.GetRawInfo(autofill::COMPANY_NAME), - profile_a.GetRawInfo(autofill::COMPANY_NAME)); - EXPECT_EQ(profile.GetRawInfo(autofill::ADDRESS_HOME_LINE1), - profile_a.GetRawInfo(autofill::ADDRESS_HOME_LINE1)); - EXPECT_EQ(profile.GetRawInfo(autofill::ADDRESS_HOME_LINE2), - profile_a.GetRawInfo(autofill::ADDRESS_HOME_LINE2)); - EXPECT_EQ(profile.GetRawInfo(autofill::ADDRESS_HOME_CITY), - profile_a.GetRawInfo(autofill::ADDRESS_HOME_CITY)); - EXPECT_EQ(profile.GetRawInfo(autofill::ADDRESS_HOME_STATE), - profile_a.GetRawInfo(autofill::ADDRESS_HOME_STATE)); - EXPECT_EQ(profile.GetRawInfo(autofill::ADDRESS_HOME_ZIP), - profile_a.GetRawInfo(autofill::ADDRESS_HOME_ZIP)); - EXPECT_EQ(profile.GetRawInfo(autofill::ADDRESS_HOME_COUNTRY), - profile_a.GetRawInfo(autofill::ADDRESS_HOME_COUNTRY)); - EXPECT_EQ(profile_date_modified, profile_date_modified_a); - - sql::Statement s2( - connection.GetUniqueStatement( - "SELECT guid, name_on_card, expiration_month, " - "expiration_year, card_number_encrypted, date_modified " - "FROM credit_cards")); - ASSERT_TRUE(s2.Step()); - - CreditCard credit_card_a; - base::string16 cc_label_a; - std::string cc_number_encrypted_a; - int64 cc_date_modified_a = 0; - EXPECT_NO_FATAL_FAILURE(CreditCard32FromStatement(s2, - &credit_card_a, - &cc_number_encrypted_a, - &cc_date_modified_a)); - EXPECT_EQ(credit_card, credit_card_a); - EXPECT_EQ(cc_label, cc_label_a); - EXPECT_EQ(cc_number_encrypted, cc_number_encrypted_a); - EXPECT_EQ(cc_date_modified, cc_date_modified_a); - } -} - -// Factor |autofill_profiles| address information separately from name, email, -// and phone. -TEST_F(WebDatabaseMigrationTest, MigrateVersion32ToCurrent) { - // Initialize the database. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_32.sql"))); - - // Verify pre-conditions. These are expectations for version 32 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Verify existence of columns we'll be changing. - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "label")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "first_name")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "middle_name")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "last_name")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "email")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", - "company_name")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", - "address_line_1")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", - "address_line_2")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "city")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "state")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "zipcode")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "country")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "phone")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "fax")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", - "date_modified")); - - EXPECT_FALSE(connection.DoesTableExist("autofill_profile_names")); - EXPECT_FALSE(connection.DoesTableExist("autofill_profile_emails")); - EXPECT_FALSE(connection.DoesTableExist("autofill_profile_phones")); - - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "label")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // Verify changes to columns. - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid")); - EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "label")); - EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "first_name")); - EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", - "middle_name")); - EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "last_name")); - EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "email")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", - "company_name")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", - "street_address")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "city")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "state")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "zipcode")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", - "country_code")); - EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "phone")); - EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "fax")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", - "date_modified")); - - // New "names" table. - EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_names", "guid")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_names", - "first_name")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_names", - "middle_name")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_names", - "last_name")); - - // New "emails" table. - EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_emails", "guid")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_emails", "email")); - - // New "phones" table. - EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_phones", "guid")); - EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_phones", - "number")); - - EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "label")); - - // Verify data in the database after the migration. - sql::Statement s1( - connection.GetUniqueStatement( - "SELECT guid, company_name, street_address, city, state, zipcode, " - " country_code, date_modified " - "FROM autofill_profiles")); - - // John Doe. - ASSERT_TRUE(s1.Step()); - EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s1.ColumnString(0)); - EXPECT_EQ(ASCIIToUTF16("Doe Enterprises"), s1.ColumnString16(1)); - EXPECT_EQ(ASCIIToUTF16("1 Main St\n" - "Apt 1"), - s1.ColumnString16(2)); - EXPECT_EQ(ASCIIToUTF16("Los Altos"), s1.ColumnString16(3)); - EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(4)); - EXPECT_EQ(ASCIIToUTF16("94022"), s1.ColumnString16(5)); - EXPECT_EQ(ASCIIToUTF16("US"), s1.ColumnString16(6)); - EXPECT_EQ(1297882100L, s1.ColumnInt64(7)); - - // John P. Doe. - // Gets merged during migration from 35 to 37 due to multi-valued fields. - - // Dave Smith. - ASSERT_TRUE(s1.Step()); - EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s1.ColumnString(0)); - EXPECT_EQ(base::string16(), s1.ColumnString16(1)); - EXPECT_EQ(ASCIIToUTF16("2 Main Street"), s1.ColumnString16(2)); - EXPECT_EQ(ASCIIToUTF16("Los Altos"), s1.ColumnString16(3)); - EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(4)); - EXPECT_EQ(ASCIIToUTF16("94022"), s1.ColumnString16(5)); - EXPECT_EQ(ASCIIToUTF16("US"), s1.ColumnString16(6)); - EXPECT_EQ(1297882100L, s1.ColumnInt64(7)); - - // Dave Smith (Part 2). - ASSERT_TRUE(s1.Step()); - EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s1.ColumnString(0)); - EXPECT_EQ(base::string16(), s1.ColumnString16(1)); - EXPECT_EQ(ASCIIToUTF16("2 Main St"), s1.ColumnString16(2)); - EXPECT_EQ(ASCIIToUTF16("Los Altos"), s1.ColumnString16(3)); - EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(4)); - EXPECT_EQ(ASCIIToUTF16("94022"), s1.ColumnString16(5)); - EXPECT_EQ(ASCIIToUTF16("US"), s1.ColumnString16(6)); - EXPECT_EQ(1297882100L, s1.ColumnInt64(7)); - - // Alfred E Newman. - // Gets culled during migration from 35 to 36 due to incomplete address. - - // 3 Main St. - ASSERT_TRUE(s1.Step()); - EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s1.ColumnString(0)); - EXPECT_EQ(base::string16(), s1.ColumnString16(1)); - EXPECT_EQ(ASCIIToUTF16("3 Main St"), s1.ColumnString16(2)); - EXPECT_EQ(ASCIIToUTF16("Los Altos"), s1.ColumnString16(3)); - EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(4)); - EXPECT_EQ(ASCIIToUTF16("94022"), s1.ColumnString16(5)); - EXPECT_EQ(ASCIIToUTF16("US"), s1.ColumnString16(6)); - EXPECT_EQ(1297882100L, s1.ColumnInt64(7)); - - // That should be all. - EXPECT_FALSE(s1.Step()); - - sql::Statement s2( - connection.GetUniqueStatement( - "SELECT guid, first_name, middle_name, last_name " - "FROM autofill_profile_names")); - - // John Doe. - ASSERT_TRUE(s2.Step()); - EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s2.ColumnString(0)); - EXPECT_EQ(ASCIIToUTF16("John"), s2.ColumnString16(1)); - EXPECT_EQ(base::string16(), s2.ColumnString16(2)); - EXPECT_EQ(ASCIIToUTF16("Doe"), s2.ColumnString16(3)); - - // John P. Doe. Note same guid as above due to merging of multi-valued - // fields. - ASSERT_TRUE(s2.Step()); - EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s2.ColumnString(0)); - EXPECT_EQ(ASCIIToUTF16("John"), s2.ColumnString16(1)); - EXPECT_EQ(ASCIIToUTF16("P."), s2.ColumnString16(2)); - EXPECT_EQ(ASCIIToUTF16("Doe"), s2.ColumnString16(3)); - - // Dave Smith. - ASSERT_TRUE(s2.Step()); - EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s2.ColumnString(0)); - EXPECT_EQ(ASCIIToUTF16("Dave"), s2.ColumnString16(1)); - EXPECT_EQ(base::string16(), s2.ColumnString16(2)); - EXPECT_EQ(ASCIIToUTF16("Smith"), s2.ColumnString16(3)); - - // Dave Smith (Part 2). - ASSERT_TRUE(s2.Step()); - EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s2.ColumnString(0)); - EXPECT_EQ(ASCIIToUTF16("Dave"), s2.ColumnString16(1)); - EXPECT_EQ(base::string16(), s2.ColumnString16(2)); - EXPECT_EQ(ASCIIToUTF16("Smith"), s2.ColumnString16(3)); - - // Alfred E Newman. - // Gets culled during migration from 35 to 36 due to incomplete address. - - // 3 Main St. - ASSERT_TRUE(s2.Step()); - EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s2.ColumnString(0)); - EXPECT_EQ(base::string16(), s2.ColumnString16(1)); - EXPECT_EQ(base::string16(), s2.ColumnString16(2)); - EXPECT_EQ(base::string16(), s2.ColumnString16(3)); - - // Should be all. - EXPECT_FALSE(s2.Step()); - - sql::Statement s3( - connection.GetUniqueStatement( - "SELECT guid, email " - "FROM autofill_profile_emails")); - - // John Doe. - ASSERT_TRUE(s3.Step()); - EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s3.ColumnString(0)); - EXPECT_EQ(ASCIIToUTF16("john@doe.com"), s3.ColumnString16(1)); - - // John P. Doe. - // Gets culled during migration from 35 to 37 due to merging of John Doe and - // John P. Doe addresses. - - // 2 Main Street. - ASSERT_TRUE(s3.Step()); - EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s3.ColumnString(0)); - EXPECT_EQ(base::string16(), s3.ColumnString16(1)); - - // 2 Main St. - ASSERT_TRUE(s3.Step()); - EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s3.ColumnString(0)); - EXPECT_EQ(base::string16(), s3.ColumnString16(1)); - - // Alfred E Newman. - // Gets culled during migration from 35 to 36 due to incomplete address. - - // 3 Main St. - ASSERT_TRUE(s3.Step()); - EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s3.ColumnString(0)); - EXPECT_EQ(base::string16(), s3.ColumnString16(1)); - - // Should be all. - EXPECT_FALSE(s3.Step()); - - sql::Statement s4( - connection.GetUniqueStatement( - "SELECT guid, number " - "FROM autofill_profile_phones")); - - // John Doe phone. - ASSERT_TRUE(s4.Step()); - EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s4.ColumnString(0)); - EXPECT_EQ(ASCIIToUTF16("4151112222"), s4.ColumnString16(1)); - - // John Doe fax. - // Gets culled after fax type removed. - - // John P. Doe phone. - // Gets culled during migration from 35 to 37 due to merging of John Doe and - // John P. Doe addresses. - - // John P. Doe fax. - // Gets culled during migration from 35 to 37 due to merging of John Doe and - // John P. Doe addresses. - - // 2 Main Street phone. - ASSERT_TRUE(s4.Step()); - EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s4.ColumnString(0)); - EXPECT_EQ(base::string16(), s4.ColumnString16(1)); - - // 2 Main Street fax. - // Gets culled after fax type removed. - - // 2 Main St phone. - ASSERT_TRUE(s4.Step()); - EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s4.ColumnString(0)); - EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone. - EXPECT_EQ(base::string16(), s4.ColumnString16(2)); - - // 2 Main St fax. - // Gets culled after fax type removed. - - // Note no phone or fax for Alfred E Newman. - - // 3 Main St phone. - ASSERT_TRUE(s4.Step()); - EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s4.ColumnString(0)); - EXPECT_EQ(base::string16(), s4.ColumnString16(1)); - - // 2 Main St fax. - // Gets culled after fax type removed. - - // Should be all. - EXPECT_FALSE(s4.Step()); - } -} - -// Adds a column for the autofill profile's country code. -TEST_F(WebDatabaseMigrationTest, MigrateVersion33ToCurrent) { - // Initialize the database. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_33.sql"))); - - // Verify pre-conditions. These are expectations for version 33 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", - "country_code")); - - // Check that the country value is the one we expect. - sql::Statement s( - connection.GetUniqueStatement("SELECT country FROM autofill_profiles")); - - ASSERT_TRUE(s.Step()); - std::string country = s.ColumnString(0); - EXPECT_EQ("United States", country); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles", - "country_code")); - - // Check that the country code is properly converted. - sql::Statement s(connection.GetUniqueStatement( - "SELECT country_code FROM autofill_profiles")); - - ASSERT_TRUE(s.Step()); - std::string country_code = s.ColumnString(0); - EXPECT_EQ("US", country_code); - } -} - -// Cleans up bad country code "UK" in favor of good country code "GB". -TEST_F(WebDatabaseMigrationTest, MigrateVersion34ToCurrent) { - // Initialize the database. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_34.sql"))); - - // Verify pre-conditions. These are expectations for version 34 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", - "country_code")); - - // Check that the country_code value is the one we expect. - sql::Statement s( - connection.GetUniqueStatement("SELECT country_code " - "FROM autofill_profiles")); - - ASSERT_TRUE(s.Step()); - std::string country_code = s.ColumnString(0); - EXPECT_EQ("UK", country_code); - - // Should have only one. - ASSERT_FALSE(s.Step()); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles", - "country_code")); - - // Check that the country_code code is properly converted. - sql::Statement s(connection.GetUniqueStatement( - "SELECT country_code FROM autofill_profiles")); - - ASSERT_TRUE(s.Step()); - std::string country_code = s.ColumnString(0); - EXPECT_EQ("GB", country_code); - - // Should have only one. - ASSERT_FALSE(s.Step()); - } -} - -// Cleans up invalid profiles based on more agressive merging. Filters out -// profiles that are subsets of other profiles, and profiles with invalid email, -// state, and incomplete address. -TEST_F(WebDatabaseMigrationTest, MigrateVersion35ToCurrent) { - // Initialize the database. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_35.sql"))); - - // Verify pre-conditions. These are expectations for version 34 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - EXPECT_FALSE(connection.DoesTableExist("autofill_profiles_trash")); - ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid")); - - // Check that there are 6 profiles prior to merge. - sql::Statement s( - connection.GetUniqueStatement("SELECT guid FROM autofill_profiles")); - int i = 0; - while (s.Step()) - ++i; - EXPECT_EQ(6, i); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - ASSERT_TRUE(connection.DoesTableExist("autofill_profiles_trash")); - ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles_trash", "guid")); - ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid")); - - // Verify data in the database after the migration. - sql::Statement s1( - connection.GetUniqueStatement( - "SELECT guid, company_name, street_address, city, state, zipcode," - " country_code, date_modified " - "FROM autofill_profiles")); - - // John Doe. - ASSERT_TRUE(s1.Step()); - EXPECT_EQ("00000000-0000-0000-0000-000000000001", s1.ColumnString(0)); - EXPECT_EQ(ASCIIToUTF16("Acme Inc."), s1.ColumnString16(1)); - EXPECT_EQ(ASCIIToUTF16("1 Main Street\n" - "Apt 2"), - s1.ColumnString16(2)); - EXPECT_EQ(ASCIIToUTF16("San Francisco"), s1.ColumnString16(3)); - EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(4)); - EXPECT_EQ(ASCIIToUTF16("94102"), s1.ColumnString16(5)); - EXPECT_EQ(ASCIIToUTF16("US"), s1.ColumnString16(6)); - EXPECT_EQ(1300131704, s1.ColumnInt64(7)); - - // That should be it. - ASSERT_FALSE(s1.Step()); - - // Check that there 5 trashed profile after the merge. - sql::Statement s2( - connection.GetUniqueStatement("SELECT guid " - "FROM autofill_profiles_trash")); - ASSERT_TRUE(s2.Step()); - EXPECT_EQ("00000000-0000-0000-0000-000000000002", s2.ColumnString(0)); - - ASSERT_TRUE(s2.Step()); - EXPECT_EQ("00000000-0000-0000-0000-000000000003", s2.ColumnString(0)); - - ASSERT_TRUE(s2.Step()); - EXPECT_EQ("00000000-0000-0000-0000-000000000004", s2.ColumnString(0)); - - ASSERT_TRUE(s2.Step()); - EXPECT_EQ("00000000-0000-0000-0000-000000000005", s2.ColumnString(0)); - - ASSERT_TRUE(s2.Step()); - EXPECT_EQ("00000000-0000-0000-0000-000000000006", s2.ColumnString(0)); - - // That should be it. - ASSERT_FALSE(s2.Step()); - } -} - -// Tests that the |keywords| |last_modified| column gets added to the schema for -// a version 37 database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion37ToCurrent) { - // This schema is taken from a build prior to the addition of the |keywords| - // |last_modified| column. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_37.sql"))); - - // Verify pre-conditions. These are expectations for version 37 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Columns existing and not existing before current version. - ASSERT_TRUE(connection.DoesColumnExist("keywords", "id")); - ASSERT_FALSE(connection.DoesColumnExist("keywords", "last_modified")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // |keywords| |last_modified| column should have been added. - EXPECT_TRUE(connection.DoesColumnExist("keywords", "id")); - EXPECT_TRUE(connection.DoesColumnExist("keywords", "last_modified")); - } -} - -// Tests that the |keywords| |sync_guid| column gets added to the schema for -// a version 38 database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion38ToCurrent) { - // This schema is taken from a build prior to the addition of the |keywords| - // |sync_guid| column. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_38.sql"))); - - // Verify pre-conditions. These are expectations for version 38 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Columns existing and not existing before current version. - ASSERT_TRUE(connection.DoesColumnExist("keywords", "id")); - ASSERT_FALSE(connection.DoesColumnExist("keywords", "sync_guid")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // |keywords| |sync_guid| column should have been added. - EXPECT_TRUE(connection.DoesColumnExist("keywords", "id")); - EXPECT_TRUE(connection.DoesColumnExist("keywords", "sync_guid")); - } -} - -// Tests that no backup data is added to a version 39 database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion39ToCurrent) { - // This schema is taken from a build prior to the addition of the default - // search provider backup field to the meta table. - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_39.sql"))); - - // Verify pre-conditions. These are expectations for version 39 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, 39, 39)); - - int64 default_search_provider_id = 0; - EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey, - &default_search_provider_id)); - - EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table)); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber, - kCurrentTestedVersionNumber)); - - int64 default_search_provider_id = 0; - EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey, - &default_search_provider_id)); - EXPECT_NE(0, default_search_provider_id); - - EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table)); - } -} - -// Tests that the backup data is removed from the database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion40ToCurrent) { - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_40.sql"))); - - // Verify pre-conditions. These are expectations for version 40 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, 40, 40)); - - int64 default_search_provider_id = 0; - EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey, - &default_search_provider_id)); - - EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table)); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber, - kCurrentTestedVersionNumber)); - - int64 default_search_provider_id = 0; - EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey, - &default_search_provider_id)); - EXPECT_NE(0, default_search_provider_id); - - EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table)); - } -} - -// Tests that the backup data is removed from the database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion41ToCurrent) { - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_41.sql"))); - - // Verify pre-conditions. These are expectations for version 41 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, 41, 41)); - - int64 default_search_provider_id = 0; - EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey, - &default_search_provider_id)); - - EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table)); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber, - kCurrentTestedVersionNumber)); - - int64 default_search_provider_id = 0; - EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey, - &default_search_provider_id)); - EXPECT_NE(0, default_search_provider_id); - - EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table)); - } -} - -// Tests that the backup data is removed from the database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion42ToCurrent) { - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_42.sql"))); - - // Verify pre-conditions. These are expectations for version 42 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, 42, 42)); - - int64 default_search_provider_id = 0; - EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey, - &default_search_provider_id)); - - EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table)); - - EXPECT_FALSE(connection.DoesTableExist("keywords_backup")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber, - kCurrentTestedVersionNumber)); - - int64 default_search_provider_id = 0; - EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey, - &default_search_provider_id)); - EXPECT_NE(0, default_search_provider_id); - - EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table)); - } -} - -// Tests that the backup data is removed from the database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion43ToCurrent) { - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_43.sql"))); - - int64 previous_default_search_provider_id; - - // Verify pre-conditions. These are expectations for version 43 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, 43, 43)); - - int64 default_search_provider_id = 0; - EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey, - &default_search_provider_id)); - EXPECT_NE(default_search_provider_id, 0); - previous_default_search_provider_id = default_search_provider_id; - - EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table)); - EXPECT_TRUE(connection.DoesTableExist("keywords_backup")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init( - &connection, - kCurrentTestedVersionNumber, - kCurrentTestedVersionNumber)); - - int64 default_search_provider_id = 0; - EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey, - &default_search_provider_id)); - // Default search provider ID should not change. - EXPECT_EQ(previous_default_search_provider_id, default_search_provider_id); - - EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table)); - } -} - -// Tests that the |autogenerate_keyword| and |logo_id| columns get removed from -// the keyword table schema for a version 45 database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion44ToCurrent) { - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_44.sql"))); - - // Verify pre-conditions. These are expectations for version 44 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, 44, 44)); - - ASSERT_TRUE(connection.DoesColumnExist("keywords", "autogenerate_keyword")); - ASSERT_TRUE(connection.DoesColumnExist("keywords", "logo_id")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber, - kCurrentTestedVersionNumber)); - - // We should have removed this obsolete key. - std::string default_search_provider_backup; - EXPECT_FALSE(meta_table.GetValue("Default Search Provider Backup", - &default_search_provider_backup)); - - // Two columns should have been removed. - EXPECT_FALSE(connection.DoesColumnExist("keywords", - "autogenerate_keyword")); - EXPECT_FALSE(connection.DoesColumnExist("keywords", "logo_id")); - - // Backup data should have been removed. - EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table)); - } -} - -// Previously, this tested that the web_intents and web_intents_defaults tables -// were modified to include "scheme" columns. Since the web_intents and -// web_intents_defaults tables are now obsolete, this test checks to ensure that -// they are properly removed. -TEST_F(WebDatabaseMigrationTest, MigrateVersion45ToCurrent) { - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_45.sql"))); - - // Verify pre-conditions. These are expectations for version 45 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, 45, 45)); - - ASSERT_FALSE(connection.DoesColumnExist("scheme", "web_intents")); - ASSERT_FALSE(connection.DoesColumnExist( - "scheme", "web_intents_defaults")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init( - &connection, - kCurrentTestedVersionNumber, - kCurrentTestedVersionNumber)); - - // finally ensure the migration code cleaned up after itself - EXPECT_FALSE(connection.DoesTableExist("web_intents")); - EXPECT_FALSE(connection.DoesTableExist("web_intents_defaults")); - } -} - -// Previously, this tested that the web_intents and web_intents_defaults tables -// were modified to include "scheme" columns. Since the web_intents and -// web_intents_defaults tables are now obsolete, this test checks to ensure that -// they are properly removed. -TEST_F(WebDatabaseMigrationTest, MigrateVersion45InvalidToCurrent) { - ASSERT_NO_FATAL_FAILURE( - LoadDatabase(FILE_PATH_LITERAL("version_45_invalid.sql"))); - - // Verify pre-conditions. These are expectations for version 45 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, 45, 45)); - - ASSERT_FALSE(connection.DoesColumnExist("scheme", "web_intents")); - ASSERT_FALSE(connection.DoesColumnExist( - "scheme", "web_intents_defaults")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init( - &connection, - kCurrentTestedVersionNumber, - kCurrentTestedVersionNumber)); - - EXPECT_FALSE(connection.DoesTableExist("web_intents")); - EXPECT_FALSE(connection.DoesTableExist("web_intents_defaults")); - } -} - -// Check that current version is forced to compatible version before migration, -// if the former is smaller. -TEST_F(WebDatabaseMigrationTest, MigrateVersion45CompatibleToCurrent) { - ASSERT_NO_FATAL_FAILURE( - LoadDatabase(FILE_PATH_LITERAL("version_45_compatible.sql"))); - - // Verify pre-conditions. These are expectations for version 45 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - sql::MetaTable meta_table; - // Database is actually version 45 but the version field states 40. - ASSERT_TRUE(meta_table.Init(&connection, 40, 45)); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - EXPECT_LE(45, VersionFromConnection(&connection)); - } -} - -// Tests that the |alternate_urls| column is added to the keyword table schema -// for a version 47 database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion46ToCurrent) { - ASSERT_NO_FATAL_FAILURE( - LoadDatabase(FILE_PATH_LITERAL("version_46.sql"))); - - // Verify pre-conditions. These are expectations for version 46 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, 46, 46)); - - ASSERT_FALSE(connection.DoesColumnExist("keywords", "alternate_urls")); - ASSERT_FALSE(connection.DoesColumnExist("keywords_backup", - "alternate_urls")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // A new column should have been created. - EXPECT_TRUE(connection.DoesColumnExist("keywords", "alternate_urls")); - } -} - -// Tests that the backup data is removed from the database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion47ToCurrent) { - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_47.sql"))); - - // Verify pre-conditions. These are expectations for version 47 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, 47, 47)); - - int64 default_search_provider_id = 0; - EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey, - &default_search_provider_id)); - EXPECT_NE(0, default_search_provider_id); - - EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table)); - EXPECT_TRUE(connection.DoesTableExist("keywords_backup")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber, - kCurrentTestedVersionNumber)); - - int64 default_search_provider_id = 0; - EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey, - &default_search_provider_id)); - EXPECT_NE(0, default_search_provider_id); - - EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table)); - } -} - -// Tests that the |search_terms_replacement_key| column is added to the keyword -// table schema for a version 49 database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion48ToCurrent) { - ASSERT_NO_FATAL_FAILURE( - LoadDatabase(FILE_PATH_LITERAL("version_48.sql"))); - - // Verify pre-conditions. These are expectations for version 48 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&connection, 48, 48)); - - ASSERT_FALSE(connection.DoesColumnExist("keywords", - "search_terms_replacement_key")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // A new column should have been created. - EXPECT_TRUE(connection.DoesColumnExist("keywords", - "search_terms_replacement_key")); - } -} - -// Tests that the |origin| column is added to the autofill_profiles and -// credit_cards table schemas for a version 50 database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion49ToCurrent) { - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_49.sql"))); - - // Verify pre-conditions. These are expectations for version 49 of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - - ASSERT_FALSE(connection.DoesColumnExist("autofill_profiles", "origin")); - ASSERT_FALSE(connection.DoesColumnExist("credit_cards", "origin")); - } - - DoMigration(); - - // Verify post-conditions. These are expectations for current version of the - // database. - { - sql::Connection connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - // Check version. - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - - // A new column should have been created in both tables. - EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "origin")); - EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "origin")); - } -} - -// Tests that the columns |image_url|, |search_url_post_params|, -// |suggest_url_post_params|, |instant_url_post_params|, and -// |image_url_post_params| are added to the keyword table schema for a version -// 50 database. -TEST_F(WebDatabaseMigrationTest, MigrateVersion50ToCurrent) { +// Versions below 52 are deprecated. This verifies that old databases are razed. +TEST_F(WebDatabaseMigrationTest, RazeDeprecatedVersionAndReinit) { ASSERT_NO_FATAL_FAILURE( LoadDatabase(FILE_PATH_LITERAL("version_50.sql")));
diff --git a/components/webui_generator.gypi b/components/webui_generator.gypi new file mode 100644 index 0000000..32556c4f --- /dev/null +++ b/components/webui_generator.gypi
@@ -0,0 +1,37 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'targets': [{ + # GN version: //components/webui_generator + 'target_name': 'webui_generator', + 'type': '<(component)', + 'dependencies': [ + 'login', + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/components/components_resources.gyp:components_resources', + '<(DEPTH)/content/content.gyp:content_browser', + '<(DEPTH)/ui/base/ui_base.gyp:ui_base', + ], + 'export_dependent_settings': [ + 'login', + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/content/content.gyp:content_browser', + ], + 'defines': [ + 'WUG_IMPLEMENTATION', + ], + 'sources': [ + 'webui_generator/data_source_util.cc', + 'webui_generator/data_source_util.h', + 'webui_generator/export.h', + 'webui_generator/view.cc', + 'webui_generator/view.h', + 'webui_generator/view_model.cc', + 'webui_generator/view_model.h', + 'webui_generator/web_ui_view.cc', + 'webui_generator/web_ui_view.h', + ], + }], +}
diff --git a/components/webui_generator/BUILD.gn b/components/webui_generator/BUILD.gn new file mode 100644 index 0000000..13e167f --- /dev/null +++ b/components/webui_generator/BUILD.gn
@@ -0,0 +1,36 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# GYP version: components/webui_generator.gypi:webui_generator +component("webui_generator") { + sources = [ + "data_source_util.cc", + "data_source_util.h", + "export.h", + "view.cc", + "view.h", + "view_model.cc", + "view_model.h", + "web_ui_view.cc", + "web_ui_view.h", + ] + + defines = [ "WUG_IMPLEMENTATION" ] + + deps = [ + "//components/resources", + "//ui/base", + ] + + public_deps = [ + "//base", + "//components/login", + "//content/public/browser", + ] +} + +# Config for users of generated files. +config("wug_generated_config") { + include_dirs = [ "$root_gen_dir/wug" ] +}
diff --git a/components/webui_generator/DEPS b/components/webui_generator/DEPS new file mode 100644 index 0000000..3985eeff --- /dev/null +++ b/components/webui_generator/DEPS
@@ -0,0 +1,6 @@ +include_rules = [ + "+base", + "+content/public/browser", + "+grit/components_resources.h", + "+components/login", +]
diff --git a/components/webui_generator/OWNERS b/components/webui_generator/OWNERS new file mode 100644 index 0000000..df660f709 --- /dev/null +++ b/components/webui_generator/OWNERS
@@ -0,0 +1 @@ +dzhioev@chromium.org
diff --git a/components/webui_generator/data_source_util.cc b/components/webui_generator/data_source_util.cc new file mode 100644 index 0000000..a3103cd --- /dev/null +++ b/components/webui_generator/data_source_util.cc
@@ -0,0 +1,22 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/webui_generator/data_source_util.h" +#include "content/public/browser/web_ui_data_source.h" +#include "grit/components_resources.h" + +namespace webui_generator { + +void SetUpDataSource(content::WebUIDataSource* data_source) { + data_source->AddResourcePath("webui_generator/webui-view.html", + IDR_WUG_WEBUI_VIEW_HTML); + data_source->AddResourcePath("webui_generator/webui-view.js", + IDR_WUG_WEBUI_VIEW_JS); + data_source->AddResourcePath("webui_generator/context.js", + IDR_WUG_CONTEXT_JS); + data_source->AddResourcePath("webui_generator/context.html", + IDR_WUG_CONTEXT_HTML); +} + +} // namespace webui_generator
diff --git a/components/webui_generator/data_source_util.h b/components/webui_generator/data_source_util.h new file mode 100644 index 0000000..95abe42 --- /dev/null +++ b/components/webui_generator/data_source_util.h
@@ -0,0 +1,21 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_WUG_DATA_SOURCE_UTIL_H_ +#define CHROME_BROWSER_UI_WEBUI_WUG_DATA_SOURCE_UTIL_H_ + +#include "components/webui_generator/export.h" + +namespace content { +class WebUIDataSource; +} + +namespace webui_generator { + +// Adds common resources needed for WUG to |data_source|. +void WUG_EXPORT SetUpDataSource(content::WebUIDataSource* data_source); + +} // namespace webui_generator + +#endif // CHROME_BROWSER_UI_WEBUI_WUG_DATA_SOURCE_UTIL_H_
diff --git a/components/webui_generator/export.h b/components/webui_generator/export.h new file mode 100644 index 0000000..226cfd25e --- /dev/null +++ b/components/webui_generator/export.h
@@ -0,0 +1,34 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_WUG_EXPORT_H_ +#define COMPONENTS_WUG_EXPORT_H_ + +#if defined(COMPONENT_BUILD) + +#if defined(WIN32) + +#if defined(WUG_IMPLEMENTATION) +#define WUG_EXPORT __declspec(dllexport) +#else +#define WUG_EXPORT __declspec(dllimport) +#endif // defined(WUG_IMPLEMENTATION) + +#else // defined(WIN32) + +#if defined(WUG_IMPLEMENTATION) +#define WUG_EXPORT __attribute__((visibility("default"))) +#else +#define WUG_EXPORT +#endif // defined(WUG_IMPLEMENTATION) + +#endif // defined(WIN32) + +#else // defined(COMPONENT_BUILD) + +#define WUG_EXPORT + +#endif + +#endif // COMPONENTS_WUG_EXPORT_H_
diff --git a/components/webui_generator/generator/build_helper.py b/components/webui_generator/generator/build_helper.py new file mode 100644 index 0000000..06232e6 --- /dev/null +++ b/components/webui_generator/generator/build_helper.py
@@ -0,0 +1,69 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Provides various information needed for GYP and GN to generate and build +# files. + +import os +import sys + +from declaration import Declaration +import export_h +import util +import view_model +import web_ui_view + +def GetImportDependencies(declaration): + return set(child.build_target for child in declaration.children.itervalues()) + +parser = util.CreateArgumentParser() +parser.add_argument('--output', + choices=['view_cc', 'view_h', 'model_cc', 'model_h', + 'export_h', 'dirname', 'target_name', 'imports', + 'impl_macro', 'import_dependencies', + 'list_outputs'], + required=True, + help='Type of output') +parser.add_argument('--gn', action='store_true', + help='Is called by GN') +args = parser.parse_args() +declaration_path = os.path.relpath(args.declaration, args.root) +os.chdir(args.root) +try: + declaration = Declaration(declaration_path) +except Exception as e: + print >> sys.stderr, e.message + sys.exit(1) + +if args.output == 'view_cc': + print declaration.webui_view_cc_name +elif args.output == 'view_h': + print declaration.webui_view_h_name +elif args.output == 'model_cc': + print declaration.view_model_cc_name +elif args.output == 'model_h': + print declaration.view_model_h_name +elif args.output == 'export_h': + print declaration.export_h_name +elif args.output == 'dirname': + print os.path.dirname(declaration_path) +elif args.output == 'target_name': + print declaration.build_target +elif args.output == 'imports': + for i in declaration.imports: + print '//' + i +elif args.output == 'import_dependencies': + for d in GetImportDependencies(declaration): + print (':' if args.gn else '') + d +elif args.output == 'list_outputs': + outputs = web_ui_view.ListOutputs(declaration, args.destination) + \ + view_model.ListOutputs(declaration, args.destination) + \ + export_h.ListOutputs(declaration, args.destination) + for output in outputs: + print output +elif args.output == 'impl_macro': + print declaration.component_impl_macro +else: + assert False +
diff --git a/components/webui_generator/generator/declaration.py b/components/webui_generator/generator/declaration.py new file mode 100644 index 0000000..e9863b5 --- /dev/null +++ b/components/webui_generator/generator/declaration.py
@@ -0,0 +1,312 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import itertools +import json +import os.path +import re + +import util + +# Schema is described as follows: +# * for simple type: +# %simple_type% +# * for list: +# (list, %items_schema%) +# * for dict: +# (dict, { '%key_name%': (%is_key_required%, %value_schema%), +# ... +# }) +DECLARATION_SCHEMA = (dict, { + 'imports': (False, (list, unicode)), + 'type': (True, unicode), + 'children': (False, (list, (dict, { + 'id': (True, unicode), + 'type': (True, unicode), + 'comment': (False, unicode) + }))), + 'context': (False, (list, (dict, { + 'name': (True, unicode), + 'type': (False, unicode), + 'default': (False, object), + 'comment': (False, unicode) + }))), + 'events': (False, (list, (dict, { + 'name': (True, unicode), + 'comment': (False, unicode) + }))), + 'strings': (False, (list, (dict, { + 'name': (True, unicode), + 'comment': (False, unicode) + }))), + 'comment': (False, unicode) +}) + +# Returns (True,) if |obj| matches |schema|. +# Otherwise returns (False, msg), where |msg| is a diagnostic message. +def MatchSchema(obj, schema): + expected_type = schema[0] if isinstance(schema, tuple) else schema + if not isinstance(obj, expected_type): + return (False, 'Wrong type, expected %s, got %s.' % + (expected_type, type(obj))) + if expected_type == dict: + obj_keys = set(obj.iterkeys()) + allowed_keys = set(schema[1].iterkeys()) + required_keys = set(kv[0] for kv in schema[1].iteritems() if kv[1][0]) + if not obj_keys.issuperset(required_keys): + missing_keys = required_keys.difference(obj_keys) + return (False, 'Missing required key%s %s.' % + ('s' if len(missing_keys) > 1 else '', + ', '.join('\'%s\'' % k for k in missing_keys))) + if not obj_keys.issubset(allowed_keys): + unknown_keys = obj_keys.difference(allowed_keys) + return (False, 'Unknown key%s %s.' % + ('s' if len(unknown_keys) > 1 else '', + ', '.join('\'%s\'' % k for k in unknown_keys))) + for key in obj: + match = MatchSchema(obj[key], schema[1][key][1]) + if not match[0]: + return (False, ('[\'%s\'] ' % key) + match[1]) + elif expected_type == list: + for i, item in enumerate(obj): + match = MatchSchema(item, schema[1]) + if not match[0]: + return (False, ('[%d] ' % i) + match[1]) + return (True,) + +def CheckDeclarationIsValid(declaration): + match = MatchSchema(declaration, DECLARATION_SCHEMA) + if not match[0]: + raise Exception('Declaration is not valid: ' + match[1]) + +def CheckFieldIsUnique(list_of_dicts, field): + seen = {} + for i, d in enumerate(list_of_dicts): + value = d[field] + if value in seen: + raise Exception( + '[%d] Object with "%s" equal to "%s" already exists. See [%d].' % + (i, field, value, seen[value])) + else: + seen[value] = i + +class FieldDeclaration(object): + ALLOWED_TYPES = [ + 'boolean', + 'integer', + 'double', + 'string', + 'string_list' + ] + + DEFAULTS = { + 'boolean': False, + 'integer': 0, + 'double': 0.0, + 'string': u'', + 'string_list': [] + } + + def __init__(self, declaration): + self.name = declaration['name'] + self.id = util.ToLowerCamelCase(self.name) + self.type = declaration['type'] if 'type' in declaration else 'string' + if self.type not in self.ALLOWED_TYPES: + raise Exception('Unknown type of context field "%s": "%s"' % + (self.name, self.type)) + self.default_value = declaration['default'] if 'default' in declaration \ + else self.DEFAULTS[self.type] + if type(self.default_value) != type(self.DEFAULTS[self.type]): + raise Exception('Wrong type of default for field "%s": ' + 'expected "%s", got "%s"' % + (self.name, + type(self.DEFAULTS[self.type]), + type(self.default_value))) + +class Declaration(object): + class InvalidDeclaration(Exception): + def __init__(self, path, message): + super(Exception, self).__init__( + 'Invalid declaration file "%s": %s' % (path, message)) + + class DeclarationsStorage(object): + def __init__(self): + self.by_path = {} + self.by_type = {} + + def Add(self, declaration): + assert declaration.path not in self.by_path + self.by_path[declaration.path] = declaration + if declaration.type in self.by_type: + raise Exception( + 'Redefinition of type "%s". ' \ + 'Previous definition was in "%s".' % \ + (declaration.type, self.by_type[declaration.type].path)) + self.by_type[declaration.type] = declaration + + def HasPath(self, path): + return path in self.by_path + + def HasType(self, type): + return type in self.by_type + + def GetByPath(self, path): + return self.by_path[path] + + def GetByType(self, type): + return self.by_type[type] + + def GetKnownPathes(self): + return self.by_path.keys() + + + def __init__(self, path, known_declarations=None): + if known_declarations is None: + known_declarations = Declaration.DeclarationsStorage() + self.path = path + try: + self.data = json.load(open(path, 'r')) + CheckDeclarationIsValid(self.data) + filename_wo_ext = os.path.splitext(os.path.basename(self.path))[0] + if self.data['type'] != filename_wo_ext: + raise Exception( + 'File with declaration of type "%s" should be named "%s.json"' % + (self.data['type'], filename_wo_ext)) + + known_declarations.Add(self) + if 'imports' in self.data: + for import_path in self.data['imports']: + #TODO(dzhioev): detect circular dependencies. + if not known_declarations.HasPath(import_path): + Declaration(import_path, known_declarations) + + for key in ['children', 'strings', 'context', 'events']: + if key in self.data: + unique_field = 'id' if key == 'children' else 'name' + try: + CheckFieldIsUnique(self.data[key], unique_field) + except Exception as e: + raise Exception('["%s"] %s' % (key, e.message)) + else: + self.data[key] = [] + + self.children = {} + for child_data in self.data['children']: + child_type = child_data['type'] + child_id = child_data['id'] + if not known_declarations.HasType(child_type): + raise Exception('Unknown type "%s" for child "%s"' % + (child_type, child_id)) + self.children[child_id] = known_declarations.GetByType(child_type) + + self.fields = [FieldDeclaration(d) for d in self.data['context']] + fields_names = [field.name for field in self.fields] + if len(fields_names) > len(set(fields_names)): + raise Exception('Duplicate fields in declaration.') + self.known_declarations = known_declarations + except Declaration.InvalidDeclaration: + raise + except Exception as e: + raise Declaration.InvalidDeclaration(self.path, e.message) + + @property + def type(self): + return self.data['type'] + + @property + def strings(self): + return (string['name'] for string in self.data['strings']) + + @property + def events(self): + return (event['name'] for event in self.data['events']) + + @property + def webui_view_basename(self): + return self.type + '_web_ui_view' + + @property + def webui_view_h_name(self): + return self.webui_view_basename + '.h' + + @property + def webui_view_cc_name(self): + return self.webui_view_basename + '.cc' + + @property + def webui_view_include_path(self): + return os.path.join(os.path.dirname(self.path), self.webui_view_h_name) + + @property + def export_h_name(self): + return self.type + '_export.h' + + @property + def component_export_macro(self): + return "WUG_" + self.type.upper() + "_EXPORT" + + @property + def component_impl_macro(self): + return "WUG_" + self.type.upper() + "_IMPLEMENTATION" + + @property + def export_h_include_path(self): + return os.path.join(os.path.dirname(self.path), self.export_h_name) + + @property + def view_model_basename(self): + return self.type + '_view_model' + + @property + def view_model_h_name(self): + return self.view_model_basename + '.h' + + @property + def view_model_cc_name(self): + return self.view_model_basename + '.cc' + + @property + def view_model_include_path(self): + return os.path.join(os.path.dirname(self.path), self.view_model_h_name) + + @property + def html_view_basename(self): + return '%s-view' % self.type.replace('_', '-') + + @property + def html_view_html_name(self): + return self.html_view_basename + '.html' + + @property + def html_view_js_name(self): + return self.html_view_basename + '.js' + + @property + def html_view_html_include_path(self): + return os.path.join(os.path.dirname(self.path), self.html_view_html_name) + + @property + def html_view_js_include_path(self): + return os.path.join(os.path.dirname(self.path), self.html_view_js_name) + + @property + def build_target(self): + return self.type + "_wug_generated" + + @property + def webui_view_class(self): + return util.ToUpperCamelCase(self.type) + 'WebUIView' + + @property + def view_model_class(self): + return util.ToUpperCamelCase(self.type) + 'ViewModel' + + @property + def imports(self): + res = set(self.known_declarations.GetKnownPathes()) + res.remove(self.path) + return res + + +
diff --git a/components/webui_generator/generator/export_h.py b/components/webui_generator/generator/export_h.py new file mode 100644 index 0000000..3c4eceb9 --- /dev/null +++ b/components/webui_generator/generator/export_h.py
@@ -0,0 +1,66 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import datetime +import util +import os + +H_FILE_TEMPLATE = \ +"""// Copyright %(year)d 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. + +// NOTE: this file is generated from "%(source)s". Do not modify directly. + +#ifndef %(include_guard)s +#define %(include_guard)s + +#if defined(COMPONENT_BUILD) + +#if defined(WIN32) + +#if defined(%(impl_macro)s) +#define %(export_macro)s __declspec(dllexport) +#else +#define %(export_macro)s __declspec(dllimport) +#endif // defined(%(impl_macro)s) + +#else // defined(WIN32) + +#if defined(%(impl_macro)s) +#define %(export_macro)s __attribute__((visibility("default"))) +#else +#define %(export_macro)s +#endif // defined(%(impl_macro)s) + +#endif // defined(WIN32) + +#else // defined(COMPONENT_BUILD) + +#define %(export_macro)s + +#endif + +#endif // %(include_guard)s +""" + +def GenHFile(declaration): + subs = {} + subs['year'] = datetime.date.today().year + subs['source'] = declaration.path + subs['include_guard'] = util.PathToIncludeGuard( + declaration.export_h_include_path) + subs['export_macro'] = declaration.component_export_macro + subs['impl_macro'] = declaration.component_impl_macro + return H_FILE_TEMPLATE % subs + +def ListOutputs(declaration, destination): + dirname = os.path.join(destination, os.path.dirname(declaration.path)) + h_file_path = os.path.join(dirname, declaration.export_h_name) + return [h_file_path] + +def Gen(declaration, destination): + h_file_path = ListOutputs(declaration, destination)[0] + util.CreateDirIfNotExists(os.path.dirname(h_file_path)) + open(h_file_path, 'w').write(GenHFile(declaration))
diff --git a/components/webui_generator/generator/gen_sources.py b/components/webui_generator/generator/gen_sources.py new file mode 100644 index 0000000..6b9a87a --- /dev/null +++ b/components/webui_generator/generator/gen_sources.py
@@ -0,0 +1,27 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import os.path +import sys + +from declaration import Declaration +import export_h +import util +import view_model +import web_ui_view + +args = util.CreateArgumentParser().parse_args() +declaration_path = os.path.relpath(args.declaration, args.root) +destination = os.path.relpath(args.destination, args.root) +os.chdir(args.root) +try: + declaration = Declaration(declaration_path) +except Exception as e: + print >> sys.stderr, e.message + sys.exit(1) +view_model.Gen(declaration, destination) +web_ui_view.Gen(declaration, destination) +export_h.Gen(declaration, destination) +
diff --git a/components/webui_generator/generator/html_view.py b/components/webui_generator/generator/html_view.py new file mode 100644 index 0000000..73fc8a90 --- /dev/null +++ b/components/webui_generator/generator/html_view.py
@@ -0,0 +1,111 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import util +import os +import datetime + +HTML_FILE_TEMPLATE = \ +"""<!-- Copyright %(year)d 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. --> + +<!-- NOTE: this file is generated from "%(source)s". Do not modify directly. --> + +<!doctype html> +<html><head> +<link rel="import" href="chrome://resources/polymer/polymer/polymer.html"> +<link rel="import" href="/webui_generator/webui-view.html"> +%(children_includes)s +</head><body> +<polymer-element name="%(element_name)s" extends="webui-view"> +</polymer-element> +<script src="%(js_file_path)s"></script> +</body></html> +""" + +JS_FILE_TEMPLATE = \ +"""// Copyright %(year)d 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. + +// NOTE: this file is generated from "%(source)s". Do not modify directly. + + +Polymer('%(element_name)s', (function() { + 'use strict'; + return { + getType: function() { + return '%(type)s'; + }, + + initialize: function() {}, + contextChanged: function(changedKeys) {}, + + initChildren_: function() { +%(init_children_body)s + }, + + initContext_: function() { +%(init_context_body)s + } + } +})()); +""" + +def GetCommonSubistitutions(declaration): + subs = {} + subs['year'] = datetime.date.today().year + subs['element_name'] = declaration.type.replace('_', '-') + '-view' + subs['source'] = declaration.path + return subs + +def GenChildrenIncludes(children): + lines = [] + for declaration in set(children.itervalues()): + lines.append('<link rel="import" href="/%s">' % + declaration.html_view_html_include_path) + return '\n'.join(lines) + +def GenHTMLFile(declaration): + subs = GetCommonSubistitutions(declaration) + subs['js_file_path'] = subs['element_name'] + '.js' + subs['children_includes'] = GenChildrenIncludes(declaration.children) + return HTML_FILE_TEMPLATE % subs + +def GenInitChildrenBody(children): + lines = [] + lines.append(' var child = null;'); + for id in children: + lines.append(' child = this.shadowRoot.querySelector(\'[wugid="%s"]\');' + % id); + lines.append(' if (!child)'); + lines.append(' console.error(this.path_ + \'$%s not found.\');' % id); + lines.append(' else'); + lines.append(' child.setPath_(this.path_ + \'$%s\');' % id) + return '\n'.join(lines) + +def GenInitContextBody(fields): + lines = [] + for field in fields: + value = '' + if field.type in ['integer', 'double']: + value = str(field.default_value) + elif field.type == 'boolean': + value = 'true' if field.default_value else 'false' + elif field.type == 'string': + value = '\'%s\'' % field.default_value + elif field.type == 'string_list': + value = '[' + \ + ', '.join('\'%s\'' % s for s in field.default_value) + ']' + lines.append(' this.context.set(\'%s\', %s);' % (field.id, value)) + lines.append(' this.context.getChangesAndReset();') + return '\n'.join(lines) + +def GenJSFile(declaration): + subs = GetCommonSubistitutions(declaration) + subs['type'] = declaration.type + subs['init_children_body'] = GenInitChildrenBody(declaration.children) + subs['init_context_body'] = GenInitContextBody(declaration.fields) + return JS_FILE_TEMPLATE % subs
diff --git a/components/webui_generator/generator/util.py b/components/webui_generator/generator/util.py new file mode 100644 index 0000000..28a20db --- /dev/null +++ b/components/webui_generator/generator/util.py
@@ -0,0 +1,30 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import argparse +import os.path +import re + +def CreateArgumentParser(): + parser = argparse.ArgumentParser() + parser.add_argument('declaration', help='Path to declaration file.') + parser.add_argument('--root', default='.', help='Path to src/ dir.') + parser.add_argument('--destination', + help='Root directory for generated files.') + return parser + +def ToUpperCamelCase(underscore_name): + return re.sub(r'(?:_|^)(.)', lambda m: m.group(1).upper(), underscore_name) + +def ToLowerCamelCase(underscore_name): + return re.sub(r'_(.)', lambda m: m.group(1).upper(), underscore_name) + +def PathToIncludeGuard(path): + return re.sub(r'[/.]', '_', path.upper()) + '_' + +def CreateDirIfNotExists(path): + if not os.path.isdir(path): + if os.path.exists(path): + raise Exception('%s exists and is not a directory.' % path) + os.makedirs(path)
diff --git a/components/webui_generator/generator/view_model.py b/components/webui_generator/generator/view_model.py new file mode 100644 index 0000000..a920807 --- /dev/null +++ b/components/webui_generator/generator/view_model.py
@@ -0,0 +1,329 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import datetime +import util + +H_FILE_TEMPLATE = \ +"""// Copyright %(year)d 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. + +// NOTE: this file is generated from "%(source)s". Do not modify directly. + +#ifndef %(include_guard)s +#define %(include_guard)s + +#include "base/macros.h" +#include "components/webui_generator/view_model.h" +#include "%(export_h_include_path)s" + +namespace content { +class BrowserContext; +} + +%(children_forward_declarations)s + +namespace gen { + +class %(export_macro)s %(class_name)s : public ::webui_generator::ViewModel { + public: + using FactoryFunction = %(class_name)s* (*)(content::BrowserContext*); + +%(context_keys)s + + static %(class_name)s* Create(content::BrowserContext* context); + static void SetFactory(FactoryFunction factory); + + %(class_name)s(); + +%(children_getters)s + +%(context_getters)s + +%(event_handlers)s + + void Initialize() override {} + void OnAfterChildrenReady() override {} + void OnViewBound() override {} + + private: + void OnEvent(const std::string& event) final; + + static FactoryFunction factory_function_; +}; + +} // namespace gen + +#endif // %(include_guard)s +""" + +CHILD_FORWARD_DECLARATION_TEMPLATE = \ +"""namespace gen { + class %(child_type)s; +} +""" +CONTEXT_KEY_DECLARATION_TEMPLATE = \ +""" static const char %s[];""" + +CHILD_GETTER_DECLARATION_TEMPLATE = \ +""" virtual gen::%(child_type)s* %(method_name)s() const;"""; + +CONTEXT_VALUE_GETTER_DECLARATION_TEMPLATE = \ +""" %(type)s %(method_name)s() const;""" + +EVENT_HANDLER_DECLARATION_TEMPLATE = \ +""" virtual void %s() = 0;""" + +CC_FILE_TEMPLATE = \ +"""// Copyright %(year)d 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. + +// NOTE: this file is generated from "%(source)s". Do not modify directly. + +#include "%(header_path)s" + +#include "base/logging.h" +#include "components/webui_generator/view.h" +%(children_includes)s + +namespace gen { + +%(context_keys)s + +%(class_name)s::FactoryFunction %(class_name)s::factory_function_; + +%(class_name)s* %(class_name)s::Create(content::BrowserContext* context) { + CHECK(factory_function_) << "Factory function for %(class_name)s was not " + "set."; + return factory_function_(context); +} + +void %(class_name)s::SetFactory(FactoryFunction factory) { + factory_function_ = factory; +} + +%(class_name)s::%(class_name)s() { +%(constructor_body)s +} + +%(children_getters)s + +%(context_getters)s + +void %(class_name)s::OnEvent(const std::string& event) { +%(event_dispatcher_body)s + LOG(ERROR) << "Unknown event '" << event << "'"; +} + +} // namespace gen +""" + +CONTEXT_KEY_DEFINITION_TEMPLATE = \ +"""const char %(class_name)s::%(name)s[] = "%(value)s";""" + +CHILD_GETTER_DEFINITION_TEMPLATE = \ +"""gen::%(child_type)s* %(class_name)s::%(method_name)s() const { + return static_cast<gen::%(child_type)s*>( + view()->GetChild("%(child_id)s")->GetViewModel()); +} +""" + +CONTEXT_VALUE_GETTER_DEFINITION_TEMPLATE = \ +"""%(type)s %(class_name)s::%(method_name)s() const { + return context().%(context_getter)s(%(key_constant)s); +} +""" + +FIELD_TYPE_TO_GETTER_TYPE = { + 'boolean': 'bool', + 'integer': 'int', + 'double': 'double', + 'string': 'std::string', + 'string_list': 'login::StringList' +} + +DISPATCH_EVENT_TEMPLATE = \ +""" if (event == "%(event_id)s") { + %(method_name)s(); + return; + }""" + +def GetCommonSubistitutions(declaration): + subs = {} + subs['year'] = datetime.date.today().year + subs['class_name'] = declaration.view_model_class + subs['source'] = declaration.path + return subs + +def FieldNameToConstantName(field_name): + return 'kContextKey' + util.ToUpperCamelCase(field_name) + +def GenContextKeysDeclarations(fields): + return '\n'.join( + (CONTEXT_KEY_DECLARATION_TEMPLATE % \ + FieldNameToConstantName(f.name) for f in fields)) + +def GenChildrenForwardDeclarations(children): + lines = [] + for declaration in set(children.itervalues()): + lines.append(CHILD_FORWARD_DECLARATION_TEMPLATE % { + 'child_type': declaration.view_model_class + }) + return '\n'.join(lines) + +def ChildIdToChildGetterName(id): + return 'Get%s' % util.ToUpperCamelCase(id) + +def GenChildrenGettersDeclarations(children): + lines = [] + for id, declaration in children.iteritems(): + lines.append(CHILD_GETTER_DECLARATION_TEMPLATE % { + 'child_type': declaration.view_model_class, + 'method_name': ChildIdToChildGetterName(id) + }) + return '\n'.join(lines) + +def FieldNameToGetterName(field_name): + return 'Get%s' % util.ToUpperCamelCase(field_name) + +def GenContextGettersDeclarations(context_fields): + lines = [] + for field in context_fields: + lines.append(CONTEXT_VALUE_GETTER_DECLARATION_TEMPLATE % { + 'type': FIELD_TYPE_TO_GETTER_TYPE[field.type], + 'method_name': FieldNameToGetterName(field.name) + }) + return '\n'.join(lines) + +def EventIdToMethodName(event): + return 'On' + util.ToUpperCamelCase(event) + +def GenEventHandlersDeclarations(events): + lines = [] + for event in events: + lines.append(EVENT_HANDLER_DECLARATION_TEMPLATE % + EventIdToMethodName(event)) + return '\n'.join(lines) + +def GenHFile(declaration): + subs = GetCommonSubistitutions(declaration) + subs['include_guard'] = \ + util.PathToIncludeGuard(declaration.view_model_include_path) + subs['context_keys'] = GenContextKeysDeclarations(declaration.fields) + subs['children_forward_declarations'] = \ + GenChildrenForwardDeclarations(declaration.children) + subs['children_getters'] = \ + GenChildrenGettersDeclarations(declaration.children); + subs['context_getters'] = \ + GenContextGettersDeclarations(declaration.fields); + subs['event_handlers'] = GenEventHandlersDeclarations(declaration.events) + subs['export_h_include_path'] = declaration.export_h_include_path + subs['export_macro'] = declaration.component_export_macro + return H_FILE_TEMPLATE % subs + +def GenContextKeysDefinitions(declaration): + lines = [] + for field in declaration.fields: + definition = CONTEXT_KEY_DEFINITION_TEMPLATE % { + 'class_name': declaration.view_model_class, + 'name': FieldNameToConstantName(field.name), + 'value': field.id + } + lines.append(definition) + return '\n'.join(lines) + +def GenChildrenIncludes(children): + lines = [] + for declaration in set(children.itervalues()): + lines.append('#include "%s"' % declaration.view_model_include_path) + return '\n'.join(lines) + +def GenContextFieldInitialization(field): + lines = [] + key_constant = FieldNameToConstantName(field.name) + setter_method = 'Set' + util.ToUpperCamelCase(field.type) + if field.type == 'string_list': + lines.append(' {') + lines.append(' std::vector<std::string> defaults;') + for s in field.default_value: + lines.append(' defaults.push_back("%s");' % s) + lines.append(' context().%s(%s, defaults);' % + (setter_method, key_constant)) + lines.append(' }') + else: + setter = ' context().%s(%s, ' % (setter_method, key_constant) + if field.type in ['integer', 'double']: + setter += str(field.default_value) + elif field.type == 'boolean': + setter += 'true' if field.default_value else 'false' + else: + assert field.type == 'string' + setter += '"%s"' % field.default_value + setter += ");" + lines.append(setter) + return '\n'.join(lines) + +def GenChildrenGettersDefenitions(declaration): + lines = [] + for id, child in declaration.children.iteritems(): + lines.append(CHILD_GETTER_DEFINITION_TEMPLATE % { + 'child_type': child.view_model_class, + 'class_name': declaration.view_model_class, + 'method_name': ChildIdToChildGetterName(id), + 'child_id': id + }); + return '\n'.join(lines) + +def GenContextGettersDefinitions(declaration): + lines = [] + for field in declaration.fields: + lines.append(CONTEXT_VALUE_GETTER_DEFINITION_TEMPLATE % { + 'type': FIELD_TYPE_TO_GETTER_TYPE[field.type], + 'class_name': declaration.view_model_class, + 'method_name': FieldNameToGetterName(field.name), + 'context_getter': 'Get' + util.ToUpperCamelCase( + field.type), + 'key_constant': FieldNameToConstantName(field.name) + }); + return '\n'.join(lines) + +def GenEventDispatcherBody(events): + lines = [] + for event in events: + lines.append(DISPATCH_EVENT_TEMPLATE % { + 'event_id': util.ToLowerCamelCase(event), + 'method_name': EventIdToMethodName(event) + }); + return '\n'.join(lines) + +def GenCCFile(declaration): + subs = GetCommonSubistitutions(declaration) + subs['header_path'] = declaration.view_model_include_path + subs['context_keys'] = GenContextKeysDefinitions(declaration) + subs['children_includes'] = GenChildrenIncludes(declaration.children) + initializations = [GenContextFieldInitialization(field) \ + for field in declaration.fields] + initializations.append(' base::DictionaryValue diff;'); + initializations.append(' context().GetChangesAndReset(&diff);'); + subs['constructor_body'] = '\n'.join(initializations) + subs['children_getters'] = GenChildrenGettersDefenitions(declaration) + subs['context_getters'] = GenContextGettersDefinitions(declaration) + subs['event_dispatcher_body'] = GenEventDispatcherBody(declaration.events) + return CC_FILE_TEMPLATE % subs + +def ListOutputs(declaration, destination): + dirname = os.path.join(destination, os.path.dirname(declaration.path)) + h_file_path = os.path.join(dirname, declaration.view_model_h_name) + cc_file_path = os.path.join(dirname, declaration.view_model_cc_name) + return [h_file_path, cc_file_path] + +def Gen(declaration, destination): + h_file_path, cc_file_path = ListOutputs(declaration, destination) + util.CreateDirIfNotExists(os.path.dirname(h_file_path)) + open(h_file_path, 'w').write(GenHFile(declaration)) + open(cc_file_path, 'w').write(GenCCFile(declaration)) +
diff --git a/components/webui_generator/generator/web_ui_view.py b/components/webui_generator/generator/web_ui_view.py new file mode 100644 index 0000000..f534caef --- /dev/null +++ b/components/webui_generator/generator/web_ui_view.py
@@ -0,0 +1,205 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import datetime +import json +import os +import os.path +import util +import html_view + +H_FILE_TEMPLATE = \ +"""// Copyright %(year)d 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. + +// NOTE: this file is generated from "%(source)s". Do not modify directly. + +#ifndef %(include_guard)s +#define %(include_guard)s + +#include "base/macros.h" +#include "components/webui_generator/web_ui_view.h" +#include "%(export_h_include_path)s" + +namespace gen { + +class %(export_macro)s %(class_name)s : public ::webui_generator::WebUIView { + public: + %(class_name)s(content::WebUI* web_ui); + %(class_name)s(content::WebUI* web_ui, const std::string& id); + + protected: + void AddLocalizedValues(::login::LocalizedValuesBuilder* builder) override; + void AddResources(ResourcesMap* resources_map) override; + void CreateAndAddChildren() override; + ::webui_generator::ViewModel* CreateViewModel() override; + std::string GetType() override; + + private: + DISALLOW_COPY_AND_ASSIGN(%(class_name)s); +}; + +} // namespace gen + +#endif // %(include_guard)s +""" + +CC_FILE_TEMPLATE = \ +"""// Copyright %(year)d 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. + +// NOTE: this file is generated from "%(source)s". Do not modify directly. + +#include "%(header_path)s" + +#include "content/public/browser/web_ui_data_source.h" +#include "content/public/browser/web_contents.h" +#include "components/login/localized_values_builder.h" +#include "grit/components_strings.h" +%(includes)s + +namespace { + +const char kHTMLDoc[] = "%(html_doc)s"; +const char kJSDoc[] = "%(js_doc)s"; + +} // namespace + +namespace gen { + +%(class_name)s::%(class_name)s(content::WebUI* web_ui) + : webui_generator::WebUIView(web_ui, "WUG_ROOT") { +} + +%(class_name)s::%(class_name)s(content::WebUI* web_ui, const std::string& id) + : webui_generator::WebUIView(web_ui, id) { +} + +void %(class_name)s::AddLocalizedValues( + ::login::LocalizedValuesBuilder* builder) { +%(add_localized_values_body)s +} + +void %(class_name)s::AddResources(ResourcesMap* resources_map) { +%(add_resources_body)s +} + +void %(class_name)s::CreateAndAddChildren() { +%(create_and_add_children_body)s +} + +::webui_generator::ViewModel* %(class_name)s::CreateViewModel() { +%(create_view_model_body)s +} + +std::string %(class_name)s::GetType() { +%(get_type_body)s +} + +} // namespace gen +""" + +ADD_LOCALIZED_VALUE_TEMPLATE = \ +""" builder->Add("%(string_name)s", %(resource_id)s);""" + +ADD_RESOURCE_TEMPLATE = \ +""" (*resources_map)["%(path)s"] = scoped_refptr<base::RefCountedMemory>( + new base::RefCountedStaticMemory(%(const)s, arraysize(%(const)s) - 1));""" + +CREATE_AND_ADD_CHILD_TEMPLATE = \ +""" AddChild(new gen::%(child_class)s(web_ui(), "%(child_id)s"));""" + +CREATE_VIEW_MODEL_BODY_TEMPLATE = \ +""" return gen::%s::Create(web_ui()->GetWebContents()->GetBrowserContext());""" + +def GetCommonSubistitutions(declaration): + subs = {} + subs['year'] = datetime.date.today().year + subs['class_name'] = declaration.webui_view_class + subs['source'] = declaration.path + return subs + + +def GenHFile(declaration): + subs = GetCommonSubistitutions(declaration) + subs['include_guard'] = util.PathToIncludeGuard( + declaration.webui_view_include_path) + subs['export_h_include_path'] = declaration.export_h_include_path + subs['export_macro'] = declaration.component_export_macro + return H_FILE_TEMPLATE % subs + +def GenIncludes(declaration): + lines = [] + lines.append('#include "%s"' % declaration.view_model_include_path) + children_declarations = set(declaration.children.itervalues()) + for child in children_declarations: + lines.append('#include "%s"' % child.webui_view_include_path) + return '\n'.join(lines) + +def GenAddLocalizedValuesBody(declaration): + lines = [] + resource_id_prefix = "IDS_WUG_" + declaration.type.upper() + "_" + for name in declaration.strings: + resource_id = resource_id_prefix + name.upper() + subs = { + 'string_name': util.ToLowerCamelCase(name), + 'resource_id': resource_id + } + lines.append(ADD_LOCALIZED_VALUE_TEMPLATE % subs) + return '\n'.join(lines) + +def GenAddResourcesBody(declaration): + lines = [] + html_path = declaration.html_view_html_include_path + lines.append(ADD_RESOURCE_TEMPLATE % { 'path': html_path, + 'const': 'kHTMLDoc' }) + js_path = declaration.html_view_js_include_path + lines.append(ADD_RESOURCE_TEMPLATE % { 'path': js_path, + 'const': 'kJSDoc' }) + return '\n'.join(lines) + +def GenCreateAndAddChildrenBody(children): + lines = [] + for id, declaration in children.iteritems(): + subs = { + 'child_class': declaration.webui_view_class, + 'child_id': id + } + lines.append(CREATE_AND_ADD_CHILD_TEMPLATE % subs) + return '\n'.join(lines) + +def EscapeStringForCLiteral(string): + return json.dumps(string)[1:][:-1] + +def GenCCFile(declaration): + subs = GetCommonSubistitutions(declaration) + subs['header_path'] = declaration.webui_view_include_path + subs['includes'] = GenIncludes(declaration) + subs['add_localized_values_body'] = \ + GenAddLocalizedValuesBody(declaration) + subs['add_resources_body'] = \ + GenAddResourcesBody(declaration) + subs['create_and_add_children_body'] = \ + GenCreateAndAddChildrenBody(declaration.children) + subs['create_view_model_body'] = \ + CREATE_VIEW_MODEL_BODY_TEMPLATE % declaration.view_model_class + subs['get_type_body'] = ' return "%s";' % declaration.type + subs['html_doc'] = EscapeStringForCLiteral(html_view.GenHTMLFile(declaration)) + subs['js_doc'] = EscapeStringForCLiteral(html_view.GenJSFile(declaration)) + return CC_FILE_TEMPLATE % subs + +def ListOutputs(declaration, destination): + dirname = os.path.join(destination, os.path.dirname(declaration.path)) + h_file_path = os.path.join(dirname, declaration.webui_view_h_name) + cc_file_path = os.path.join(dirname, declaration.webui_view_cc_name) + return [h_file_path, cc_file_path] + +def Gen(declaration, destination): + h_file_path, cc_file_path = ListOutputs(declaration, destination) + util.CreateDirIfNotExists(os.path.dirname(h_file_path)) + open(h_file_path, 'w').write(GenHFile(declaration)) + open(cc_file_path, 'w').write(GenCCFile(declaration)) +
diff --git a/components/webui_generator/generator/wug.gni b/components/webui_generator/generator/wug.gni new file mode 100644 index 0000000..28009a0 --- /dev/null +++ b/components/webui_generator/generator/wug.gni
@@ -0,0 +1,112 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Generates native and HTML/JS supporting code for Web UI element from element's +# declaration JSON file. +# +# Parameters: +# +# source (required) +# declaration file. +# +# Example: +# wug("some_type_wug_generated") { +# source = "some_type.json" +# } +# +# Target's name should be deduced from declaration file name by removing +# extension and adding '_wug_generated' prefix. This is needed to properly +# handle dependencies between declaration files and their imports. +# +# For declaration file with a full path 'src/full/path/some_type.json' 5 files +# will be generated and compiled: +# $root_gen_dir/wug/full/path/some_type_export.h +# $root_gen_dir/wug/full/path/some_type_view.h +# $root_gen_dir/wug/full/path/some_type_view_model.cc +# $root_gen_dir/wug/full/path/some_type_view_model.h +# $root_gen_dir/wug/full/path/some_type_webui_view.cc + +template("wug") { + declaration_path = invoker.source + generator_dir = "//components/webui_generator/generator" + generator_path = "$generator_dir/gen_sources.py" + src_root = rebase_path("//", root_build_dir) + + helper_path = "$generator_dir/build_helper.py" + target_name = "${target_name}" + action_name = target_name + "_gen" + out_dir = "$root_gen_dir/wug" + + helper_args = [ + rebase_path(declaration_path, root_build_dir), + "--destination", + rebase_path(out_dir, root_build_dir), + "--root", + src_root, + "--gn", + "--output", + ] + + expected_target_name = + exec_script(helper_path, helper_args + [ "target_name" ], "trim string") + assert(target_name == expected_target_name, + "Wrong target name. " + "Expected '" + expected_target_name + + "', got '" + target_name + "'.") + + action(action_name) { + script = generator_path + sources = [ + "$generator_dir/declaration.py", + "$generator_dir/export_h.py", + "$generator_dir/html_view.py", + "$generator_dir/util.py", + "$generator_dir/view_model.py", + "$generator_dir/web_ui_view.py", + ] + inputs = [ + declaration_path, + ] + inputs += + exec_script(helper_path, helper_args + [ "imports" ], "list lines") + common_prefix = process_file_template( + [ declaration_path ], + "$out_dir/{{source_root_relative_dir}}/{{source_name_part}}_") + common_prefix = common_prefix[0] + outputs = [ + common_prefix + "export.h", + common_prefix + "view_model.h", + common_prefix + "view_model.cc", + common_prefix + "web_ui_view.h", + common_prefix + "web_ui_view.cc", + ] + args = [ + rebase_path(declaration_path, root_build_dir), + "--root", + src_root, + "--destination", + rebase_path(out_dir, root_build_dir), + ] + } + + component(target_name) { + sources = get_target_outputs(":$action_name") + defines = [ exec_script(helper_path, + helper_args + [ "impl_macro" ], + "trim string") ] + deps = [ + "//base", + "//components/login", + "//components/strings", + ] + deps += exec_script(helper_path, + helper_args + [ "import_dependencies" ], + "list lines") + public_deps = [ + "//components/webui_generator", + ] + + all_dependent_configs = + [ "//components/webui_generator:wug_generated_config" ] + } +}
diff --git a/components/webui_generator/generator/wug.gypi b/components/webui_generator/generator/wug.gypi new file mode 100644 index 0000000..a40577c --- /dev/null +++ b/components/webui_generator/generator/wug.gypi
@@ -0,0 +1,118 @@ +# Copyright (c) 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file included into a targets definition creates a target that generates +# native and HTML/JS supporting code for Web UI element from element's +# declaration JSON file. +# +# Example: +# 'targets': [ +# ... +# { +# 'variables': { +# 'declaration_file': 'path/to/file.json' +# } +# 'includes': ['path/to/this/file.gypi'] +# }, +# ... +# ] +# +# Such inclusion creates a target, which name is deduced from declaration file +# name by removing extension and adding '_wug_generated' prefix, e.g. for +# declaration file named 'some_type.json' will be created target named +# 'some_type_wug_generated'. This is needed to properly handle dependencies +# between declaration files and their imports. +# +# For declaration file with a full path 'src/full/path/some_type.json' 5 files +# will be generated and compiled: +# <(SHARED_INTERMEDIATE_DIR)/wug/full/path/some_type_export.h +# <(SHARED_INTERMEDIATE_DIR)/wug/full/path/some_type_view.h +# <(SHARED_INTERMEDIATE_DIR)/wug/full/path/some_type_view_model.cc +# <(SHARED_INTERMEDIATE_DIR)/wug/full/path/some_type_view_model.h +# <(SHARED_INTERMEDIATE_DIR)/wug/full/path/some_type_webui_view.cc + +{ + 'variables': { + 'generator_dir': '<(DEPTH)/components/webui_generator/generator', + 'helper_path': '<(generator_dir)/build_helper.py', + 'generator_path': '<(generator_dir)/gen_sources.py', + 'out_dir': '<(SHARED_INTERMEDIATE_DIR)/wug', + 'helper_cl': 'python <(helper_path) --root=<(DEPTH) <(declaration_file)', + 'dirname': '<(out_dir)/<!(<(helper_cl) --output=dirname)', + 'view_cc': '<(dirname)/<!(<(helper_cl) --output=view_cc)', + 'view_h': '<(dirname)/<!(<(helper_cl) --output=view_h)', + 'model_cc': '<(dirname)/<!(<(helper_cl) --output=model_cc)', + 'model_h': '<(dirname)/<!(<(helper_cl) --output=model_h)', + 'export_h': '<(dirname)/<!(<(helper_cl) --output=export_h)', + 'export_h': '<(dirname)/<!(<(helper_cl) --output=export_h)', + 'impl_macro': '<!(<(helper_cl) --output=impl_macro)', + }, + 'target_name': '<!(<(helper_cl) --output=target_name)', + 'type': '<(component)', + 'sources': [ + '<(view_cc)', + '<(view_h)', + '<(model_cc)', + '<(model_h)', + '<(export_h)', + ], + 'defines': [ + '<(impl_macro)', + ], + 'actions': [ + { + 'action_name': 'gen_files', + 'inputs': [ + '<(generator_path)', + '<(generator_dir)/declaration.py', + '<(generator_dir)/export_h.py', + '<(generator_dir)/html_view.py', + '<(generator_dir)/util.py', + '<(generator_dir)/view_model.py', + '<(generator_dir)/web_ui_view.py', + '<(declaration_file)', + ], + 'outputs': [ + '<(view_cc)', + '<(view_h)', + '<(model_cc)', + '<(model_h)', + '<(export_h)', + ], + 'action': [ + 'python', + '<(generator_path)', + '--root=<(DEPTH)', + '--destination=<(out_dir)', + '<(declaration_file)' + ], + 'message': 'Generating C++ code from <(declaration_file).', + }, + ], + 'dependencies': [ + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/components/components.gyp:login', + '<(DEPTH)/components/components.gyp:webui_generator', + '<(DEPTH)/components/components_strings.gyp:components_strings', + '<(DEPTH)/skia/skia.gyp:skia', + '<!@(<(helper_cl) --output=import_dependencies)', + ], + 'include_dirs': [ + '<(DEPTH)', + '<(out_dir)', + ], + 'all_dependent_settings': { + 'include_dirs': [ + '<(DEPTH)', + '<(out_dir)', + ], + }, + 'export_dependent_settings': [ + '<(DEPTH)/components/components.gyp:webui_generator', + '<(DEPTH)/components/components.gyp:login', + ], + # This target exports a hard dependency because it generates header + # files. + 'hard_dependency': 1, +}
diff --git a/components/webui_generator/resources/context.html b/components/webui_generator/resources/context.html new file mode 100644 index 0000000..e1631b2 --- /dev/null +++ b/components/webui_generator/resources/context.html
@@ -0,0 +1,5 @@ +<!-- Copyright 2015 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> +<script src="context.js"></script> +
diff --git a/components/webui_generator/resources/context.js b/components/webui_generator/resources/context.js new file mode 100644 index 0000000..0bd28f1 --- /dev/null +++ b/components/webui_generator/resources/context.js
@@ -0,0 +1,21 @@ +// 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. + +(function(global) { + var has_cr = !!global.cr; + var cr_define_bckp = null; + if (has_cr && global.cr.define) + cr_define_bckp = global.cr.define; + if (!has_cr) + global.cr = {} + global.cr.define = function(_, define) { + global.wug = global.wug || {} + global.wug.Context = define().ScreenContext; + } +<include src="../../../chrome/browser/resources/chromeos/login/screen_context.js"> + if (!has_cr) + delete global.cr; + if (cr_define_bckp) + global.cr.define = cr_define_bckp; +})(this);
diff --git a/components/webui_generator/resources/webui-view.html b/components/webui_generator/resources/webui-view.html new file mode 100644 index 0000000..b07fa5c3 --- /dev/null +++ b/components/webui_generator/resources/webui-view.html
@@ -0,0 +1,10 @@ +<!-- Copyright 2015 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<link rel="import" href="chrome://resources/polymer/polymer/polymer.html"> +<link rel="import" href="context.html"> + +<polymer-element name="webui-view"></polymer-element> +<script src="webui-view.js"></script> +
diff --git a/components/webui_generator/resources/webui-view.js b/components/webui_generator/resources/webui-view.js new file mode 100644 index 0000000..99a033f --- /dev/null +++ b/components/webui_generator/resources/webui-view.js
@@ -0,0 +1,189 @@ +// 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. + +Polymer('webui-view', (function() { + /** @const */ var CALLBACK_CONTEXT_CHANGED = 'contextChanged'; + /** @const */ var CALLBACK_READY = 'ready'; + + return { + /** @const */ + CALLBACK_EVENT_FIRED: 'eventFired', + + /** + * Dictionary of context observers that are methods of |this| bound to + * |this|. + */ + contextObservers_: null, + + /** + * Full path to the element in views hierarchy. + */ + path_: null, + + /** + * Whether DOM is ready. + */ + domReady_: false, + + /** + * Context used for sharing data with native backend. + */ + context: null, + + /** + * Internal storage of |this.context|. + * |C| bound to the native part of the context, that means that all the + * changes in the native part appear in |C| automatically. Reverse is not + * true, you should use: + * this.context.set(...); + * this.context.commitContextChanges(); + * to send updates to the native part. + */ + C: null, + + ready: function() { + this.context = new wug.Context; + this.C = this.context.storage_; + this.contextObservers_ = {}; + }, + + /** + * One of element's lifecycle methods. + */ + domReady: function() { + var id = this.getAttribute('wugid'); + if (!id) { + console.error('"wugid" attribute is missing.'); + return; + } + if (id == 'WUG_ROOT') + this.setPath_('WUG_ROOT'); + this.domReady_ = true; + if (this.path_) + this.init_(); + }, + + setPath_: function(path) { + this.path_ = path; + if (this.domReady_) + this.init_(); + }, + + init_: function() { + this.initContext_(); + this.initChildren_(); + window[this.path_ + '$contextChanged'] = + this.onContextChanged_.bind(this); + this.initialize(); + this.send(CALLBACK_READY); + }, + + fireEvent: function(_, _, source) { + this.send(this.CALLBACK_EVENT_FIRED, source.getAttribute('event')); + }, + + i18n: function(args) { + if (!(args instanceof Array)) + args = [args]; + args[0] = this.getType() + '$' + args[0]; + return loadTimeData.getStringF.apply(loadTimeData, args); + }, + + /** + * Sends message to Chrome, adding needed prefix to message name. All + * arguments after |messageName| are packed into message parameters list. + * + * @param {string} messageName Name of message without a prefix. + * @param {...*} varArgs parameters for message. + * @private + */ + send: function(messageName, varArgs) { + if (arguments.length == 0) + throw Error('Message name is not provided.'); + var fullMessageName = this.path_ + '$' + messageName; + var payload = Array.prototype.slice.call(arguments, 1); + chrome.send(fullMessageName, payload); + }, + + /** + * Starts observation of property with |key| of the context attached to + * current screen. In contrast with "wug.Context.addObserver" this method + * can automatically detect if observer is method of |this| and make + * all needed actions to make it work correctly. So there is no need in + * binding method to |this| before adding it. For example, if |this| has + * a method |onKeyChanged_|, you can do: + * + * this.addContextObserver('key', this.onKeyChanged_); + * ... + * this.removeContextObserver('key', this.onKeyChanged_); + * + * instead of: + * + * this.keyObserver_ = this.onKeyChanged_.bind(this); + * this.addContextObserver('key', this.keyObserver_); + * ... + * this.removeContextObserver('key', this.keyObserver_); + * + * @private + */ + addContextObserver: function(key, observer) { + var realObserver = observer; + var propertyName = this.getPropertyNameOf_(observer); + if (propertyName) { + if (!this.contextObservers_.hasOwnProperty(propertyName)) + this.contextObservers_[propertyName] = observer.bind(this); + realObserver = this.contextObservers_[propertyName]; + } + this.context.addObserver(key, realObserver); + }, + + /** + * Removes |observer| from the list of context observers. Observer could be + * a method of |this| (see comment to |addContextObserver|). + * @private + */ + removeContextObserver: function(observer) { + var realObserver = observer; + var propertyName = this.getPropertyNameOf_(observer); + if (propertyName) { + if (!this.contextObservers_.hasOwnProperty(propertyName)) + return; + realObserver = this.contextObservers_[propertyName]; + delete this.contextObservers_[propertyName]; + } + this.context.removeObserver(realObserver); + }, + + /** + * Sends recent context changes to C++ handler. + * @private + */ + commitContextChanges: function() { + if (!this.context.hasChanges()) + return; + this.send(CALLBACK_CONTEXT_CHANGED, this.context.getChangesAndReset()); + }, + + /** + * Called when context changed on C++ side. + */ + onContextChanged_: function(diff) { + var changedKeys = this.context.applyChanges(diff); + this.contextChanged(changedKeys); + }, + + /** + * If |value| is the value of some property of |this| returns property's + * name. Otherwise returns empty string. + * @private + */ + getPropertyNameOf_: function(value) { + for (var key in this) + if (this[key] === value) + return key; + return ''; + } + }; +})()); +
diff --git a/components/webui_generator/view.cc b/components/webui_generator/view.cc new file mode 100644 index 0000000..a335ef5 --- /dev/null +++ b/components/webui_generator/view.cc
@@ -0,0 +1,102 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/webui_generator/view.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "components/webui_generator/view_model.h" + +namespace webui_generator { + +View::View(const std::string& id) + : parent_(NULL), + id_(id), + ready_children_(0), + view_model_ready_(false), + ready_(false), + weak_factory_(this) { +} + +View::~View() { +} + +void View::Init() { + CreateAndAddChildren(); + + if (!IsRootView()) + path_ = parent_->path() + "$"; + + path_ += id_; + view_model_.reset(CreateViewModel()); + view_model_->SetView(this); + + for (auto& id_child : children_) + id_child.second->Init(); + + if (children_.empty()) + OnChildrenReady(); +} + +bool View::IsRootView() const { + return !parent_; +} + +ViewModel* View::GetViewModel() const { + return view_model_.get(); +} + +void View::OnViewModelReady() { + view_model_ready_ = true; + if (ready_children_ == static_cast<int>(children_.size())) + OnReady(); +} + +View* View::GetChild(const std::string& id) const { + auto it = children_.find(id); + if (it == children_.end()) + return nullptr; + + return it->second; +} + +void View::OnReady() { + if (ready_) + return; + + ready_ = true; + if (!IsRootView()) + parent_->OnChildReady(this); +} + +void View::UpdateContext(const base::DictionaryValue& diff) { + DCHECK(ready_); + view_model_->UpdateContext(diff); +} + +void View::HandleEvent(const std::string& event) { + DCHECK(ready_); + view_model_->OnEvent(event); +} + +void View::AddChild(View* child) { + DCHECK(children_.find(child->id()) == children_.end()); + DCHECK(!child->id().empty()); + children_.set(child->id(), make_scoped_ptr(child)); + child->set_parent(this); +} + +void View::OnChildReady(View* child) { + ++ready_children_; + if (ready_children_ == static_cast<int>(children_.size())) + OnChildrenReady(); +} + +void View::OnChildrenReady() { + view_model_->OnChildrenReady(); + if (view_model_ready_) + OnReady(); +} + +} // namespace webui_generator
diff --git a/components/webui_generator/view.h b/components/webui_generator/view.h new file mode 100644 index 0000000..b43ad74 --- /dev/null +++ b/components/webui_generator/view.h
@@ -0,0 +1,116 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_WUG_VIEW_H_ +#define CHROME_BROWSER_UI_WEBUI_WUG_VIEW_H_ + +#include "base/containers/scoped_ptr_hash_map.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "components/webui_generator/export.h" + +namespace base { +class DictionaryValue; +} + +namespace webui_generator { + +class ViewModel; + +/** + * Base block of Web UI (in terms of Web UI Generator). Every View instance is + * associated with single ViewModel instance which provides a context for the + * view. Views are hierarchical. Every child of view has an unique id. + */ +class WUG_EXPORT View { + public: + explicit View(const std::string& id); + virtual ~View(); + + // Should be called before using the view. This method creates children (using + // CreateAndAddChildren() method) and a view-model (using CreateViewModel() + // method). Then it recursively calls Init() for the children. When + // all the children and the view-model are ready, OnReady() method is called. + // Overridden methods should call the base implementation. + virtual void Init(); + + // Root view is a view without parent. + // Root view should have id equal to "WUG_ROOT". + bool IsRootView() const; + + ViewModel* GetViewModel() const; + + // Called by view-model when it is ready. + void OnViewModelReady(); + + const std::string& id() const { return id_; } + + // Every view has an unique path in a view hierarchy which is: + // a) |id| for the root view; + // b) concatenation of parent's path, $-sign and |id| for not-root views. + const std::string& path() const { return path_; } + + // Returns a child with a given |id|. Returns |nullptr| if such child doesn't + // exist. + View* GetChild(const std::string& id) const; + + // Called by view-model when it changes the context. + virtual void OnContextChanged(const base::DictionaryValue& diff) = 0; + + protected: + // Called when view is ready, which means view-model and all children are + // ready. Overridden methods should call the base implementation. + virtual void OnReady(); + + // Forwards context changes stored in |diff| to view-model. + void UpdateContext(const base::DictionaryValue& diff); + + // Forwards |event| to view-model. + void HandleEvent(const std::string& event); + + bool ready() const { return ready_; } + + base::ScopedPtrHashMap<std::string, View>& children() { return children_; } + + // Adds |child| to the list of children of |this|. Can be called only from + // CreateAndAddChildren() override. + void AddChild(View* child); + + virtual std::string GetType() = 0; + + // Implementation should create an instance of view-model for this view. + virtual ViewModel* CreateViewModel() = 0; + + // Implementation should create and add children to |this| view. This method + // is an only place where it is allowed to add children. + virtual void CreateAndAddChildren() = 0; + + private: + // Called by |child| view, when it is ready. + void OnChildReady(View* child); + + // Called when all the children created by CreatedAndAddChildren() are ready. + void OnChildrenReady(); + + void set_parent(View* parent) { parent_ = parent; } + + View* parent_; + std::string id_; + std::string path_; + + // Number of child views that are ready. + int ready_children_; + + bool view_model_ready_; + bool ready_; + base::ScopedPtrHashMap<std::string, View> children_; + scoped_ptr<ViewModel> view_model_; + base::WeakPtrFactory<View> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(View); +}; + +} // namespace webui_generator + +#endif // CHROME_BROWSER_UI_WEBUI_WUG_VIEW_H_
diff --git a/components/webui_generator/view_model.cc b/components/webui_generator/view_model.cc new file mode 100644 index 0000000..d81ce98 --- /dev/null +++ b/components/webui_generator/view_model.cc
@@ -0,0 +1,106 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/webui_generator/view_model.h" + +#include "components/webui_generator/view.h" + +namespace webui_generator { + +ViewModel::ContextEditor::ContextEditor(ViewModel& view_model) + : view_model_(view_model), context_(view_model_.context()) { +} + +ViewModel::ContextEditor::~ContextEditor() { + view_model_.CommitContextChanges(); +} + +const ViewModel::ContextEditor& ViewModel::ContextEditor::SetBoolean( + const KeyType& key, + bool value) const { + context_.SetBoolean(key, value); + return *this; +} + +const ViewModel::ContextEditor& ViewModel::ContextEditor::SetInteger( + const KeyType& key, + int value) const { + context_.SetInteger(key, value); + return *this; +} + +const ViewModel::ContextEditor& ViewModel::ContextEditor::SetDouble( + const KeyType& key, + double value) const { + context_.SetDouble(key, value); + return *this; +} + +const ViewModel::ContextEditor& ViewModel::ContextEditor::SetString( + const KeyType& key, + const std::string& value) const { + context_.SetString(key, value); + return *this; +} + +const ViewModel::ContextEditor& ViewModel::ContextEditor::SetString( + const KeyType& key, + const base::string16& value) const { + context_.SetString(key, value); + return *this; +} + +const ViewModel::ContextEditor& ViewModel::ContextEditor::SetStringList( + const KeyType& key, + const StringList& value) const { + context_.SetStringList(key, value); + return *this; +} + +const ViewModel::ContextEditor& ViewModel::ContextEditor::SetString16List( + const KeyType& key, + const String16List& value) const { + context_.SetString16List(key, value); + return *this; +} + +ViewModel::ViewModel() : view_(nullptr) { +} + +ViewModel::~ViewModel() { +} + +void ViewModel::SetView(View* view) { + view_ = view; + Initialize(); +} + +void ViewModel::OnChildrenReady() { + OnAfterChildrenReady(); + view_->OnViewModelReady(); +} + +void ViewModel::UpdateContext(const base::DictionaryValue& diff) { + std::vector<std::string> changed_keys; + context_.ApplyChanges(diff, &changed_keys); + OnContextChanged(changed_keys); +} + +void ViewModel::OnEvent(const std::string& event) { +} + +ViewModel::ContextEditor ViewModel::GetContextEditor() { + return ContextEditor(*this); +} + +void ViewModel::CommitContextChanges() { + if (!context().HasChanges()) + return; + + base::DictionaryValue diff; + context().GetChangesAndReset(&diff); + view_->OnContextChanged(diff); +} + +} // namespace webui_generator
diff --git a/components/webui_generator/view_model.h b/components/webui_generator/view_model.h new file mode 100644 index 0000000..a7021e0 --- /dev/null +++ b/components/webui_generator/view_model.h
@@ -0,0 +1,108 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_WUG_VIEW_MODEL_H_ +#define CHROME_BROWSER_UI_WEBUI_WUG_VIEW_MODEL_H_ + +#include <vector> + +#include "base/macros.h" +#include "components/login/screens/screen_context.h" +#include "components/webui_generator/export.h" + +namespace base { +class DictionaryValue; +} + +namespace webui_generator { + +using Context = login::ScreenContext; +class View; + +// Base class for view-model. Usually View is responsible for creating and +// initializing instances of this class. +class WUG_EXPORT ViewModel { + public: + ViewModel(); + virtual ~ViewModel(); + + void SetView(View* view); + + // Called by view to notify that children are ready. + void OnChildrenReady(); + + // Called by view when it became bound (meaning that all changes in context + // will be reflected in view right after they are made). + virtual void OnViewBound() = 0; + + // Notifies view-model about context changes happended on view side. + // View-model corrects its copy of context according to changes in |diff|. + void UpdateContext(const base::DictionaryValue& diff); + + // Notifies view-model about |event| sent from view. + virtual void OnEvent(const std::string& event); + + protected: + // Scoped context editor, which automatically commits all pending + // context changes on destruction. + class ContextEditor { + public: + using KeyType = ::login::ScreenContext::KeyType; + using String16List = ::login::String16List; + using StringList = ::login::StringList; + + explicit ContextEditor(ViewModel& screen); + ~ContextEditor(); + + const ContextEditor& SetBoolean(const KeyType& key, bool value) const; + const ContextEditor& SetInteger(const KeyType& key, int value) const; + const ContextEditor& SetDouble(const KeyType& key, double value) const; + const ContextEditor& SetString(const KeyType& key, + const std::string& value) const; + const ContextEditor& SetString(const KeyType& key, + const base::string16& value) const; + const ContextEditor& SetStringList(const KeyType& key, + const StringList& value) const; + const ContextEditor& SetString16List(const KeyType& key, + const String16List& value) const; + + private: + ViewModel& view_model_; + Context& context_; + }; + + // This method is called in a time appropriate for initialization. At this + // point it is allowed to make changes in the context, but it is not allowed + // to access child view-models. + virtual void Initialize() = 0; + + // This method is called when all children are ready. + virtual void OnAfterChildrenReady() = 0; + + // This method is called after context was changed on view side. + // |chanaged_keys| contains a list of keys of changed fields. + virtual void OnContextChanged(const std::vector<std::string>& changed_keys) {} + + Context& context() { return context_; } + const Context& context() const { return context_; } + + View* view() const { return view_; } + + // Returns scoped context editor. The editor or it's copies should not outlive + // current BaseScreen instance. + ContextEditor GetContextEditor(); + + // Notifies view about changes made in context. + void CommitContextChanges(); + + private: + Context context_; + View* view_; + + DISALLOW_COPY_AND_ASSIGN(ViewModel); +}; + +} // namespace webui_generator + +#endif // CHROME_BROWSER_UI_WEBUI_WUG_VIEW_MODEL_H_
diff --git a/components/webui_generator/web_ui_view.cc b/components/webui_generator/web_ui_view.cc new file mode 100644 index 0000000..54b8668 --- /dev/null +++ b/components/webui_generator/web_ui_view.cc
@@ -0,0 +1,111 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/webui_generator/web_ui_view.h" + +#include "base/bind_helpers.h" +#include "base/memory/scoped_ptr.h" +#include "components/login/localized_values_builder.h" +#include "components/webui_generator/data_source_util.h" +#include "components/webui_generator/view_model.h" + +namespace { + +const char kEventCallback[] = "eventFired"; +const char kContextChangedCallback[] = "contextChanged"; +const char kReadyCallback[] = "ready"; + +const char kMethodContextChanged[] = "contextChanged"; + +} // namespace + +namespace webui_generator { + +WebUIView::WebUIView(content::WebUI* web_ui, const std::string& id) + : View(id), web_ui_(web_ui), html_ready_(false), view_bound_(false) { +} + +WebUIView::~WebUIView() { +} + +void WebUIView::Init() { + View::Init(); + AddCallback(path() + "$" + kEventCallback, &WebUIView::HandleEvent); + AddCallback(path() + "$" + kContextChangedCallback, + &WebUIView::HandleContextChanged); + AddCallback(path() + "$" + kReadyCallback, &WebUIView::HandleHTMLReady); +} + +void WebUIView::SetUpDataSource(content::WebUIDataSource* data_source) { + DCHECK(IsRootView()); + webui_generator::SetUpDataSource(data_source); + ResourcesMap* resources_map = new ResourcesMap(); + SetUpDataSourceInternal(data_source, resources_map); + data_source->SetRequestFilter(base::Bind(&WebUIView::HandleDataRequest, + base::Unretained(this), + base::Owned(resources_map))); +} + +void WebUIView::OnReady() { + View::OnReady(); + if (html_ready_) + Bind(); +} + +void WebUIView::OnContextChanged(const base::DictionaryValue& diff) { + if (view_bound_) + web_ui_->CallJavascriptFunction(path() + "$" + kMethodContextChanged, diff); + + if (!pending_context_changes_) + pending_context_changes_.reset(new Context()); + + pending_context_changes_->ApplyChanges(diff, nullptr); +} + +void WebUIView::SetUpDataSourceInternal(content::WebUIDataSource* data_source, + ResourcesMap* resources_map) { + base::DictionaryValue strings; + auto builder = make_scoped_ptr( + new ::login::LocalizedValuesBuilder(GetType() + "$", &strings)); + AddLocalizedValues(builder.get()); + data_source->AddLocalizedStrings(strings); + AddResources(resources_map); + for (auto& id_child : children()) { + static_cast<WebUIView*>(id_child.second) + ->SetUpDataSourceInternal(data_source, resources_map); + } +} + +bool WebUIView::HandleDataRequest( + const ResourcesMap* resources, + const std::string& path, + const content::WebUIDataSource::GotDataCallback& got_data_callback) { + auto it = resources->find(path); + + if (it == resources->end()) + return false; + + got_data_callback.Run(it->second.get()); + return true; +} + +void WebUIView::HandleHTMLReady() { + html_ready_ = true; + if (ready()) + Bind(); +} + +void WebUIView::HandleContextChanged(const base::DictionaryValue* diff) { + UpdateContext(*diff); +} + +void WebUIView::Bind() { + view_bound_ = true; + if (pending_context_changes_) + OnContextChanged(pending_context_changes_->storage()); + + GetViewModel()->OnViewBound(); +} + +} // namespace webui_generator
diff --git a/components/webui_generator/web_ui_view.h b/components/webui_generator/web_ui_view.h new file mode 100644 index 0000000..9fd26cf --- /dev/null +++ b/components/webui_generator/web_ui_view.h
@@ -0,0 +1,116 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_WUG_WEB_UI_VIEW_H_ +#define CHROME_BROWSER_UI_WEBUI_WUG_WEB_UI_VIEW_H_ + +#include <string> + +#include "base/bind.h" +#include "base/containers/hash_tables.h" +#include "base/macros.h" +#include "base/memory/ref_counted_memory.h" +#include "base/memory/scoped_ptr.h" +#include "components/login/base_screen_handler_utils.h" +#include "components/login/screens/screen_context.h" +#include "components/webui_generator/export.h" +#include "components/webui_generator/view.h" +#include "content/public/browser/web_ui.h" +#include "content/public/browser/web_ui_data_source.h" + +namespace base { +class DictionaryValue; +} + +namespace content { +class WebUI; +} + +namespace login { +class LocalizedValuesBuilder; +} + +namespace webui_generator { + +using Context = login::ScreenContext; + +/** + * View implementation for the WebUI. Represents a single HTML element derieved + * from <web-ui-view>. + */ +class WUG_EXPORT WebUIView : public View { + public: + WebUIView(content::WebUI* web_ui, const std::string& id); + ~WebUIView() override; + + // Should be called for |data_source|, where this views will be used. + // Sets up |data_source| for children of |this| as well, that is why this + // method only shouldn't be called for non-root views. + void SetUpDataSource(content::WebUIDataSource* data_source); + + // Overridden from View: + void Init() override; + + protected: + using ResourcesMap = + base::hash_map<std::string, scoped_refptr<base::RefCountedMemory>>; + + content::WebUI* web_ui() { return web_ui_; } + + template <typename T> + void AddCallback(const std::string& name, void (T::*method)()) { + base::Callback<void()> callback = + base::Bind(method, base::Unretained(static_cast<T*>(this))); + web_ui_->RegisterMessageCallback( + name, base::Bind(&::login::CallbackWrapper0, callback)); + } + + template <typename T, typename A1> + void AddCallback(const std::string& name, void (T::*method)(A1 arg1)) { + base::Callback<void(A1)> callback = + base::Bind(method, base::Unretained(static_cast<T*>(this))); + web_ui_->RegisterMessageCallback( + name, base::Bind(&::login::CallbackWrapper1<A1>, callback)); + } + + // Overridden from View: + void OnReady() override; + void OnContextChanged(const base::DictionaryValue& diff) override; + + virtual void AddLocalizedValues(::login::LocalizedValuesBuilder* builder) = 0; + virtual void AddResources(ResourcesMap* resources_map) = 0; + + private: + // Internal implementation of SetUpDataSource. + void SetUpDataSourceInternal(content::WebUIDataSource* data_source, + ResourcesMap* resources_map); + + // Called when corresponding <web-ui-view> is ready. + void HandleHTMLReady(); + + // Called when context is changed on JS side. + void HandleContextChanged(const base::DictionaryValue* diff); + + // Called when both |this| and corresponding <web-ui-view> are ready. + void Bind(); + + // Request filter for data source. Filter is needed to answer with a generated + // HTML and JS code which is not kept in resources. + bool HandleDataRequest( + const ResourcesMap* resources, + const std::string& path, + const content::WebUIDataSource::GotDataCallback& got_data_callback); + + private: + content::WebUI* web_ui_; + bool html_ready_; + bool view_bound_; + scoped_ptr<Context> pending_context_changes_; + + DISALLOW_COPY_AND_ASSIGN(WebUIView); +}; + +} // namespace webui_generator + +#endif // CHROME_BROWSER_UI_WEBUI_WUG_WEB_UI_VIEW_H_
diff --git a/components/webui_generator_strings.grdp b/components/webui_generator_strings.grdp new file mode 100644 index 0000000..d29818e --- /dev/null +++ b/components/webui_generator_strings.grdp
@@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + This strings are used in WebUI views created by WUG framework. Resource id is + deduced from string id and view's type. For example, if view's type is + 'foo_bar' and string id is 'some_string', resource id should be + 'IDS_WUG_FOO_BAR_SOME_STRING'. +--> +<grit-part> +</grit-part>
diff --git a/content/browser/android/browser_jni_registrar.cc b/content/browser/android/browser_jni_registrar.cc index 02cfceb..c6844c19 100644 --- a/content/browser/android/browser_jni_registrar.cc +++ b/content/browser/android/browser_jni_registrar.cc
@@ -22,7 +22,7 @@ #include "content/browser/android/load_url_params.h" #include "content/browser/android/popup_touch_handle_drawable.h" #include "content/browser/android/tracing_controller_android.h" -#include "content/browser/android/web_contents_observer_android.h" +#include "content/browser/android/web_contents_observer_proxy.h" #include "content/browser/device_sensors/sensor_manager_android.h" #include "content/browser/frame_host/navigation_controller_android.h" #include "content/browser/gamepad/gamepad_platform_data_fetcher_android.h" @@ -92,7 +92,7 @@ content::SyntheticGestureTargetAndroid::RegisterTouchEventSynthesizer}, {"TracingControllerAndroid", content::RegisterTracingControllerAndroid}, {"WebContentsAndroid", content::WebContentsAndroid::Register}, - {"WebContentsObserver", content::RegisterWebContentsObserverAndroid}, + {"WebContentsObserver", content::RegisterWebContentsObserverProxy}, {"WebViewStatics", content::RegisterWebViewStatics}, };
diff --git a/content/browser/android/media_players_observer.cc b/content/browser/android/media_players_observer.cc new file mode 100644 index 0000000..c277130 --- /dev/null +++ b/content/browser/android/media_players_observer.cc
@@ -0,0 +1,59 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/android/media_players_observer.h" + +#include <climits> + +#include "base/logging.h" +#include "content/public/browser/web_contents.h" + +namespace content { + +MediaPlayersObserver::MediaPlayersObserver(WebContents* web_contents) + : AudioStateProvider(web_contents) { +} + +MediaPlayersObserver::~MediaPlayersObserver() {} + +bool MediaPlayersObserver::IsAudioStateAvailable() const { + return true; +} + +// This audio state provider does not have a monitor +AudioStreamMonitor* MediaPlayersObserver::audio_stream_monitor() { + return nullptr; +} + +void MediaPlayersObserver::OnAudibleStateChanged(RenderFrameHost* rfh, + int player_id, + bool is_audible) { + audio_status_map_[Key(rfh, player_id)] = is_audible; + UpdateStatusAndNotify(); +} + +void MediaPlayersObserver::RemovePlayer(RenderFrameHost* rfh, int player_id) { + audio_status_map_.erase(Key(rfh, player_id)); + UpdateStatusAndNotify(); +} + +void MediaPlayersObserver::RenderFrameDeleted(RenderFrameHost* rfh) { + StatusMap::iterator begin = audio_status_map_.lower_bound(Key(rfh, 0)); + StatusMap::iterator end = audio_status_map_.upper_bound(Key(rfh, INT_MAX)); + audio_status_map_.erase(begin, end); + UpdateStatusAndNotify(); +} + +void MediaPlayersObserver::UpdateStatusAndNotify() { + for (const auto& player_status : audio_status_map_) { + if (player_status.second) { + Notify(true); // at least one player is making noise + return; + } + } + + Notify(false); +} + +} // namespace content
diff --git a/content/browser/android/media_players_observer.h b/content/browser/android/media_players_observer.h new file mode 100644 index 0000000..b01a3bf --- /dev/null +++ b/content/browser/android/media_players_observer.h
@@ -0,0 +1,51 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_ANDROID_MEDIA_PLAYERS_OBSERVER_H_ +#define CONTENT_BROWSER_ANDROID_MEDIA_PLAYERS_OBSERVER_H_ + +#include <map> + +#include "base/macros.h" +#include "content/browser/media/audio_state_provider.h" + +namespace content { + +class RenderFrameHost; + +// On Android the MediaPlayerAndroid objects report +// the audible state to us. +class MediaPlayersObserver : public AudioStateProvider { + public: + explicit MediaPlayersObserver(WebContents* web_contents); + ~MediaPlayersObserver() override; + + bool IsAudioStateAvailable() const override; + + // This audio state provider does not have a monitor, + // the method returns nullptr. + AudioStreamMonitor* audio_stream_monitor() override; + + // These methods constitute the observer pattern, should + // be called when corresponding event happens. They will notify + // WebContents whenever its audible state as a whole changes. + void OnAudibleStateChanged(RenderFrameHost* rfh, int player_id, + bool is_audible); + void RemovePlayer(RenderFrameHost* rfh, int player_id); + void RenderFrameDeleted(RenderFrameHost* rfh); + + private: + void UpdateStatusAndNotify(); + + // Audible status per player ID and frame + typedef std::pair<RenderFrameHost*, int> Key; + typedef std::map<Key, bool> StatusMap; + StatusMap audio_status_map_; + + DISALLOW_COPY_AND_ASSIGN(MediaPlayersObserver); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_ANDROID_MEDIA_PLAYERS_OBSERVER_H_
diff --git a/content/browser/android/web_contents_observer_android.cc b/content/browser/android/web_contents_observer_android.cc deleted file mode 100644 index e056f31..0000000 --- a/content/browser/android/web_contents_observer_android.cc +++ /dev/null
@@ -1,355 +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. - -#include "content/browser/android/web_contents_observer_android.h" - -#include <string> - -#include <jni.h> - -#include "base/android/jni_android.h" -#include "base/android/jni_string.h" -#include "base/android/scoped_java_ref.h" -#include "content/browser/renderer_host/render_widget_host_impl.h" -#include "content/browser/web_contents/web_contents_impl.h" -#include "content/public/browser/navigation_details.h" -#include "content/public/browser/navigation_entry.h" -#include "jni/WebContentsObserver_jni.h" - -using base::android::AttachCurrentThread; -using base::android::ScopedJavaLocalRef; -using base::android::ConvertUTF8ToJavaString; -using base::android::ConvertUTF16ToJavaString; - -namespace content { - -// TODO(dcheng): File a bug. This class incorrectly passes just a frame ID, -// which is not sufficient to identify a frame (since frame IDs are scoped per -// render process, and so may collide). -WebContentsObserverAndroid::WebContentsObserverAndroid( - JNIEnv* env, - jobject obj, - WebContents* web_contents) - : WebContentsObserver(web_contents), - weak_java_observer_(env, obj){ -} - -WebContentsObserverAndroid::~WebContentsObserverAndroid() { -} - -jlong Init(JNIEnv* env, jobject obj, jobject java_web_contents) { - WebContents* web_contents = - WebContents::FromJavaWebContents(java_web_contents); - CHECK(web_contents); - - WebContentsObserverAndroid* native_observer = new WebContentsObserverAndroid( - env, obj, web_contents); - return reinterpret_cast<intptr_t>(native_observer); -} - -void WebContentsObserverAndroid::Destroy(JNIEnv* env, jobject obj) { - delete this; -} - -void WebContentsObserverAndroid::WebContentsDestroyed() { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) { - delete this; - } else { - // The java side will destroy |this| - Java_WebContentsObserver_detachFromWebContents(env, obj.obj()); - } -} - -void WebContentsObserverAndroid::RenderViewReady() { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - Java_WebContentsObserver_renderViewReady(env, obj.obj()); -} - -void WebContentsObserverAndroid::RenderProcessGone( - base::TerminationStatus termination_status) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - jboolean was_oom_protected = - termination_status == base::TERMINATION_STATUS_OOM_PROTECTED; - Java_WebContentsObserver_renderProcessGone( - env, obj.obj(), was_oom_protected); -} - -void WebContentsObserverAndroid::DidStartLoading( - RenderViewHost* render_view_host) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString( - env, web_contents()->GetVisibleURL().spec())); - Java_WebContentsObserver_didStartLoading( - env, obj.obj(), jstring_url.obj()); -} - -void WebContentsObserverAndroid::DidStopLoading( - RenderViewHost* render_view_host) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString( - env, web_contents()->GetLastCommittedURL().spec())); - Java_WebContentsObserver_didStopLoading( - env, obj.obj(), jstring_url.obj()); -} - -void WebContentsObserverAndroid::DidFailProvisionalLoad( - RenderFrameHost* render_frame_host, - const GURL& validated_url, - int error_code, - const base::string16& error_description) { - DidFailLoadInternal(true, - !render_frame_host->GetParent(), - error_code, - error_description, - validated_url); -} - -void WebContentsObserverAndroid::DidFailLoad( - RenderFrameHost* render_frame_host, - const GURL& validated_url, - int error_code, - const base::string16& error_description) { - DidFailLoadInternal(false, - !render_frame_host->GetParent(), - error_code, - error_description, - validated_url); -} - -void WebContentsObserverAndroid::DidNavigateMainFrame( - const LoadCommittedDetails& details, - const FrameNavigateParams& params) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - ScopedJavaLocalRef<jstring> jstring_url( - ConvertUTF8ToJavaString(env, params.url.spec())); - ScopedJavaLocalRef<jstring> jstring_base_url( - ConvertUTF8ToJavaString(env, params.base_url.spec())); - - // See http://crbug.com/251330 for why it's determined this way. - url::Replacements<char> replacements; - replacements.ClearRef(); - bool urls_same_ignoring_fragment = - params.url.ReplaceComponents(replacements) == - details.previous_url.ReplaceComponents(replacements); - - // is_fragment_navigation is indicative of the intent of this variable. - // However, there isn't sufficient information here to determine whether this - // is actually a fragment navigation, or a history API navigation to a URL - // that would also be valid for a fragment navigation. - bool is_fragment_navigation = urls_same_ignoring_fragment && - (details.type == NAVIGATION_TYPE_IN_PAGE || details.is_in_page); - Java_WebContentsObserver_didNavigateMainFrame( - env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(), - details.is_navigation_to_different_page(), is_fragment_navigation, - details.http_status_code); -} - -void WebContentsObserverAndroid::DidNavigateAnyFrame( - RenderFrameHost* render_frame_host, - const LoadCommittedDetails& details, - const FrameNavigateParams& params) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - ScopedJavaLocalRef<jstring> jstring_url( - ConvertUTF8ToJavaString(env, params.url.spec())); - ScopedJavaLocalRef<jstring> jstring_base_url( - ConvertUTF8ToJavaString(env, params.base_url.spec())); - jboolean jboolean_is_reload = ui::PageTransitionCoreTypeIs( - params.transition, ui::PAGE_TRANSITION_RELOAD); - - Java_WebContentsObserver_didNavigateAnyFrame( - env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(), - jboolean_is_reload); -} - -void WebContentsObserverAndroid::DocumentAvailableInMainFrame() { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - Java_WebContentsObserver_documentAvailableInMainFrame(env, obj.obj()); -} - -void WebContentsObserverAndroid::DidStartProvisionalLoadForFrame( - RenderFrameHost* render_frame_host, - const GURL& validated_url, - bool is_error_page, - bool is_iframe_srcdoc) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - ScopedJavaLocalRef<jstring> jstring_url( - ConvertUTF8ToJavaString(env, validated_url.spec())); - // TODO(dcheng): Does Java really need the parent frame ID? It doesn't appear - // to be used at all, and it just adds complexity here. - Java_WebContentsObserver_didStartProvisionalLoadForFrame( - env, - obj.obj(), - render_frame_host->GetRoutingID(), - render_frame_host->GetParent() - ? render_frame_host->GetParent()->GetRoutingID() - : -1, - !render_frame_host->GetParent(), - jstring_url.obj(), - is_error_page, - is_iframe_srcdoc); -} - -void WebContentsObserverAndroid::DidCommitProvisionalLoadForFrame( - RenderFrameHost* render_frame_host, - const GURL& url, - ui::PageTransition transition_type) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - ScopedJavaLocalRef<jstring> jstring_url( - ConvertUTF8ToJavaString(env, url.spec())); - Java_WebContentsObserver_didCommitProvisionalLoadForFrame( - env, - obj.obj(), - render_frame_host->GetRoutingID(), - !render_frame_host->GetParent(), - jstring_url.obj(), - transition_type); -} - -void WebContentsObserverAndroid::DidFinishLoad( - RenderFrameHost* render_frame_host, - const GURL& validated_url) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - - std::string url_string = validated_url.spec(); - NavigationEntry* entry = - web_contents()->GetController().GetLastCommittedEntry(); - // Note that GetBaseURLForDataURL is only used by the Android WebView. - if (entry && !entry->GetBaseURLForDataURL().is_empty()) - url_string = entry->GetBaseURLForDataURL().possibly_invalid_spec(); - - ScopedJavaLocalRef<jstring> jstring_url( - ConvertUTF8ToJavaString(env, url_string)); - Java_WebContentsObserver_didFinishLoad( - env, - obj.obj(), - render_frame_host->GetRoutingID(), - jstring_url.obj(), - !render_frame_host->GetParent()); -} - -void WebContentsObserverAndroid::DocumentLoadedInFrame( - RenderFrameHost* render_frame_host) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - Java_WebContentsObserver_documentLoadedInFrame( - env, obj.obj(), render_frame_host->GetRoutingID()); -} - -void WebContentsObserverAndroid::NavigationEntryCommitted( - const LoadCommittedDetails& load_details) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - Java_WebContentsObserver_navigationEntryCommitted(env, obj.obj()); -} - -void WebContentsObserverAndroid::DidAttachInterstitialPage() { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - Java_WebContentsObserver_didAttachInterstitialPage(env, obj.obj()); -} - -void WebContentsObserverAndroid::DidDetachInterstitialPage() { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - Java_WebContentsObserver_didDetachInterstitialPage(env, obj.obj()); -} - -void WebContentsObserverAndroid::DidChangeThemeColor(SkColor color) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - Java_WebContentsObserver_didChangeThemeColor(env, obj.obj(), color); -} - -void WebContentsObserverAndroid::DidFailLoadInternal( - bool is_provisional_load, - bool is_main_frame, - int error_code, - const base::string16& description, - const GURL& url) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - ScopedJavaLocalRef<jstring> jstring_error_description( - ConvertUTF16ToJavaString(env, description)); - ScopedJavaLocalRef<jstring> jstring_url( - ConvertUTF8ToJavaString(env, url.spec())); - - Java_WebContentsObserver_didFailLoad( - env, obj.obj(), - is_provisional_load, - is_main_frame, - error_code, - jstring_error_description.obj(), jstring_url.obj()); -} - -void WebContentsObserverAndroid::DidFirstVisuallyNonEmptyPaint() { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - Java_WebContentsObserver_didFirstVisuallyNonEmptyPaint( - env, obj.obj()); -} - -void WebContentsObserverAndroid::DidStartNavigationToPendingEntry( - const GURL& url, - NavigationController::ReloadType reload_type) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); - if (obj.is_null()) - return; - ScopedJavaLocalRef<jstring> jstring_url( - ConvertUTF8ToJavaString(env, url.spec())); - - Java_WebContentsObserver_didStartNavigationToPendingEntry(env, obj.obj(), - jstring_url.obj()); -} - -bool RegisterWebContentsObserverAndroid(JNIEnv* env) { - return RegisterNativesImpl(env); -} -} // namespace content
diff --git a/content/browser/android/web_contents_observer_android.h b/content/browser/android/web_contents_observer_android.h deleted file mode 100644 index 3f5d1110..0000000 --- a/content/browser/android/web_contents_observer_android.h +++ /dev/null
@@ -1,89 +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. - -#ifndef CONTENT_BROWSER_ANDROID_WEB_CONTENTS_OBSERVER_ANDROID_H_ -#define CONTENT_BROWSER_ANDROID_WEB_CONTENTS_OBSERVER_ANDROID_H_ - -#include <jni.h> - -#include "base/android/jni_weak_ref.h" -#include "base/basictypes.h" -#include "base/process/kill.h" -#include "content/browser/web_contents/web_contents_impl.h" -#include "content/public/browser/web_contents_observer.h" -#include "content/public/common/frame_navigate_params.h" -#include "url/gurl.h" - -namespace content { - -class RenderViewHost; -class WebContents; - -// Extends WebContentsObserver for providing a public Java API for some of the -// the calls it receives. -class WebContentsObserverAndroid : public WebContentsObserver { - public: - WebContentsObserverAndroid(JNIEnv* env, - jobject obj, - WebContents* web_contents); - ~WebContentsObserverAndroid() override; - - void Destroy(JNIEnv* env, jobject obj); - - private: - void RenderViewReady() override; - void RenderProcessGone(base::TerminationStatus termination_status) override; - void DidStartLoading(RenderViewHost* render_view_host) override; - void DidStopLoading(RenderViewHost* render_view_host) override; - void DidFailProvisionalLoad(RenderFrameHost* render_frame_host, - const GURL& validated_url, - int error_code, - const base::string16& error_description) override; - void DidFailLoad(RenderFrameHost* render_frame_host, - const GURL& validated_url, - int error_code, - const base::string16& error_description) override; - void DidNavigateMainFrame(const LoadCommittedDetails& details, - const FrameNavigateParams& params) override; - void DidNavigateAnyFrame(RenderFrameHost* render_frame_host, - const LoadCommittedDetails& details, - const FrameNavigateParams& params) override; - void DocumentAvailableInMainFrame() override; - void DidFirstVisuallyNonEmptyPaint() override; - void DidStartProvisionalLoadForFrame(RenderFrameHost* render_frame_host, - const GURL& validated_url, - bool is_error_page, - bool is_iframe_srcdoc) override; - void DidCommitProvisionalLoadForFrame( - RenderFrameHost* render_frame_host, - const GURL& url, - ui::PageTransition transition_type) override; - void DidFinishLoad(RenderFrameHost* render_frame_host, - const GURL& validated_url) override; - void DocumentLoadedInFrame(RenderFrameHost* render_frame_host) override; - void NavigationEntryCommitted( - const LoadCommittedDetails& load_details) override; - void WebContentsDestroyed() override; - void DidAttachInterstitialPage() override; - void DidDetachInterstitialPage() override; - void DidChangeThemeColor(SkColor color) override; - void DidStartNavigationToPendingEntry( - const GURL& url, - NavigationController::ReloadType reload_type) override; - - void DidFailLoadInternal(bool is_provisional_load, - bool is_main_frame, - int error_code, - const base::string16& description, - const GURL& url); - - JavaObjectWeakGlobalRef weak_java_observer_; - - DISALLOW_COPY_AND_ASSIGN(WebContentsObserverAndroid); -}; - -bool RegisterWebContentsObserverAndroid(JNIEnv* env); -} // namespace content - -#endif // CONTENT_BROWSER_ANDROID_WEB_CONTENTS_OBSERVER_ANDROID_H_
diff --git a/content/browser/android/web_contents_observer_proxy.cc b/content/browser/android/web_contents_observer_proxy.cc new file mode 100644 index 0000000..8566bee --- /dev/null +++ b/content/browser/android/web_contents_observer_proxy.cc
@@ -0,0 +1,330 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/android/web_contents_observer_proxy.h" + +#include <string> + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/android/scoped_java_ref.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/navigation_details.h" +#include "content/public/browser/navigation_entry.h" +#include "jni/WebContentsObserverProxy_jni.h" + +using base::android::AttachCurrentThread; +using base::android::ScopedJavaLocalRef; +using base::android::ConvertUTF8ToJavaString; +using base::android::ConvertUTF16ToJavaString; + +namespace content { + +// TODO(dcheng): File a bug. This class incorrectly passes just a frame ID, +// which is not sufficient to identify a frame (since frame IDs are scoped per +// render process, and so may collide). +WebContentsObserverProxy::WebContentsObserverProxy(JNIEnv* env, + jobject obj, + WebContents* web_contents) + : WebContentsObserver(web_contents), weak_java_observer_(env, obj) { +} + +WebContentsObserverProxy::~WebContentsObserverProxy() { +} + +jlong Init(JNIEnv* env, jobject obj, jobject java_web_contents) { + WebContents* web_contents = + WebContents::FromJavaWebContents(java_web_contents); + CHECK(web_contents); + + WebContentsObserverProxy* native_observer = + new WebContentsObserverProxy(env, obj, web_contents); + return reinterpret_cast<intptr_t>(native_observer); +} + +void WebContentsObserverProxy::Destroy(JNIEnv* env, jobject obj) { + delete this; +} + +void WebContentsObserverProxy::WebContentsDestroyed() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) { + delete this; + } else { + // The java side will destroy |this| + Java_WebContentsObserverProxy_destroy(env, obj.obj()); + } +} + +void WebContentsObserverProxy::RenderViewReady() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + Java_WebContentsObserverProxy_renderViewReady(env, obj.obj()); +} + +void WebContentsObserverProxy::RenderProcessGone( + base::TerminationStatus termination_status) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + jboolean was_oom_protected = + termination_status == base::TERMINATION_STATUS_OOM_PROTECTED; + Java_WebContentsObserverProxy_renderProcessGone(env, obj.obj(), + was_oom_protected); +} + +void WebContentsObserverProxy::DidStartLoading( + RenderViewHost* render_view_host) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + ScopedJavaLocalRef<jstring> jstring_url( + ConvertUTF8ToJavaString(env, web_contents()->GetVisibleURL().spec())); + Java_WebContentsObserverProxy_didStartLoading(env, obj.obj(), + jstring_url.obj()); +} + +void WebContentsObserverProxy::DidStopLoading( + RenderViewHost* render_view_host) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString( + env, web_contents()->GetLastCommittedURL().spec())); + Java_WebContentsObserverProxy_didStopLoading(env, obj.obj(), + jstring_url.obj()); +} + +void WebContentsObserverProxy::DidFailProvisionalLoad( + RenderFrameHost* render_frame_host, + const GURL& validated_url, + int error_code, + const base::string16& error_description) { + DidFailLoadInternal(true, !render_frame_host->GetParent(), error_code, + error_description, validated_url); +} + +void WebContentsObserverProxy::DidFailLoad( + RenderFrameHost* render_frame_host, + const GURL& validated_url, + int error_code, + const base::string16& error_description) { + DidFailLoadInternal(false, !render_frame_host->GetParent(), error_code, + error_description, validated_url); +} + +void WebContentsObserverProxy::DidNavigateMainFrame( + const LoadCommittedDetails& details, + const FrameNavigateParams& params) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + ScopedJavaLocalRef<jstring> jstring_url( + ConvertUTF8ToJavaString(env, params.url.spec())); + ScopedJavaLocalRef<jstring> jstring_base_url( + ConvertUTF8ToJavaString(env, params.base_url.spec())); + + // See http://crbug.com/251330 for why it's determined this way. + url::Replacements<char> replacements; + replacements.ClearRef(); + bool urls_same_ignoring_fragment = + params.url.ReplaceComponents(replacements) == + details.previous_url.ReplaceComponents(replacements); + + // is_fragment_navigation is indicative of the intent of this variable. + // However, there isn't sufficient information here to determine whether this + // is actually a fragment navigation, or a history API navigation to a URL + // that would also be valid for a fragment navigation. + bool is_fragment_navigation = + urls_same_ignoring_fragment && + (details.type == NAVIGATION_TYPE_IN_PAGE || details.is_in_page); + Java_WebContentsObserverProxy_didNavigateMainFrame( + env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(), + details.is_navigation_to_different_page(), is_fragment_navigation, + details.http_status_code); +} + +void WebContentsObserverProxy::DidNavigateAnyFrame( + RenderFrameHost* render_frame_host, + const LoadCommittedDetails& details, + const FrameNavigateParams& params) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + ScopedJavaLocalRef<jstring> jstring_url( + ConvertUTF8ToJavaString(env, params.url.spec())); + ScopedJavaLocalRef<jstring> jstring_base_url( + ConvertUTF8ToJavaString(env, params.base_url.spec())); + jboolean jboolean_is_reload = ui::PageTransitionCoreTypeIs( + params.transition, ui::PAGE_TRANSITION_RELOAD); + + Java_WebContentsObserverProxy_didNavigateAnyFrame( + env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(), + jboolean_is_reload); +} + +void WebContentsObserverProxy::DocumentAvailableInMainFrame() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + Java_WebContentsObserverProxy_documentAvailableInMainFrame(env, obj.obj()); +} + +void WebContentsObserverProxy::DidStartProvisionalLoadForFrame( + RenderFrameHost* render_frame_host, + const GURL& validated_url, + bool is_error_page, + bool is_iframe_srcdoc) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + ScopedJavaLocalRef<jstring> jstring_url( + ConvertUTF8ToJavaString(env, validated_url.spec())); + // TODO(dcheng): Does Java really need the parent frame ID? It doesn't appear + // to be used at all, and it just adds complexity here. + Java_WebContentsObserverProxy_didStartProvisionalLoadForFrame( + env, obj.obj(), render_frame_host->GetRoutingID(), + render_frame_host->GetParent() + ? render_frame_host->GetParent()->GetRoutingID() + : -1, + !render_frame_host->GetParent(), jstring_url.obj(), is_error_page, + is_iframe_srcdoc); +} + +void WebContentsObserverProxy::DidCommitProvisionalLoadForFrame( + RenderFrameHost* render_frame_host, + const GURL& url, + ui::PageTransition transition_type) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + ScopedJavaLocalRef<jstring> jstring_url( + ConvertUTF8ToJavaString(env, url.spec())); + Java_WebContentsObserverProxy_didCommitProvisionalLoadForFrame( + env, obj.obj(), render_frame_host->GetRoutingID(), + !render_frame_host->GetParent(), jstring_url.obj(), transition_type); +} + +void WebContentsObserverProxy::DidFinishLoad(RenderFrameHost* render_frame_host, + const GURL& validated_url) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + + std::string url_string = validated_url.spec(); + NavigationEntry* entry = + web_contents()->GetController().GetLastCommittedEntry(); + // Note that GetBaseURLForDataURL is only used by the Android WebView. + if (entry && !entry->GetBaseURLForDataURL().is_empty()) + url_string = entry->GetBaseURLForDataURL().possibly_invalid_spec(); + + ScopedJavaLocalRef<jstring> jstring_url( + ConvertUTF8ToJavaString(env, url_string)); + Java_WebContentsObserverProxy_didFinishLoad( + env, obj.obj(), render_frame_host->GetRoutingID(), jstring_url.obj(), + !render_frame_host->GetParent()); +} + +void WebContentsObserverProxy::DocumentLoadedInFrame( + RenderFrameHost* render_frame_host) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + Java_WebContentsObserverProxy_documentLoadedInFrame( + env, obj.obj(), render_frame_host->GetRoutingID()); +} + +void WebContentsObserverProxy::NavigationEntryCommitted( + const LoadCommittedDetails& load_details) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + Java_WebContentsObserverProxy_navigationEntryCommitted(env, obj.obj()); +} + +void WebContentsObserverProxy::DidAttachInterstitialPage() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + Java_WebContentsObserverProxy_didAttachInterstitialPage(env, obj.obj()); +} + +void WebContentsObserverProxy::DidDetachInterstitialPage() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + Java_WebContentsObserverProxy_didDetachInterstitialPage(env, obj.obj()); +} + +void WebContentsObserverProxy::DidChangeThemeColor(SkColor color) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + Java_WebContentsObserverProxy_didChangeThemeColor(env, obj.obj(), color); +} + +void WebContentsObserverProxy::DidFailLoadInternal( + bool is_provisional_load, + bool is_main_frame, + int error_code, + const base::string16& description, + const GURL& url) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + ScopedJavaLocalRef<jstring> jstring_error_description( + ConvertUTF16ToJavaString(env, description)); + ScopedJavaLocalRef<jstring> jstring_url( + ConvertUTF8ToJavaString(env, url.spec())); + + Java_WebContentsObserverProxy_didFailLoad( + env, obj.obj(), is_provisional_load, is_main_frame, error_code, + jstring_error_description.obj(), jstring_url.obj()); +} + +void WebContentsObserverProxy::DidFirstVisuallyNonEmptyPaint() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + Java_WebContentsObserverProxy_didFirstVisuallyNonEmptyPaint(env, obj.obj()); +} + +void WebContentsObserverProxy::DidStartNavigationToPendingEntry( + const GURL& url, + NavigationController::ReloadType reload_type) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); + if (obj.is_null()) + return; + ScopedJavaLocalRef<jstring> jstring_url( + ConvertUTF8ToJavaString(env, url.spec())); + + Java_WebContentsObserverProxy_didStartNavigationToPendingEntry( + env, obj.obj(), jstring_url.obj()); +} + +bool RegisterWebContentsObserverProxy(JNIEnv* env) { + return RegisterNativesImpl(env); +} +} // namespace content
diff --git a/content/browser/android/web_contents_observer_proxy.h b/content/browser/android/web_contents_observer_proxy.h new file mode 100644 index 0000000..1d45011d --- /dev/null +++ b/content/browser/android/web_contents_observer_proxy.h
@@ -0,0 +1,87 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_ANDROID_WEB_CONTENTS_OBSERVER_PROXY_H_ +#define CONTENT_BROWSER_ANDROID_WEB_CONTENTS_OBSERVER_PROXY_H_ + +#include <jni.h> + +#include "base/android/jni_weak_ref.h" +#include "base/basictypes.h" +#include "base/process/kill.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/common/frame_navigate_params.h" +#include "url/gurl.h" + +namespace content { + +class RenderViewHost; +class WebContents; + +// Extends WebContentsObserver for providing a public Java API for some of the +// the calls it receives. +class WebContentsObserverProxy : public WebContentsObserver { + public: + WebContentsObserverProxy(JNIEnv* env, jobject obj, WebContents* web_contents); + ~WebContentsObserverProxy() override; + + void Destroy(JNIEnv* env, jobject obj); + + private: + void RenderViewReady() override; + void RenderProcessGone(base::TerminationStatus termination_status) override; + void DidStartLoading(RenderViewHost* render_view_host) override; + void DidStopLoading(RenderViewHost* render_view_host) override; + void DidFailProvisionalLoad(RenderFrameHost* render_frame_host, + const GURL& validated_url, + int error_code, + const base::string16& error_description) override; + void DidFailLoad(RenderFrameHost* render_frame_host, + const GURL& validated_url, + int error_code, + const base::string16& error_description) override; + void DidNavigateMainFrame(const LoadCommittedDetails& details, + const FrameNavigateParams& params) override; + void DidNavigateAnyFrame(RenderFrameHost* render_frame_host, + const LoadCommittedDetails& details, + const FrameNavigateParams& params) override; + void DocumentAvailableInMainFrame() override; + void DidFirstVisuallyNonEmptyPaint() override; + void DidStartProvisionalLoadForFrame(RenderFrameHost* render_frame_host, + const GURL& validated_url, + bool is_error_page, + bool is_iframe_srcdoc) override; + void DidCommitProvisionalLoadForFrame( + RenderFrameHost* render_frame_host, + const GURL& url, + ui::PageTransition transition_type) override; + void DidFinishLoad(RenderFrameHost* render_frame_host, + const GURL& validated_url) override; + void DocumentLoadedInFrame(RenderFrameHost* render_frame_host) override; + void NavigationEntryCommitted( + const LoadCommittedDetails& load_details) override; + void WebContentsDestroyed() override; + void DidAttachInterstitialPage() override; + void DidDetachInterstitialPage() override; + void DidChangeThemeColor(SkColor color) override; + void DidStartNavigationToPendingEntry( + const GURL& url, + NavigationController::ReloadType reload_type) override; + + void DidFailLoadInternal(bool is_provisional_load, + bool is_main_frame, + int error_code, + const base::string16& description, + const GURL& url); + + JavaObjectWeakGlobalRef weak_java_observer_; + + DISALLOW_COPY_AND_ASSIGN(WebContentsObserverProxy); +}; + +bool RegisterWebContentsObserverProxy(JNIEnv* env); +} // namespace content + +#endif // CONTENT_BROWSER_ANDROID_WEB_CONTENTS_OBSERVER_PROXY_H_
diff --git a/content/browser/compositor/software_browser_compositor_output_surface.cc b/content/browser/compositor/software_browser_compositor_output_surface.cc index 647a062..2d422c9 100644 --- a/content/browser/compositor/software_browser_compositor_output_surface.cc +++ b/content/browser/compositor/software_browser_compositor_output_surface.cc
@@ -30,9 +30,13 @@ void SoftwareBrowserCompositorOutputSurface::SwapBuffers( cc::CompositorFrame* frame) { - for (size_t i = 0; i < frame->metadata.latency_info.size(); i++) { - frame->metadata.latency_info[i].AddLatencyNumber( - ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0); + base::TimeTicks swap_time = base::TimeTicks::Now(); + for (auto& latency : frame->metadata.latency_info) { + latency.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1); + latency.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0, + swap_time, 1); } base::MessageLoop::current()->PostTask( FROM_HERE,
diff --git a/content/browser/device_sensors/data_fetcher_shared_memory.h b/content/browser/device_sensors/data_fetcher_shared_memory.h index beb8254e..f17eb27 100644 --- a/content/browser/device_sensors/data_fetcher_shared_memory.h +++ b/content/browser/device_sensors/data_fetcher_shared_memory.h
@@ -61,6 +61,7 @@ class SensorEventSink; class SensorEventSinkMotion; class SensorEventSinkOrientation; + class SensorEventSinkLight; virtual FetcherType GetType() const override; @@ -72,6 +73,7 @@ base::win::ScopedComPtr<ISensor> sensor_inclinometer_; base::win::ScopedComPtr<ISensor> sensor_accelerometer_; base::win::ScopedComPtr<ISensor> sensor_gyrometer_; + base::win::ScopedComPtr<ISensor> sensor_light_; #endif DISALLOW_COPY_AND_ASSIGN(DataFetcherSharedMemory);
diff --git a/content/browser/device_sensors/data_fetcher_shared_memory_win.cc b/content/browser/device_sensors/data_fetcher_shared_memory_win.cc index 77c962e..7b29bfd0 100644 --- a/content/browser/device_sensors/data_fetcher_shared_memory_win.cc +++ b/content/browser/device_sensors/data_fetcher_shared_memory_win.cc
@@ -18,6 +18,13 @@ const double kMeanGravity = 9.80665; +void SetLightBuffer(content::DeviceLightHardwareBuffer* buffer, double lux) { + DCHECK(buffer); + buffer->seqlock.WriteBegin(); + buffer->data.value = lux; + buffer->seqlock.WriteEnd(); +} + } // namespace @@ -222,8 +229,41 @@ DISALLOW_COPY_AND_ASSIGN(SensorEventSinkMotion); }; +class DataFetcherSharedMemory::SensorEventSinkLight + : public DataFetcherSharedMemory::SensorEventSink { + public: + explicit SensorEventSinkLight(DeviceLightHardwareBuffer* const buffer) + : buffer_(buffer) {} + virtual ~SensorEventSinkLight() {} + + protected: + virtual bool UpdateSharedMemoryBuffer(ISensor* sensor, + ISensorDataReport* new_data) override { + double lux; + bool has_lux; + + GetSensorValue(SENSOR_DATA_TYPE_LIGHT_LEVEL_LUX, new_data, &lux, &has_lux); + + if(!has_lux) { + // Could not get lux value. + return false; + } + + SetLightBuffer(buffer_, lux); + + return true; + } + + private: + DeviceLightHardwareBuffer* const buffer_; + + DISALLOW_COPY_AND_ASSIGN(SensorEventSinkLight); +}; + DataFetcherSharedMemory::DataFetcherSharedMemory() - : motion_buffer_(nullptr), orientation_buffer_(nullptr) { + : motion_buffer_(nullptr), + orientation_buffer_(nullptr), + light_buffer_(nullptr) { } DataFetcherSharedMemory::~DataFetcherSharedMemory() { @@ -277,6 +317,22 @@ SetBufferAvailableState(consumer_type, true); } break; + case CONSUMER_TYPE_LIGHT: + { + light_buffer_ = static_cast<DeviceLightHardwareBuffer*>(buffer); + scoped_refptr<SensorEventSink> sink( + new SensorEventSinkLight(light_buffer_)); + bool sensor_light_available = RegisterForSensor( + SENSOR_TYPE_AMBIENT_LIGHT, sensor_light_.Receive(), sink); + if (sensor_light_available) { + SetLightBuffer(light_buffer_, -1); + return true; + } + + // if no sensors are available, fire an Infinity event. + SetLightBuffer(light_buffer_, std::numeric_limits<double>::infinity()); + } + break; default: NOTREACHED(); } @@ -293,6 +349,10 @@ case CONSUMER_TYPE_MOTION: motion_buffer_ = nullptr; return true; + case CONSUMER_TYPE_LIGHT: + SetLightBuffer(light_buffer_, -1); + light_buffer_ = nullptr; + return true; default: NOTREACHED(); } @@ -368,6 +428,12 @@ sensor_gyrometer_.Release(); } break; + case CONSUMER_TYPE_LIGHT: + if (sensor_light_.get()) { + sensor_light_->SetEventSink(nullptr); + sensor_light_.Release(); + } + break; default: NOTREACHED(); }
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc index 31ccdbe..cbbd46a 100644 --- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc +++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -96,20 +96,6 @@ } }; -IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, QueryUsageAndQuota) { - scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue); - params->SetString("securityOrigin", "http://example.com"); - SendCommand("Page.queryUsageAndQuota", params.Pass()); - - EXPECT_TRUE(HasValue("quota.persistent")); - EXPECT_TRUE(HasValue("quota.temporary")); - EXPECT_TRUE(HasListItem("usage.temporary", "id", "appcache")); - EXPECT_TRUE(HasListItem("usage.temporary", "id", "database")); - EXPECT_TRUE(HasListItem("usage.temporary", "id", "indexeddatabase")); - EXPECT_TRUE(HasListItem("usage.temporary", "id", "filesystem")); - EXPECT_TRUE(HasListItem("usage.persistent", "id", "filesystem")); -} - class CaptureScreenshotTest : public DevToolsProtocolTest { private: #if !defined(OS_ANDROID)
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc index 127a797..356cefa 100644 --- a/content/browser/devtools/protocol/page_handler.cc +++ b/content/browser/devtools/protocol/page_handler.cc
@@ -13,7 +13,6 @@ #include "base/threading/worker_pool.h" #include "content/browser/devtools/protocol/color_picker.h" #include "content/browser/devtools/protocol/frame_recorder.h" -#include "content/browser/devtools/protocol/usage_and_quota_query.h" #include "content/browser/geolocation/geolocation_service_context.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" @@ -27,7 +26,6 @@ #include "content/public/browser/web_contents_delegate.h" #include "content/public/common/referrer.h" #include "content/public/common/url_constants.h" -#include "storage/browser/quota/quota_manager.h" #include "third_party/WebKit/public/platform/WebScreenInfo.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/page_transition_types.h" @@ -65,24 +63,6 @@ return result; } -void QueryUsageAndQuotaCompletedOnIOThread( - const UsageAndQuotaQuery::Callback& callback, - scoped_refptr<QueryUsageAndQuotaResponse> response) { - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(callback, response)); -} - -void QueryUsageAndQuotaOnIOThread( - scoped_refptr<storage::QuotaManager> quota_manager, - const GURL& security_origin, - const UsageAndQuotaQuery::Callback& callback) { - new UsageAndQuotaQuery( - quota_manager, - security_origin, - base::Bind(&QueryUsageAndQuotaCompletedOnIOThread, - callback)); -} - std::string EncodeScreencastFrame(const SkBitmap& bitmap, const std::string& format, int quality) { @@ -449,21 +429,6 @@ Response PageHandler::QueryUsageAndQuota(DevToolsCommandId command_id, const std::string& security_origin) { - if (!host_) - return Response::InternalError("Could not connect to view"); - - scoped_refptr<storage::QuotaManager> quota_manager = - host_->GetProcess()->GetStoragePartition()->GetQuotaManager(); - - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&QueryUsageAndQuotaOnIOThread, - quota_manager, - GURL(security_origin), - base::Bind(&PageHandler::QueryUsageAndQuotaCompleted, - weak_factory_.GetWeakPtr(), - command_id))); return Response::OK(); } @@ -634,12 +599,6 @@ client_->SendStopRecordingFramesResponse(command_id, response_data); } -void PageHandler::QueryUsageAndQuotaCompleted( - DevToolsCommandId command_id, - scoped_refptr<QueryUsageAndQuotaResponse> response_data) { - client_->SendQueryUsageAndQuotaResponse(command_id, response_data); -} - } // namespace page } // namespace devtools } // namespace content
diff --git a/content/browser/devtools/protocol/page_handler.h b/content/browser/devtools/protocol/page_handler.h index 27285b5..4ddb67d3 100644 --- a/content/browser/devtools/protocol/page_handler.h +++ b/content/browser/devtools/protocol/page_handler.h
@@ -109,10 +109,6 @@ DevToolsCommandId command_id, scoped_refptr<StopRecordingFramesResponse> response_data); - void QueryUsageAndQuotaCompleted( - DevToolsCommandId command_id, - scoped_refptr<QueryUsageAndQuotaResponse> response); - bool enabled_; bool touch_emulation_enabled_; std::string touch_emulation_configuration_;
diff --git a/content/browser/devtools/protocol/usage_and_quota_query.cc b/content/browser/devtools/protocol/usage_and_quota_query.cc deleted file mode 100644 index 3a1fff0..0000000 --- a/content/browser/devtools/protocol/usage_and_quota_query.cc +++ /dev/null
@@ -1,92 +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 "content/browser/devtools/protocol/usage_and_quota_query.h" - -#include "net/base/net_util.h" - -namespace content { -namespace devtools { -namespace page { - -UsageAndQuotaQuery::UsageAndQuotaQuery( - scoped_refptr<storage::QuotaManager> quota_manager, - const GURL& security_origin, - const Callback& callback) - : quota_manager_(quota_manager), - security_origin_(security_origin), - callback_(callback), - temporary_quota_(0.0), - persistent_quota_(0.0) { - AddRef(); - quota_manager->GetUsageAndQuotaForWebApps( - security_origin, - storage::kStorageTypeTemporary, - base::Bind(&UsageAndQuotaQuery::DidGetTemporaryQuota, this)); - quota_manager->GetPersistentHostQuota( - net::GetHostOrSpecFromURL(security_origin), - base::Bind(&UsageAndQuotaQuery::DidGetPersistentQuota, this)); - GetHostUsage(&temporary_usage_, storage::kStorageTypeTemporary); - GetHostUsage(&persistent_usage_, storage::kStorageTypePersistent); - GetHostUsage(&syncable_usage_, storage::kStorageTypeSyncable); - Release(); -} - -UsageAndQuotaQuery::~UsageAndQuotaQuery() { - callback_.Run(QueryUsageAndQuotaResponse::Create() - ->set_quota(Quota::Create()->set_temporary(temporary_quota_) - ->set_persistent(persistent_quota_)) - ->set_usage(Usage::Create()->set_temporary(temporary_usage_) - ->set_persistent(persistent_usage_) - ->set_syncable(syncable_usage_))); -} - -void UsageAndQuotaQuery::DidGetTemporaryQuota(storage::QuotaStatusCode status, - int64 used_bytes, - int64 quota_in_bytes) { - if (status == storage::kQuotaStatusOk) - temporary_quota_ = quota_in_bytes; -} - -void UsageAndQuotaQuery::DidGetPersistentQuota(storage::QuotaStatusCode status, - int64 value) { - if (status == storage::kQuotaStatusOk) - persistent_quota_ = value; -} - -void UsageAndQuotaQuery::GetHostUsage(UsageItems* list, - storage::StorageType storage_type) { - GetUsageForClient(list, storage_type, storage::QuotaClient::kFileSystem, - usage_item::kIdFilesystem); - GetUsageForClient(list, storage_type, storage::QuotaClient::kDatabase, - usage_item::kIdDatabase); - GetUsageForClient(list, storage_type, storage::QuotaClient::kAppcache, - usage_item::kIdAppcache); - GetUsageForClient(list, storage_type, storage::QuotaClient::kIndexedDatabase, - usage_item::kIdIndexeddatabase); -} - -void UsageAndQuotaQuery::GetUsageForClient(UsageItems* list, - storage::StorageType storage_type, - storage::QuotaClient::ID client_id, - const std::string& client_name) { - if (!quota_manager_->IsTrackingHostUsage(storage_type, client_id)) - return; - quota_manager_->GetHostUsage( - net::GetHostOrSpecFromURL(security_origin_), - storage_type, - client_id, - base::Bind(&UsageAndQuotaQuery::DidGetUsageForClient, - this, list, client_name)); -} - -void UsageAndQuotaQuery::DidGetUsageForClient(UsageItems* list, - const std::string& client_name, - int64 value) { - list->push_back(UsageItem::Create()->set_id(client_name)->set_value(value)); -} - -} // namespace page -} // namespace devtools -} // namespace content
diff --git a/content/browser/devtools/protocol/usage_and_quota_query.h b/content/browser/devtools/protocol/usage_and_quota_query.h deleted file mode 100644 index 972afc1..0000000 --- a/content/browser/devtools/protocol/usage_and_quota_query.h +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_USAGE_AND_QUOTA_QUERY_H_ -#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_USAGE_AND_QUOTA_QUERY_H_ - -#include "content/browser/devtools/protocol/devtools_protocol_handler.h" -#include "storage/browser/quota/quota_manager.h" - -namespace content { -namespace devtools { -namespace page { - -// This class can only be used on IO thread. -class UsageAndQuotaQuery : public base::RefCounted<UsageAndQuotaQuery> { - public: - using Callback = - base::Callback<void(scoped_refptr<QueryUsageAndQuotaResponse>)>; - - UsageAndQuotaQuery(scoped_refptr<storage::QuotaManager> quota_manager, - const GURL& security_origin, - const Callback& callback); - - private: - friend class base::RefCounted<UsageAndQuotaQuery>; - - using UsageItems = std::vector<scoped_refptr<UsageItem>>; - - virtual ~UsageAndQuotaQuery(); - - void DidGetTemporaryQuota(storage::QuotaStatusCode status, - int64 used_bytes, - int64 quota_in_bytes); - - void DidGetPersistentQuota(storage::QuotaStatusCode status, int64 value); - - void GetHostUsage(UsageItems* list, storage::StorageType storage_type); - - void GetUsageForClient(UsageItems* list, - storage::StorageType storage_type, - storage::QuotaClient::ID client_id, - const std::string& client_name); - - void DidGetUsageForClient(UsageItems* list, - const std::string& client_name, - int64 value); - - scoped_refptr<storage::QuotaManager> quota_manager_; - GURL security_origin_; - Callback callback_; - double temporary_quota_; - double persistent_quota_; - UsageItems temporary_usage_; - UsageItems persistent_usage_; - UsageItems syncable_usage_; -}; - -} // namespace page -} // namespace devtools -} // namespace content - -#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_USAGE_AND_QUOTA_QUERY_H_
diff --git a/content/browser/devtools/protocol/worker_handler.cc b/content/browser/devtools/protocol/worker_handler.cc index 9baee177..8eee22d 100644 --- a/content/browser/devtools/protocol/worker_handler.cc +++ b/content/browser/devtools/protocol/worker_handler.cc
@@ -24,6 +24,10 @@ return Response::FallThrough(); } +Response WorkerHandler::DisconnectFromWorker(const std::string& worker_id) { + return Response::FallThrough(); +} + } // namespace worker } // namespace devtools } // namespace content
diff --git a/content/browser/devtools/protocol/worker_handler.h b/content/browser/devtools/protocol/worker_handler.h index b4ff38f55..60b594f 100644 --- a/content/browser/devtools/protocol/worker_handler.h +++ b/content/browser/devtools/protocol/worker_handler.h
@@ -22,6 +22,8 @@ Response DisconnectFromWorker(int worker_id); + Response DisconnectFromWorker(const std::string& worker_id); + private: scoped_ptr<Client> client_;
diff --git a/content/browser/dom_storage/session_storage_database.cc b/content/browser/dom_storage/session_storage_database.cc index 6e47a1f..3afc669 100644 --- a/content/browser/dom_storage/session_storage_database.cc +++ b/content/browser/dom_storage/session_storage_database.cc
@@ -236,9 +236,14 @@ } bool SessionStorageDatabase::DeleteNamespace(const std::string& namespace_id) { - if (!LazyOpen(false)) { - // No need to create the database if it doesn't exist. - return true; + { + // The caller should have called other methods to open the DB before this + // function. Otherwise, DB stores nothing interesting related to the + // specified namespace. + // Do nothing if the DB is not open (or we know it has failed already), + base::AutoLock auto_lock(db_lock_); + if (!IsOpen() || db_error_ || is_inconsistent_) + return false; } DBOperation operation(this); // Itereate through the areas in the namespace.
diff --git a/content/browser/fileapi/blob_storage_context_unittest.cc b/content/browser/fileapi/blob_storage_context_unittest.cc index 9602b3a..29270b7 100644 --- a/content/browser/fileapi/blob_storage_context_unittest.cc +++ b/content/browser/fileapi/blob_storage_context_unittest.cc
@@ -2,6 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "storage/browser/blob/blob_storage_context.h" + +#include <limits> +#include <string> + #include "base/files/file_path.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" @@ -11,24 +16,19 @@ #include "content/browser/fileapi/blob_storage_host.h" #include "storage/browser/blob/blob_data_builder.h" #include "storage/browser/blob/blob_data_handle.h" +#include "storage/browser/blob/blob_data_item.h" #include "storage/browser/blob/blob_data_snapshot.h" -#include "storage/browser/blob/blob_storage_context.h" #include "testing/gtest/include/gtest/gtest.h" using storage::BlobDataBuilder; using storage::BlobDataHandle; +using storage::BlobDataItem; using storage::BlobDataSnapshot; using storage::BlobStorageContext; using storage::DataElement; namespace content { - namespace { -// This is necessary to clean up the blobs after the handles are released. -void RunEventLoopTillIdle() { - base::RunLoop run_loop; - run_loop.RunUntilIdle(); -} void SetupBasicBlob(BlobStorageHost* host, const std::string& id) { EXPECT_TRUE(host->StartBuildingBlob(id)); @@ -38,6 +38,7 @@ EXPECT_TRUE(host->FinishBuildingBlob(id, "text/plain")); EXPECT_FALSE(host->StartBuildingBlob(id)); } + } // namespace TEST(BlobStorageContextTest, IncrementDecrementRef) { @@ -54,7 +55,7 @@ blob_data_handle = context.GetBlobDataFromUUID(kId); EXPECT_TRUE(blob_data_handle); blob_data_handle.reset(); - RunEventLoopTillIdle(); + base::RunLoop().RunUntilIdle(); // Make sure its still there after inc/dec. EXPECT_TRUE(host.IncrementBlobRefCount(kId)); @@ -62,7 +63,7 @@ blob_data_handle = context.GetBlobDataFromUUID(kId); EXPECT_TRUE(blob_data_handle); blob_data_handle.reset(); - RunEventLoopTillIdle(); + base::RunLoop().RunUntilIdle(); // Make sure it goes away in the end. EXPECT_TRUE(host.DecrementBlobRefCount(kId)); @@ -113,7 +114,7 @@ // Should disappear after dropping both handles. blob_data_handle.reset(); another_handle.reset(); - RunEventLoopTillIdle(); + base::RunLoop().RunUntilIdle(); blob_data_handle = context.GetBlobDataFromUUID(kId); EXPECT_FALSE(blob_data_handle); @@ -147,11 +148,11 @@ EXPECT_EQ(10lu, context.memory_usage()); blob_data_handle.reset(); - RunEventLoopTillIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(10lu, context.memory_usage()); blob_data_handle2.reset(); - RunEventLoopTillIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(0lu, context.memory_usage()); } @@ -190,7 +191,7 @@ blob_data_handle.reset(); data2.reset(); - RunEventLoopTillIdle(); + base::RunLoop().RunUntilIdle(); blob_data_handle = context.GetBlobDataFromUUID(kId1); EXPECT_FALSE(blob_data_handle); @@ -205,7 +206,7 @@ scoped_ptr<BlobDataHandle> blob_data_handle3 = context.AddFinishedBlob(&builder3); blob_data_handle2.reset(); - RunEventLoopTillIdle(); + base::RunLoop().RunUntilIdle(); blob_data_handle2 = context.GetBlobDataFromUUID(kId2); EXPECT_FALSE(blob_data_handle2); @@ -222,7 +223,43 @@ blob_data_handle.reset(); blob_data_handle2.reset(); blob_data_handle3.reset(); - RunEventLoopTillIdle(); + base::RunLoop().RunUntilIdle(); +} + +TEST(BlobStorageContextTest, AddFinishedBlob_LargeOffset) { + // A value which does not fit in a 4-byte data type. Used to confirm that + // large values are supported on 32-bit Chromium builds. Regression test for: + // crbug.com/458122. + const uint64_t kLargeSize = std::numeric_limits<uint64_t>::max(); + + const uint64_t kBlobLength = 5; + const std::string kId1("id1"); + const std::string kId2("id2"); + base::MessageLoop fake_io_message_loop; + + BlobDataBuilder builder1(kId1); + builder1.AppendFileSystemFile(GURL(), 0, kLargeSize, base::Time::Now()); + + BlobDataBuilder builder2(kId2); + builder2.AppendBlob(kId1, kLargeSize - kBlobLength, kBlobLength); + + BlobStorageContext context; + scoped_ptr<BlobDataHandle> blob_data_handle1 = + context.AddFinishedBlob(&builder1); + scoped_ptr<BlobDataHandle> blob_data_handle2 = + context.AddFinishedBlob(&builder2); + + ASSERT_TRUE(blob_data_handle1); + ASSERT_TRUE(blob_data_handle2); + scoped_ptr<BlobDataSnapshot> data = blob_data_handle2->CreateSnapshot(); + ASSERT_EQ(1u, data->items().size()); + const scoped_refptr<BlobDataItem> item = data->items()[0]; + EXPECT_EQ(kLargeSize - kBlobLength, item->offset()); + EXPECT_EQ(kBlobLength, item->length()); + + blob_data_handle1.reset(); + blob_data_handle2.reset(); + base::RunLoop().RunUntilIdle(); } TEST(BlobStorageContextTest, CompoundBlobs) { @@ -276,7 +313,7 @@ EXPECT_EQ(*data, canonicalized_blob_data2); blob_data_handle.reset(); - RunEventLoopTillIdle(); + base::RunLoop().RunUntilIdle(); } TEST(BlobStorageContextTest, PublicBlobUrls) { @@ -297,7 +334,7 @@ EXPECT_EQ(kId, blob_data_handle->uuid()); scoped_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot(); blob_data_handle.reset(); - RunEventLoopTillIdle(); + base::RunLoop().RunUntilIdle(); // The url registration should keep the blob alive even after // explicit references are dropped. @@ -305,7 +342,7 @@ blob_data_handle = context.GetBlobDataFromPublicURL(kUrl); EXPECT_TRUE(blob_data_handle); blob_data_handle.reset(); - RunEventLoopTillIdle(); + base::RunLoop().RunUntilIdle(); // Finally get rid of the url registration and the blob. EXPECT_TRUE(host.RevokePublicBlobURL(kUrl));
diff --git a/content/browser/frame_host/frame_tree_unittest.cc b/content/browser/frame_host/frame_tree_unittest.cc index ad4fd75..27285fbc 100644 --- a/content/browser/frame_host/frame_tree_unittest.cc +++ b/content/browser/frame_host/frame_tree_unittest.cc
@@ -69,13 +69,9 @@ void RenderFrameHostChanged(RenderFrameHost* old_host, RenderFrameHost* new_host) override { - // TODO(nasko): Re-enable this logging once RenderFrameHostChanged observer - // methods are fixed. See https://crbug.com/450799. - /* if (old_host) - LogWhatHappened("RenderFrameChanged(old)", old_host); - LogWhatHappened("RenderFrameChanged(new)", new_host); - */ + LogWhatHappened("RenderFrameHostChanged(old)", old_host); + LogWhatHappened("RenderFrameHostChanged(new)", new_host); } void RenderFrameDeleted(RenderFrameHost* render_frame_host) override { @@ -213,9 +209,15 @@ // Simulate attaching a series of frames to build the frame tree. main_test_rfh()->OnCreateChildFrame(14, std::string(), SandboxFlags::NONE); - EXPECT_EQ("RenderFrameCreated(14) -> 1: [14: []]", activity.GetLog()); + EXPECT_EQ( + "RenderFrameHostChanged(new)(14) -> 1: []\n" + "RenderFrameCreated(14) -> 1: [14: []]", + activity.GetLog()); main_test_rfh()->OnCreateChildFrame(18, std::string(), SandboxFlags::NONE); - EXPECT_EQ("RenderFrameCreated(18) -> 1: [14: [], 18: []]", activity.GetLog()); + EXPECT_EQ( + "RenderFrameHostChanged(new)(18) -> 1: [14: []]\n" + "RenderFrameCreated(18) -> 1: [14: [], 18: []]", + activity.GetLog()); frame_tree->RemoveFrame(root->child_at(0)); EXPECT_EQ("RenderFrameDeleted(14) -> 1: [18: []]", activity.GetLog()); frame_tree->RemoveFrame(root->child_at(0)); @@ -228,9 +230,15 @@ TreeWalkingWebContentsLogger activity(contents()); main_test_rfh()->OnCreateChildFrame(22, std::string(), SandboxFlags::NONE); - EXPECT_EQ("RenderFrameCreated(22) -> 1: [22: []]", activity.GetLog()); + EXPECT_EQ( + "RenderFrameHostChanged(new)(22) -> 1: []\n" + "RenderFrameCreated(22) -> 1: [22: []]", + activity.GetLog()); main_test_rfh()->OnCreateChildFrame(23, std::string(), SandboxFlags::NONE); - EXPECT_EQ("RenderFrameCreated(23) -> 1: [22: [], 23: []]", activity.GetLog()); + EXPECT_EQ( + "RenderFrameHostChanged(new)(23) -> 1: [22: []]\n" + "RenderFrameCreated(23) -> 1: [22: [], 23: []]", + activity.GetLog()); // Crash the renderer main_test_rfh()->OnMessageReceived(FrameHostMsg_RenderProcessGone(
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc index 3492196..cb14e671 100644 --- a/content/browser/frame_host/navigation_controller_impl_unittest.cc +++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -316,7 +316,8 @@ urls[i] = GURL(base::StringPrintf("http://www.a.com/%d", i)); } - main_test_rfh()->PrepareForCommit(urls[0]); + main_test_rfh()->SendRendererInitiatedNavigationRequest(urls[0], true); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, urls[0]); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -326,7 +327,8 @@ EXPECT_FALSE(controller.CanGoToOffset(1)); for (int i = 1; i <= 4; ++i) { - main_test_rfh()->PrepareForCommit(urls[i]); + main_test_rfh()->SendRendererInitiatedNavigationRequest(urls[i], true); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(i, urls[i]); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -362,7 +364,7 @@ url_index += offset; // Check that the GoToOffset will land on the expected page. EXPECT_EQ(urls[url_index], controller.GetPendingEntry()->GetVirtualURL()); - main_test_rfh()->PrepareForCommit(urls[url_index]); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(url_index, urls[url_index]); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -407,7 +409,7 @@ // We should have gotten no notifications from the preceeding checks. EXPECT_EQ(0U, notifications.size()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -447,7 +449,7 @@ // Simulate the beforeunload ack for the cross-site transition, and then the // commit. - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommit(); contents()->GetPendingMainFrame()->SendNavigate(1, url2); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -489,7 +491,7 @@ controller.LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -500,7 +502,7 @@ // Simulate the beforeunload ack for the cross-site transition, and then the // commit. - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommit(); contents()->GetPendingMainFrame()->SendNavigate(1, url2); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -619,7 +621,7 @@ controller.LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); EXPECT_EQ(0U, notifications.size()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -631,7 +633,7 @@ controller.LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); EXPECT_EQ(0U, notifications.size()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -671,7 +673,7 @@ params.is_post = true; params.post_id = 123; params.page_state = PageState::CreateForTesting(url1, false, 0, 0); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigateWithParams(¶ms); // The post data should be visible. @@ -682,7 +684,7 @@ controller.LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); // We should not have produced a new session history entry. @@ -773,7 +775,7 @@ const GURL kExistingURL1("http://eh"); controller.LoadURL( kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(kExistingURL1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, kExistingURL1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -785,9 +787,9 @@ EXPECT_EQ(0U, notifications.size()); // After the beforeunload but before it commits, do a new navigation. - main_test_rfh()->PrepareForCommit(kExistingURL2); + main_test_rfh()->PrepareForCommit(); const GURL kNewURL("http://see"); - main_test_rfh()->PrepareForCommit(kNewURL); + main_test_rfh()->PrepareForCommit(); contents()->GetMainFrame()->SendNavigate(3, kNewURL); // There should no longer be any pending entry, and the third navigation we @@ -811,7 +813,7 @@ const GURL kExistingURL1("http://foo/eh"); controller.LoadURL( kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(kExistingURL1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, kExistingURL1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -819,7 +821,7 @@ const GURL kExistingURL2("http://foo/bee"); controller.LoadURL( kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(kExistingURL2); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, kExistingURL2); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -833,7 +835,8 @@ // Before that commits, do a new navigation. const GURL kNewURL("http://foo/see"); - main_test_rfh()->PrepareForCommit(kNewURL); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kNewURL, true); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(3, kNewURL); // There should no longer be any pending entry, and the third navigation we @@ -859,7 +862,7 @@ kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); // Pretend it has bindings so we can tell if we incorrectly copy it. main_test_rfh()->GetRenderViewHost()->AllowBindings(2); - main_test_rfh()->PrepareForCommit(kExistingURL1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, kExistingURL1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -868,7 +871,7 @@ const GURL kExistingURL2("http://foo/eh"); controller.LoadURL( kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(kExistingURL2); + main_test_rfh()->PrepareForCommit(); TestRenderFrameHost* foo_rfh = contents()->GetPendingMainFrame(); foo_rfh->SendNavigate(1, kExistingURL2); EXPECT_EQ(1U, navigation_entry_committed_counter_); @@ -885,7 +888,8 @@ // Before that commits, do a new navigation. const GURL kNewURL("http://foo/bee"); - foo_rfh->PrepareForCommit(kNewURL); + foo_rfh->SendRendererInitiatedNavigationRequest(kNewURL, true); + foo_rfh->PrepareForCommit(); foo_rfh->SendNavigate(3, kNewURL); // There should no longer be any pending entry, and the third navigation we @@ -910,7 +914,7 @@ const GURL kExistingURL1("http://foo/eh"); controller.LoadURL( kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(kExistingURL1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, kExistingURL1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -918,7 +922,7 @@ const GURL kExistingURL2("http://foo/bee"); controller.LoadURL( kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(kExistingURL2); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, kExistingURL2); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -932,7 +936,8 @@ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); // Before that commits, a back navigation from the renderer commits. - main_test_rfh()->PrepareForCommit(kExistingURL1); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kExistingURL1, true); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, kExistingURL1); // There should no longer be any pending entry, and the back navigation we @@ -972,7 +977,8 @@ // Before that commits, a document.write and location.reload can cause the // renderer to send a FrameNavigate with page_id -1. - main_test_rfh()->PrepareForCommit(kExistingURL); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kExistingURL, true); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(-1, kExistingURL); // This should clear the pending entry and notify of a navigation state @@ -1123,7 +1129,7 @@ // Commit. TestRenderFrameHost* orig_rfh = contents()->GetMainFrame(); - orig_rfh->PrepareForCommit(url1); + orig_rfh->PrepareForCommit(); orig_rfh->SendNavigate(0, url1); EXPECT_EQ(controller.GetEntryCount(), 1); EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); @@ -1140,7 +1146,7 @@ // privileged url. controller.LoadURL( url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - orig_rfh->PrepareForCommit(url2); + orig_rfh->PrepareForCommit(); TestRenderFrameHost* new_rfh = contents()->GetPendingMainFrame(); new_rfh->GetRenderViewHost()->AllowBindings(1); new_rfh->SendNavigate(1, url2); @@ -1153,7 +1159,7 @@ // Going back, the first entry should still appear unprivileged. controller.GoBack(); - new_rfh->PrepareForCommit(url1); + new_rfh->PrepareForCommit(); orig_rfh->SendNavigate(0, url1); EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); EXPECT_EQ(0, controller.GetLastCommittedEntry()->bindings()); @@ -1169,7 +1175,7 @@ controller.LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); EXPECT_EQ(0U, notifications.size()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -1194,7 +1200,7 @@ // See http://crbug.com/96041. EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -1224,7 +1230,7 @@ controller.LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -1232,7 +1238,7 @@ controller.Reload(true); EXPECT_EQ(0U, notifications.size()); - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommitWithServerRedirect(url2); main_test_rfh()->SendNavigate(1, url2); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -1290,7 +1296,7 @@ controller.LoadURL( original_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); EXPECT_EQ(0U, notifications.size()); - main_test_rfh()->PrepareForCommit(final_url); + main_test_rfh()->PrepareForCommitWithServerRedirect(final_url); main_test_rfh()->SendNavigateWithOriginalRequestURL( 0, final_url, original_url); EXPECT_EQ(1U, navigation_entry_committed_counter_); @@ -1323,7 +1329,7 @@ EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty()); // Send that the navigation has proceeded; say it got redirected again. - main_test_rfh()->PrepareForCommit(final_url); + main_test_rfh()->PrepareForCommitWithServerRedirect(final_url); main_test_rfh()->SendNavigate(0, final_url); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -1487,14 +1493,14 @@ controller.LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; controller.LoadURL( url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, url2); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -1511,7 +1517,7 @@ EXPECT_FALSE(controller.CanGoBack()); EXPECT_TRUE(controller.CanGoForward()); - main_test_rfh()->PrepareForCommit(url3); + main_test_rfh()->PrepareForCommitWithServerRedirect(url3); main_test_rfh()->SendNavigate(2, url3); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -1569,15 +1575,19 @@ const GURL kUrl3("http://foo/3"); // First navigate three places so we have some back history. - main_test_rfh()->PrepareForCommit(kUrl1); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1, true); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, kUrl1); - main_test_rfh()->PrepareForCommit(kUrl2); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, true); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, kUrl2); - main_test_rfh()->PrepareForCommit(kUrl3); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl3, true); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(2, kUrl3); // With nothing pending, say we get a navigation to the second entry. - main_test_rfh()->PrepareForCommit(kUrl2); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, true); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, kUrl2); // We know all the entries have the same site instance, so we can just grab @@ -1593,7 +1603,7 @@ // Now go forward to the last item again and say it was committed. controller.GoForward(); - main_test_rfh()->PrepareForCommit(kUrl3); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(2, kUrl3); // Now start going back one to the second page. It will be pending. @@ -1601,9 +1611,10 @@ EXPECT_EQ(1, controller.GetPendingEntryIndex()); EXPECT_EQ(2, controller.GetLastCommittedEntryIndex()); - // Not synthesize a totally new back event to the first page. This will not + // Now synthesize a totally new back event to the first page. This will not // match the pending one. - main_test_rfh()->PrepareForCommit(kUrl1); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1, true); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, kUrl1); // The committed navigation should clear the pending entry. @@ -1623,18 +1634,18 @@ const GURL url1("http://foo1"); const GURL url2("http://foo2"); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, url2); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; controller.GoBack(); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -1659,7 +1670,7 @@ EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(), controller.GetEntryAtIndex(1)->GetTimestamp()); - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, url2); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -1692,17 +1703,17 @@ const GURL url2("http://foo2"); const GURL url3("http://foo3"); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, url2); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; controller.GoBack(); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -1719,7 +1730,7 @@ EXPECT_TRUE(controller.CanGoBack()); EXPECT_FALSE(controller.CanGoForward()); - main_test_rfh()->PrepareForCommit(url3); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(2, url3); EXPECT_EQ(1U, navigation_entry_committed_counter_); navigation_entry_committed_counter_ = 0; @@ -2384,7 +2395,7 @@ GURL url(base::StringPrintf("http://www.a.com/%d", url_index)); controller.LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(url_index, url); } @@ -2397,7 +2408,7 @@ GURL url(base::StringPrintf("http://www.a.com/%d", url_index)); controller.LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(url_index, url); url_index++; @@ -2416,7 +2427,7 @@ url = GURL(base::StringPrintf("http:////www.a.com/%d", url_index)); controller.LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(url_index, url); url_index++; } @@ -2581,18 +2592,18 @@ const GURL url1("http://foo"); controller.LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); // Now navigate somewhere with an interstitial. const GURL url2("http://bar"); - controller.LoadURL( - url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); + controller.LoadURL(url2, Referrer(), ui::PAGE_TRANSITION_TYPED, + std::string()); controller.GetPendingEntry()->set_page_type(PAGE_TYPE_INTERSTITIAL); // At this point the interstitial will be displayed and the load will still // be pending. If the user continues, the load will commit. - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, url2); // The page should be a normal page again. @@ -2613,23 +2624,23 @@ controller.LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); controller.LoadURL( url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, url2); controller.LoadURL( url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url3); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(2, url3); controller.LoadURL( url4, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url4); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(3, url4); controller.LoadURL( url5, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url5); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(4, url5); // Try to remove the last entry. Will fail because it is the current entry. @@ -2644,7 +2655,7 @@ EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 2)); // Now commit and delete the last entry. - main_test_rfh()->PrepareForCommit(url4); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(3, url4); EXPECT_TRUE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1)); EXPECT_EQ(4, controller.GetEntryCount()); @@ -2675,15 +2686,15 @@ controller.LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url1); controller.LoadURL( url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, url2); controller.LoadURL( url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url3); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(2, url3); // Go back, but don't commit yet. Check that we can't delete the current @@ -2702,7 +2713,7 @@ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); // Now commit and ensure we land on the right entry. - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, url2); EXPECT_EQ(2, controller.GetEntryCount()); EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); @@ -2725,11 +2736,11 @@ controller.LoadURL( url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url0); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url0); controller.LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, url1); notifications.Reset(); @@ -2756,7 +2767,7 @@ // Navigate. controller.LoadURL( url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(2, url2); // We should have navigated, transient entry should be gone. @@ -2768,7 +2779,8 @@ transient_entry->SetURL(transient_url); controller.SetTransientEntry(transient_entry); EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); - main_test_rfh()->PrepareForCommit(url3); + main_test_rfh()->SendRendererInitiatedNavigationRequest(url3, true); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(3, url3); // Transient entry should be gone. EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL()); @@ -2781,7 +2793,7 @@ transient_entry->SetURL(transient_url); controller.SetTransientEntry(transient_entry); EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); - main_test_rfh()->PrepareForCommit(url4); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(4, url4); EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL()); EXPECT_EQ(controller.GetEntryCount(), 5); @@ -2797,7 +2809,9 @@ // Transient entry should be gone. EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL()); EXPECT_EQ(controller.GetEntryCount(), 5); - main_test_rfh()->PrepareForCommit(url3); + + main_test_rfh()->SendRendererInitiatedNavigationRequest(url3, false); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(3, url3); // Add a transient and go to an entry before the current one. @@ -2811,7 +2825,7 @@ EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL()); // Visible entry does not update for history navigations until commit. EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL()); - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, url1); EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL()); @@ -2826,7 +2840,7 @@ // land on url2 (which is visible after the commit). EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL()); EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL()); - main_test_rfh()->PrepareForCommit(url2); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(2, url2); EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL()); @@ -2841,7 +2855,7 @@ EXPECT_FALSE(controller.GetTransientEntry()); EXPECT_EQ(url3, controller.GetPendingEntry()->GetURL()); EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL()); - main_test_rfh()->PrepareForCommit(url3); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(3, url3); EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL()); @@ -2850,7 +2864,9 @@ transient_entry->SetURL(transient_url); controller.SetTransientEntry(transient_entry); EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); - main_test_rfh()->PrepareForCommit(url3_ref); + + main_test_rfh()->SendRendererInitiatedNavigationRequest(url3_ref, false); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(3, url3_ref); // Transient entry should be gone. EXPECT_FALSE(controller.GetTransientEntry()); @@ -2875,7 +2891,7 @@ // Load |url0|, and start a pending navigation to |url1|. controller.LoadURL( url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - main_test_rfh()->PrepareForCommit(url0); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url0); controller.LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); @@ -2898,7 +2914,7 @@ EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0); // Load of |transient_url| completes. - main_test_rfh()->PrepareForCommit(transient_url); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, transient_url); ASSERT_EQ(controller.GetEntryCount(), 2); EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0); @@ -2977,7 +2993,7 @@ url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); EXPECT_EQ(url0, controller.GetPendingEntry()->GetURL()); EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL()); - main_test_rfh()->PrepareForCommit(url0); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(0, url0); // For link clicks (renderer-initiated navigations), the pending entry should @@ -2991,7 +3007,7 @@ // After commit, both visible should be updated, there should be no pending // entry, and we should no longer treat the entry as renderer-initiated. - main_test_rfh()->PrepareForCommit(url1); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(1, url1); EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL()); EXPECT_FALSE(controller.GetPendingEntry()); @@ -4125,7 +4141,7 @@ EXPECT_EQ(1, controller.GetEntryCount()); // Try to commit the pending entry. - main_test_rfh()->PrepareForCommit(url3); + main_test_rfh()->PrepareForCommit(); main_test_rfh()->SendNavigate(2, url3); EXPECT_EQ(-1, controller.GetPendingEntryIndex()); EXPECT_FALSE(controller.GetPendingEntry()); @@ -4411,10 +4427,11 @@ ASSERT_TRUE(entry); EXPECT_TRUE(entry->should_clear_history_list()); - // Assume that the RF correctly cleared its history and commit the navigation. + // Assume that the RenderFrame correctly cleared its history and commit the + // navigation. if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableBrowserSideNavigation)) { - contents()->GetMainFrame()->PrepareForCommit(entry->GetURL()); + contents()->GetMainFrame()->SendBeforeUnloadACK(true); } contents()->GetPendingMainFrame()-> set_simulate_history_list_was_cleared(true);
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc index 7e39192..864c7c3 100644 --- a/content/browser/frame_host/navigation_entry_impl.cc +++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -351,4 +351,8 @@ UMA_HISTOGRAM_MEMORY_KB("Overscroll.ScreenshotSize", screenshot_->size()); } +GURL NavigationEntryImpl::GetHistoryURLForDataURL() const { + return GetBaseURLForDataURL().is_empty() ? GURL() : GetVirtualURL(); +} + } // namespace content
diff --git a/content/browser/frame_host/navigation_entry_impl.h b/content/browser/frame_host/navigation_entry_impl.h index 8fadcb3..c69c978e 100644 --- a/content/browser/frame_host/navigation_entry_impl.h +++ b/content/browser/frame_host/navigation_entry_impl.h
@@ -225,6 +225,9 @@ frame_tree_node_id_ = frame_tree_node_id; } + // Returns the history URL for a data URL to use in Blink. + GURL GetHistoryURLForDataURL() const; + #if defined(OS_ANDROID) base::TimeTicks intent_received_timestamp() const { return intent_received_timestamp_;
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index 8a599b1..75e61001 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc
@@ -50,6 +50,13 @@ } // namespace // static +bool NavigationRequest::ShouldMakeNetworkRequest(const GURL& url) { + // Data urls should not make network requests. + // TODO(clamy): same document navigations should not make network requests. + return !url.SchemeIs(url::kDataScheme); +} + +// static scoped_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated( FrameTreeNode* frame_tree_node, const NavigationEntryImpl& entry, @@ -90,7 +97,8 @@ CommonNavigationParams(entry.GetURL(), entry.GetReferrer(), entry.GetTransitionType(), navigation_type, !entry.IsViewSourceMode(),ui_timestamp, - report_type), + report_type, entry.GetBaseURLForDataURL(), + entry.GetHistoryURLForDataURL()), BeginNavigationParams(method, headers.ToString(), LoadFlagFromNavigationType(navigation_type), false), @@ -158,13 +166,24 @@ NavigationRequest::~NavigationRequest() { } -void NavigationRequest::BeginNavigation() { +bool NavigationRequest::BeginNavigation() { DCHECK(!loader_); DCHECK(state_ == NOT_STARTED || state_ == WAITING_FOR_RENDERER_RESPONSE); state_ = STARTED; - loader_ = NavigationURLLoader::Create( - frame_tree_node_->navigator()->GetController()->GetBrowserContext(), - frame_tree_node_->frame_tree_node_id(), info_.Pass(), this); + + if (ShouldMakeNetworkRequest(common_params_.url)) { + loader_ = NavigationURLLoader::Create( + frame_tree_node_->navigator()->GetController()->GetBrowserContext(), + frame_tree_node_->frame_tree_node_id(), info_.Pass(), this); + return true; + } + + // There is no need to make a network request for this navigation, so commit + // it immediately. + state_ = RESPONSE_STARTED; + frame_tree_node_->navigator()->CommitNavigation( + frame_tree_node_, nullptr, scoped_ptr<StreamHandle>()); + return false; // TODO(davidben): Fire (and add as necessary) observer methods such as // DidStartProvisionalLoadForFrame for the navigation.
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h index 948dbd1d..56e993d 100644 --- a/content/browser/frame_host/navigation_request.h +++ b/content/browser/frame_host/navigation_request.h
@@ -52,6 +52,10 @@ FAILED, }; + // Helper function to determine if the navigation request to |url| should be + // sent to the network stack. + static bool ShouldMakeNetworkRequest(const GURL& url); + // Creates a request for a browser-intiated navigation. static scoped_ptr<NavigationRequest> CreateBrowserInitiated( FrameTreeNode* frame_tree_node, @@ -70,11 +74,11 @@ ~NavigationRequest() override; - // Called on the UI thread by the Navigator to start the navigation on the IO - // thread. + // Called on the UI thread by the Navigator to start the navigation. Returns + // whether a request was made on the IO thread. // TODO(clamy): see if ResourceRequestBody could be un-refcounted to avoid // threading subtleties. - void BeginNavigation(); + bool BeginNavigation(); const CommonNavigationParams& common_params() const { return common_params_; }
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc index 3e78f54..72f9f87 100644 --- a/content/browser/frame_host/navigator_impl.cc +++ b/content/browser/frame_host/navigator_impl.cc
@@ -94,7 +94,8 @@ params->common_params = CommonNavigationParams( entry.GetURL(), entry.GetReferrer(), entry.GetTransitionType(), GetNavigationType(controller->GetBrowserContext(), entry, reload_type), - !entry.IsViewSourceMode(), ui_timestamp, report_type); + !entry.IsViewSourceMode(), ui_timestamp, report_type, + entry.GetBaseURLForDataURL(), entry.GetHistoryURLForDataURL()); params->commit_params = CommitNavigationParams( entry.GetPageState(), entry.GetIsOverridingUserAgent(), navigation_start); params->is_post = entry.GetHasPostData(); @@ -106,10 +107,6 @@ entry.GetBrowserInitiatedPostData()->size()); } - if (!entry.GetBaseURLForDataURL().is_empty()) { - params->base_url_for_data_url = entry.GetBaseURLForDataURL(); - params->history_url_for_data_url = entry.GetVirtualURL(); - } params->should_replace_current_entry = entry.should_replace_entry(); // This is used by the old performance infrastructure to set up DocumentState // associated with the RenderView. @@ -733,19 +730,22 @@ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableBrowserSideNavigation)); + NavigationRequest* navigation_request = + navigation_request_map_.get(frame_tree_node->frame_tree_node_id()); + DCHECK(navigation_request); + DCHECK(response || + !NavigationRequest::ShouldMakeNetworkRequest( + navigation_request->common_params().url)); + // HTTP 204 (No Content) and HTTP 205 (Reset Content) responses should not // commit; they leave the frame showing the previous page. - if (response->head.headers.get() && + if (response && response->head.headers.get() && (response->head.headers->response_code() == 204 || response->head.headers->response_code() == 205)) { CancelNavigation(frame_tree_node); return; } - NavigationRequest* navigation_request = - navigation_request_map_.get(frame_tree_node->frame_tree_node_id()); - DCHECK(navigation_request); - // Select an appropriate renderer to commit the navigation. RenderFrameHostImpl* render_frame_host = frame_tree_node->render_manager()->GetFrameHostForNavigation( @@ -864,12 +864,13 @@ if (!navigation_request) return; - // First start the request on the IO thread. - navigation_request->BeginNavigation(); - - // Then notify the RenderFrameHostManager so it can speculatively create a - // RenderFrameHost (and potentially a new renderer process) in parallel. - frame_tree_node->render_manager()->BeginNavigation(*navigation_request); + // Start the request. + if (navigation_request->BeginNavigation()) { + // If the request was sent to the IO thread, notify the + // RenderFrameHostManager so it can speculatively create a RenderFrameHost + // (and potentially a new renderer process) in parallel. + frame_tree_node->render_manager()->BeginNavigation(*navigation_request); + } } void NavigatorImpl::RecordNavigationMetrics(
diff --git a/content/browser/frame_host/navigator_impl_unittest.cc b/content/browser/frame_host/navigator_impl_unittest.cc index 82a49874..d7e41e5 100644 --- a/content/browser/frame_host/navigator_impl_unittest.cc +++ b/content/browser/frame_host/navigator_impl_unittest.cc
@@ -163,7 +163,7 @@ // Start a renderer-initiated non-user-initiated navigation. process()->sink().ClearMessages(); - main_test_rfh()->SendBeginNavigationWithURL(kUrl2, false); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, false); FrameTreeNode* node = main_test_rfh()->frame_tree_node(); NavigationRequest* request = GetNavigationRequestForFrameTreeNode(node); ASSERT_TRUE(request); @@ -421,21 +421,14 @@ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node)); // It then redirects to another site. - net::RedirectInfo redirect_info; - redirect_info.status_code = 302; - redirect_info.new_method = "GET"; - redirect_info.new_url = kUrl2; - redirect_info.new_first_party_for_cookies = kUrl2; - scoped_refptr<ResourceResponse> response(new ResourceResponse); - GetLoaderForNavigationRequest(main_request)->CallOnRequestRedirected( - redirect_info, response); + GetLoaderForNavigationRequest(main_request)->SimulateServerRedirect(kUrl2); // The redirect should have been followed. EXPECT_EQ(1, GetLoaderForNavigationRequest(main_request)->redirect_count()); EXPECT_FALSE(GetSpeculativeRenderFrameHost(node)); // Have the RenderFrameHost commit the navigation. - response = new ResourceResponse; + scoped_refptr<ResourceResponse> response(new ResourceResponse); GetLoaderForNavigationRequest(main_request)->CallOnResponseStarted( response, MakeEmptyStream()); TestRenderFrameHost* final_speculative_rfh = @@ -556,7 +549,7 @@ // Now receive a renderer-initiated user-initiated request. It should replace // the current NavigationRequest. - main_test_rfh()->SendBeginNavigationWithURL(kUrl2, true); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, true); NavigationRequest* request2 = GetNavigationRequestForFrameTreeNode(node); ASSERT_TRUE(request2); EXPECT_EQ(kUrl2, request2->common_params().url); @@ -605,7 +598,7 @@ // Start a renderer-initiated user-initiated navigation to the 1st URL. process()->sink().ClearMessages(); - main_test_rfh()->SendBeginNavigationWithURL(kUrl1, true); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1, true); NavigationRequest* request1 = GetNavigationRequestForFrameTreeNode(node); ASSERT_TRUE(request1); EXPECT_EQ(kUrl1, request1->common_params().url); @@ -615,7 +608,7 @@ // Now receive a renderer-initiated non-user-initiated request. Nothing should // change. - main_test_rfh()->SendBeginNavigationWithURL(kUrl2, false); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, false); NavigationRequest* request2 = GetNavigationRequestForFrameTreeNode(node); ASSERT_TRUE(request2); EXPECT_EQ(request1, request2); @@ -660,7 +653,7 @@ // Now receive a renderer-initiated non-user-initiated request. Nothing should // change. - main_test_rfh()->SendBeginNavigationWithURL(kUrl2, false); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, false); NavigationRequest* request2 = GetNavigationRequestForFrameTreeNode(node); ASSERT_TRUE(request2); EXPECT_EQ(request1, request2); @@ -699,7 +692,7 @@ // Start a renderer-initiated non-user-initiated navigation to the 1st URL. process()->sink().ClearMessages(); - main_test_rfh()->SendBeginNavigationWithURL(kUrl1, false); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1, false); NavigationRequest* request1 = GetNavigationRequestForFrameTreeNode(node); ASSERT_TRUE(request1); EXPECT_EQ(kUrl1, request1->common_params().url); @@ -711,7 +704,7 @@ EXPECT_TRUE(loader1); // Now receive a 2nd similar request that should replace the current one. - main_test_rfh()->SendBeginNavigationWithURL(kUrl2, false); + main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2, false); NavigationRequest* request2 = GetNavigationRequestForFrameTreeNode(node); EXPECT_EQ(kUrl2, request2->common_params().url); EXPECT_FALSE(request2->browser_initiated()); @@ -750,7 +743,7 @@ ASSERT_TRUE(main_request != NULL); EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD, main_request->common_params().navigation_type); - main_test_rfh()->PrepareForCommit(kUrl); + main_test_rfh()->PrepareForCommit(); EXPECT_FALSE(GetSpeculativeRenderFrameHost(node)); main_test_rfh()->SendNavigate(0, kUrl); @@ -765,7 +758,7 @@ ASSERT_TRUE(main_request != NULL); EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE, main_request->common_params().navigation_type); - main_test_rfh()->PrepareForCommit(kUrl); + main_test_rfh()->PrepareForCommit(); EXPECT_FALSE(GetSpeculativeRenderFrameHost(node)); } @@ -843,14 +836,8 @@ NavigationRequest* main_request = GetNavigationRequestForFrameTreeNode(node); ASSERT_TRUE(main_request); const GURL kUrlRedirect("https://www.google.com/"); - net::RedirectInfo redirect_info; - redirect_info.status_code = 302; - redirect_info.new_method = "GET"; - redirect_info.new_url = kUrlRedirect; - redirect_info.new_first_party_for_cookies = kUrlRedirect; - scoped_refptr<ResourceResponse> response(new ResourceResponse); GetLoaderForNavigationRequest(main_request) - ->CallOnRequestRedirected(redirect_info, response); + ->SimulateServerRedirect(kUrlRedirect); EXPECT_EQ(init_site_instance_id, main_test_rfh()->GetSiteInstance()->GetId()); speculative_rfh = GetSpeculativeRenderFrameHost(node); ASSERT_TRUE(speculative_rfh); @@ -863,7 +850,7 @@ // Commit the navigation with Navigator by simulating the call to // OnResponseStarted. - response = new ResourceResponse; + scoped_refptr<ResourceResponse> response(new ResourceResponse); GetLoaderForNavigationRequest(main_request) ->CallOnResponseStarted(response, MakeEmptyStream()); speculative_rfh = GetSpeculativeRenderFrameHost(node); @@ -941,4 +928,50 @@ EXPECT_FALSE(rfhm->IsOnSwappedOutList(rfh1)); } +// PlzNavigate: Verify that data urls are properly handled. +TEST_F(NavigatorTestWithBrowserSideNavigation, DataUrls) { + const GURL kUrl1("http://wikipedia.org/"); + const GURL kUrl2("data:text/html,test"); + + // Navigate to an initial site. + contents()->NavigateAndCommit(kUrl1); + FrameTreeNode* node = main_test_rfh()->frame_tree_node(); + + // Navigate to a data url. + RequestNavigation(node, kUrl2); + NavigationRequest* navigation_request = + GetNavigationRequestForFrameTreeNode(node); + ASSERT_TRUE(navigation_request); + EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE, + navigation_request->state()); + main_test_rfh()->SendBeforeUnloadACK(true); + + // The request should not have been sent to the IO thread but committed + // immediately. + EXPECT_EQ(NavigationRequest::RESPONSE_STARTED, + navigation_request->state()); + EXPECT_FALSE(navigation_request->loader_for_testing()); + TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node); + ASSERT_TRUE(speculative_rfh); + speculative_rfh->SendNavigate(0, kUrl2); + EXPECT_EQ(main_test_rfh(), speculative_rfh); + + // Go back to the initial site. + contents()->NavigateAndCommit(kUrl1); + + // Do a renderer-initiated navigation to a data url. The request should not be + // sent to the IO thread, nor committed. + TestRenderFrameHost* main_rfh = main_test_rfh(); + main_rfh->SendRendererInitiatedNavigationRequest(kUrl2, true); + navigation_request = GetNavigationRequestForFrameTreeNode(node); + ASSERT_TRUE(navigation_request); + EXPECT_EQ(NavigationRequest::RESPONSE_STARTED, + navigation_request->state()); + EXPECT_FALSE(navigation_request->loader_for_testing()); + speculative_rfh = GetSpeculativeRenderFrameHost(node); + ASSERT_TRUE(speculative_rfh); + speculative_rfh->SendNavigate(0, kUrl2); + EXPECT_EQ(main_test_rfh(), speculative_rfh); +} + } // namespace content
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 38f4192..272aeb2 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -21,6 +21,7 @@ #include "content/browser/frame_host/frame_accessibility.h" #include "content/browser/frame_host/frame_tree.h" #include "content/browser/frame_host/frame_tree_node.h" +#include "content/browser/frame_host/navigation_request.h" #include "content/browser/frame_host/navigator.h" #include "content/browser/frame_host/navigator_impl.h" #include "content/browser/frame_host/render_frame_host_delegate.h" @@ -1495,11 +1496,11 @@ ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL( GetProcess()->GetID(), params.common_params.url); if (params.common_params.url.SchemeIs(url::kDataScheme) && - params.base_url_for_data_url.SchemeIs(url::kFileScheme)) { + params.common_params.base_url_for_data_url.SchemeIs(url::kFileScheme)) { // If 'data:' is used, and we have a 'file:' base url, grant access to // local files. ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL( - GetProcess()->GetID(), params.base_url_for_data_url); + GetProcess()->GetID(), params.common_params.base_url_for_data_url); } } @@ -1666,6 +1667,8 @@ scoped_ptr<StreamHandle> body, const CommonNavigationParams& common_params, const CommitNavigationParams& commit_params) { + DCHECK((response && body.get()) || + !NavigationRequest::ShouldMakeNetworkRequest(common_params.url)); // TODO(clamy): Check if we have to add security checks for the browser plugin // guests. @@ -1673,9 +1676,11 @@ // completing a RFH swap or unload handler. SetState(RenderFrameHostImpl::STATE_DEFAULT); + const GURL body_url = body.get() ? body->GetURL() : GURL(); + const ResourceResponseHead head = response ? + response->head : ResourceResponseHead(); Send(new FrameMsg_CommitNavigation( - routing_id_, response->head, body->GetURL(), - common_params, commit_params)); + routing_id_, head, body_url, common_params, commit_params)); // TODO(clamy): Check if we should start the throbber for non javascript urls // here.
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc index f9e2bf9..b9328a4 100644 --- a/content/browser/frame_host/render_frame_host_manager.cc +++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -109,6 +109,14 @@ SetRenderFrameHost(CreateRenderFrameHost(site_instance, view_routing_id, frame_routing_id, flags)); + // Notify the delegate of the creation of the current RenderFrameHost. + // Do this only for subframes, as the main frame case is taken care of by + // WebContentsImpl::Init. + if (!frame_tree_node_->IsMainFrame()) { + delegate_->NotifySwappedFromRenderManager( + nullptr, render_frame_host_.get(), false); + } + // Keep track of renderer processes as they start to shut down or are // crashed/killed. registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED, @@ -224,14 +232,18 @@ // Now that we've created a new renderer, be sure to hide it if it isn't // our primary one. Otherwise, we might crash if we try to call Show() // on it later. - if (dest_render_frame_host != render_frame_host_ && - dest_render_frame_host->GetView()) { - dest_render_frame_host->GetView()->Hide(); + if (dest_render_frame_host != render_frame_host_) { + if (dest_render_frame_host->GetView()) + dest_render_frame_host->GetView()->Hide(); } else { - // Notify here as we won't be calling CommitPending (which does the - // notify). - delegate_->NotifySwappedFromRenderManager( - NULL, render_frame_host_.get(), frame_tree_node_->IsMainFrame()); + // TODO(nasko): This is a very ugly hack. The Chrome extensions process + // manager still uses NotificationService and expects to see a + // RenderViewHost changed notification after WebContents and + // RenderFrameHostManager are completely initialized. This should be + // removed once the process manager moves away from NotificationService. + // See https://crbug.com/462682. + delegate_->NotifyMainFrameSwappedFromRenderManager( + nullptr, render_frame_host_->render_view_host()); } }
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h index 15338be2..073908a 100644 --- a/content/browser/frame_host/render_frame_host_manager.h +++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -137,6 +137,11 @@ virtual void NotifySwappedFromRenderManager(RenderFrameHost* old_host, RenderFrameHost* new_host, bool is_main_frame) = 0; + // TODO(nasko): This should be removed once extensions no longer use + // NotificationService. See https://crbug.com/462682. + virtual void NotifyMainFrameSwappedFromRenderManager( + RenderViewHost* old_host, + RenderViewHost* new_host) = 0; virtual NavigationControllerImpl& GetControllerForRenderManager() = 0;
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 34e48e5..23abd2a 100644 --- a/content/browser/frame_host/render_frame_host_manager_unittest.cc +++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -272,7 +272,7 @@ // is replaced without a pending frame being created, and we don't get the // right values for the RFH to navigate: we try to use the old one that has // been deleted in the meantime. - contents()->GetMainFrame()->PrepareForCommit(url); + contents()->GetMainFrame()->PrepareForCommit(); TestRenderFrameHost* old_rfh = contents()->GetMainFrame(); TestRenderFrameHost* active_rfh = contents()->GetPendingMainFrame() @@ -351,7 +351,7 @@ // Navigate to a cross-site URL. contents()->GetController().LoadURL( kDestUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string()); - contents()->GetMainFrame()->PrepareForCommit(kDestUrl); + contents()->GetMainFrame()->PrepareForCommit(); EXPECT_TRUE(contents()->cross_navigation_pending()); // Manually increase the number of active frames in the @@ -430,7 +430,7 @@ // we use the committed one. contents2->GetController().LoadURL( kChromeUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string()); - contents2->GetMainFrame()->PrepareForCommit(kChromeUrl); + contents2->GetMainFrame()->PrepareForCommit(); TestRenderFrameHost* ntp_rfh2 = contents2->GetMainFrame(); EXPECT_FALSE(contents2->cross_navigation_pending()); ntp_rfh2->SendNavigate(100, kChromeUrl); @@ -439,7 +439,7 @@ // requiring a beforeunload ack. contents2->GetController().LoadURL( kDestUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string()); - contents2->GetMainFrame()->PrepareForCommit(kDestUrl); + contents2->GetMainFrame()->PrepareForCommit(); EXPECT_TRUE(contents2->cross_navigation_pending()); TestRenderFrameHost* dest_rfh2 = contents2->GetPendingMainFrame(); ASSERT_TRUE(dest_rfh2); @@ -460,7 +460,7 @@ contents2->GetController().LoadURL( kChromeUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string()); - contents2->GetMainFrame()->PrepareForCommit(kChromeUrl); + contents2->GetMainFrame()->PrepareForCommit(); contents2->GetPendingMainFrame()->SendNavigate(102, kChromeUrl); EXPECT_NE(contents()->GetMainFrame()->GetSiteInstance(), @@ -795,7 +795,7 @@ controller().LoadURL( kUrl, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); // Simulate response from RenderFrame for DispatchBeforeUnload. - contents()->GetMainFrame()->PrepareForCommit(kUrl); + contents()->GetMainFrame()->PrepareForCommit(); ASSERT_TRUE(contents()->GetPendingMainFrame()) << "Expected new pending RenderFrameHost to be created."; RenderFrameHost* last_rfh = contents()->GetPendingMainFrame(); @@ -815,7 +815,7 @@ // Navigate, again. controller().LoadURL( kUrl, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(kUrl); + contents()->GetMainFrame()->PrepareForCommit(); // The same RenderViewHost should be reused. EXPECT_FALSE(contents()->GetPendingMainFrame()); EXPECT_TRUE(last_rfh == contents()->GetMainFrame()); @@ -1075,7 +1075,7 @@ // Now let's simulate the evil page calling history.back(). contents()->OnGoToEntryAtOffset(-1); - contents()->GetMainFrame()->PrepareForCommit(kUrl1); + contents()->GetMainFrame()->PrepareForCommit(); // We should have a new pending RFH. // Note that in this case, the navigation has not committed, so evil_rfh will // not be deleted yet. @@ -1160,7 +1160,7 @@ // (http://crbug.com/93427). contents()->GetController().GoBack(); EXPECT_TRUE(rfh2->IsWaitingForBeforeUnloadACK()); - contents()->GetMainFrame()->PrepareForCommit(kUrl1); + contents()->GetMainFrame()->PrepareForCommit(); EXPECT_FALSE(rfh2->IsWaitingForBeforeUnloadACK()); // The back navigation commits. @@ -1171,7 +1171,7 @@ // We should be able to navigate forward. contents()->GetController().GoForward(); - contents()->GetMainFrame()->PrepareForCommit(kUrl2); + contents()->GetMainFrame()->PrepareForCommit(); const NavigationEntry* entry2 = contents()->GetController().GetPendingEntry(); rfh2->SendNavigate(entry2->GetPageID(), entry2->GetURL()); EXPECT_EQ(rfh2, main_test_rfh()); @@ -1342,7 +1342,7 @@ // Start a back navigation so that rfh1 becomes the pending RFH. contents()->GetController().GoBack(); - contents()->GetMainFrame()->PrepareForCommit(kUrl1); + contents()->GetMainFrame()->PrepareForCommit(); // Disown the opener from rfh2. rfh2->DidDisownOpener(); @@ -1383,7 +1383,7 @@ // Commit a back navigation before the DidDisownOpener message arrives. // rfh1 will be kept alive because of the opener tab. contents()->GetController().GoBack(); - contents()->GetMainFrame()->PrepareForCommit(kUrl1); + contents()->GetMainFrame()->PrepareForCommit(); const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry(); rfh1->SendNavigate(entry1->GetPageID(), entry1->GetURL()); @@ -1449,7 +1449,7 @@ // Reload the initial tab. This should recreate the opener's swapped out RVH // in the original SiteInstance. contents()->GetController().Reload(true); - contents()->GetMainFrame()->PrepareForCommit(kUrl1); + contents()->GetMainFrame()->PrepareForCommit(); EXPECT_EQ(opener1_manager->GetSwappedOutRenderViewHost( rvh1->GetSiteInstance())->GetRoutingID(), test_rvh()->opener_route_id()); @@ -1644,7 +1644,7 @@ kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string()); if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableBrowserSideNavigation)) { - rfh1->PrepareForCommit(kUrl2); + rfh1->PrepareForCommit(); } EXPECT_TRUE(contents()->cross_navigation_pending()); @@ -1669,7 +1669,7 @@ // Navigate to new site, simulating onbeforeunload approval. controller().LoadURL( kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string()); - contents()->GetMainFrame()->PrepareForCommit(kUrl2); + contents()->GetMainFrame()->PrepareForCommit(); EXPECT_TRUE(contents()->cross_navigation_pending()); EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state()); TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame(); @@ -1717,7 +1717,7 @@ // Navigate to new site, simulating onbeforeunload approval. controller().LoadURL( kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string()); - contents()->GetMainFrame()->PrepareForCommit(kUrl2); + contents()->GetMainFrame()->PrepareForCommit(); EXPECT_TRUE(contents()->cross_navigation_pending()); EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state()); TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame(); @@ -1760,7 +1760,7 @@ // Navigate to new site, simulating onbeforeunload approval. controller().LoadURL( kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string()); - rfh1->PrepareForCommit(kUrl2); + rfh1->PrepareForCommit(); EXPECT_TRUE(contents()->cross_navigation_pending()); TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
diff --git a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc index 57c65fbe..b628d437 100644 --- a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc +++ b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
@@ -139,6 +139,7 @@ format, usage)) { // Early out if we cannot fallback to shared memory buffer. if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) || + !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format) || usage != gfx::GpuMemoryBuffer::MAP) { callback.Run(gfx::GpuMemoryBufferHandle()); return;
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc index b949142..18eefc7 100644 --- a/content/browser/gpu/compositor_util.cc +++ b/content/browser/gpu/compositor_util.cc
@@ -316,12 +316,19 @@ bool UseSurfacesEnabled() { #if defined(OS_ANDROID) return false; -#else +#endif + bool enabled = false; +#if (defined(USE_AURA) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX) + enabled = true; +#endif + const base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); - return command_line.HasSwitch(switches::kUseSurfaces); -#endif + // Flags override. + enabled |= command_line.HasSwitch(switches::kUseSurfaces); + enabled &= !command_line.HasSwitch(switches::kDisableSurfaces); + return enabled; } int GpuRasterizationMSAASampleCount() {
diff --git a/content/browser/loader/cross_site_resource_handler.cc b/content/browser/loader/cross_site_resource_handler.cc index 44d24ce..ccdd321 100644 --- a/content/browser/loader/cross_site_resource_handler.cc +++ b/content/browser/loader/cross_site_resource_handler.cc
@@ -68,6 +68,13 @@ RenderFrameHostImpl::FromID(params.global_request_id.child_id, params.render_frame_id); if (rfh) { + if (rfh->GetParent()) { + // We should only swap processes for subframes in --site-per-process mode. + // CrossSiteResourceHandler is not installed on subframe requests in + // default Chrome. + CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSitePerProcess)); + } rfh->OnCrossSiteResponse( params.global_request_id, cross_site_transferring_request.Pass(), params.transfer_url_chain, params.referrer,
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index 19eb7560..e539eaa 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -2149,6 +2149,10 @@ // thread where they can be passed along to the respective RVHs. scoped_ptr<LoadInfoMap> info_map(new LoadInfoMap()); + tracked_objects::ScopedTracker tracking_profile0( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455952 ResourceDispatcherHostImpl::GetLoadInfoForAllRoutes0")); + for (const auto& loader : pending_loaders_) { // Also poll for upload progress on this timer and send upload progress ipc // messages to the plugin process. @@ -2220,6 +2224,10 @@ if (info_map->empty()) return; + tracked_objects::ScopedTracker tracking_profile2( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455952 ResourceDispatcherHostImpl::UpdateLoadInfo2")); + BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&ResourceDispatcherHostImpl::UpdateLoadInfoOnUIThread,
diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc index 5fecd39..8600a75 100644 --- a/content/browser/media/android/browser_media_player_manager.cc +++ b/content/browser/media/android/browser_media_player_manager.cc
@@ -7,6 +7,7 @@ #include "base/android/scoped_java_ref.h" #include "base/command_line.h" #include "content/browser/android/content_view_core_impl.h" +#include "content/browser/android/media_players_observer.h" #include "content/browser/media/android/browser_demuxer_android.h" #include "content/browser/media/android/media_resource_getter_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" @@ -57,10 +58,11 @@ // static BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create( - RenderFrameHost* rfh) { + RenderFrameHost* rfh, + MediaPlayersObserver* audio_monitor) { if (g_factory) - return g_factory(rfh); - return new BrowserMediaPlayerManager(rfh); + return g_factory(rfh, audio_monitor); + return new BrowserMediaPlayerManager(rfh, audio_monitor); } ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const { @@ -121,8 +123,10 @@ } BrowserMediaPlayerManager::BrowserMediaPlayerManager( - RenderFrameHost* render_frame_host) + RenderFrameHost* render_frame_host, + MediaPlayersObserver* audio_monitor) : render_frame_host_(render_frame_host), + audio_monitor_(audio_monitor), fullscreen_player_id_(kInvalidMediaPlayerId), fullscreen_player_is_released_(false), web_contents_(WebContents::FromRenderFrameHost(render_frame_host)), @@ -254,6 +258,12 @@ video_view_->OnVideoSizeChanged(width, height); } +void BrowserMediaPlayerManager::OnAudibleStateChanged( + int player_id, bool is_audible) { + audio_monitor_->OnAudibleStateChanged( + render_frame_host_, player_id, is_audible); +} + media::MediaResourceGetter* BrowserMediaPlayerManager::GetMediaResourceGetter() { if (!media_resource_getter_.get()) { @@ -518,6 +528,7 @@ if ((*it)->player_id() == player_id) { ReleaseMediaResources(player_id); players_.erase(it); + audio_monitor_->RemovePlayer(render_frame_host_, player_id); break; } }
diff --git a/content/browser/media/android/browser_media_player_manager.h b/content/browser/media/android/browser_media_player_manager.h index e0a40132..bec4695 100644 --- a/content/browser/media/android/browser_media_player_manager.h +++ b/content/browser/media/android/browser_media_player_manager.h
@@ -30,6 +30,7 @@ class BrowserDemuxerAndroid; class ContentViewCoreImpl; class ExternalVideoSurfaceContainer; +class MediaPlayersObserver; class RenderFrameHost; class WebContents; @@ -42,7 +43,8 @@ : public media::MediaPlayerManager { public: // Permits embedders to provide an extended version of the class. - typedef BrowserMediaPlayerManager* (*Factory)(RenderFrameHost*); + typedef BrowserMediaPlayerManager* (*Factory)(RenderFrameHost*, + MediaPlayersObserver*); static void RegisterFactory(Factory factory); // Permits embedders to handle custom urls. @@ -50,7 +52,9 @@ media::MediaUrlInterceptor* media_url_interceptor); // Returns a new instance using the registered factory if available. - static BrowserMediaPlayerManager* Create(RenderFrameHost* rfh); + static BrowserMediaPlayerManager* Create( + RenderFrameHost* rfh, + MediaPlayersObserver* audio_monitor); ContentViewCoreImpl* GetContentViewCore() const; @@ -83,6 +87,9 @@ const base::TimeDelta& current_time) override; void OnError(int player_id, int error) override; void OnVideoSizeChanged(int player_id, int width, int height) override; + void OnAudibleStateChanged( + int player_id, bool is_audible_now) override; + media::MediaResourceGetter* GetMediaResourceGetter() override; media::MediaUrlInterceptor* GetMediaUrlInterceptor() override; media::MediaPlayerAndroid* GetFullscreenPlayer() override; @@ -118,7 +125,8 @@ protected: // Clients must use Create() or subclass constructor. - explicit BrowserMediaPlayerManager(RenderFrameHost* render_frame_host); + BrowserMediaPlayerManager(RenderFrameHost* render_frame_host, + MediaPlayersObserver* audio_monitor); WebContents* web_contents() const { return web_contents_; } @@ -168,6 +176,8 @@ RenderFrameHost* const render_frame_host_; + MediaPlayersObserver* audio_monitor_; + // An array of managed players. ScopedVector<media::MediaPlayerAndroid> players_;
diff --git a/content/browser/media/audio_state_provider.cc b/content/browser/media/audio_state_provider.cc new file mode 100644 index 0000000..e09356a5 --- /dev/null +++ b/content/browser/media/audio_state_provider.cc
@@ -0,0 +1,30 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/media/audio_state_provider.h" + +#include "base/logging.h" +#include "content/browser/media/audio_stream_monitor.h" +#include "content/public/browser/web_contents.h" + +namespace content { + +AudioStateProvider::AudioStateProvider(WebContents* contents) + : web_contents_(contents), + was_recently_audible_(false) { + DCHECK(web_contents_); +} + +bool AudioStateProvider::WasRecentlyAudible() const { + return was_recently_audible_; +} + +void AudioStateProvider::Notify(bool new_state) { + if (was_recently_audible_ != new_state) { + was_recently_audible_ = new_state; + web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB); + } +} + +} // namespace content
diff --git a/content/browser/media/audio_state_provider.h b/content/browser/media/audio_state_provider.h new file mode 100644 index 0000000..5bd1b718 --- /dev/null +++ b/content/browser/media/audio_state_provider.h
@@ -0,0 +1,57 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_MEDIA_AUDIO_STATE_PROVIDER_H_ +#define CONTENT_BROWSER_MEDIA_AUDIO_STATE_PROVIDER_H_ + +#include "content/common/content_export.h" + +namespace content { +class WebContents; +class AudioStreamMonitor; + +// This class is associated with a WebContents, and maintains the audible +// state regarding all the players in it. +// The audible state is true if at least one player is playing a sound. +// Whenever the audible state of the WebContents as a whole changes, this +// class sends a notification to it. +// +// Each WebContentsImpl owns an AudioStateProvider +class CONTENT_EXPORT AudioStateProvider { + public: + explicit AudioStateProvider(WebContents* web_contents); + virtual ~AudioStateProvider() {} + + // Indicates whether this service is available on the system. + virtual bool IsAudioStateAvailable() const = 0; + + // If this provider uses monitoring (i.e. measure the signal), + // return its monitor. + virtual AudioStreamMonitor* audio_stream_monitor() = 0; + + // Returns true if the WebContents is playing or has recently been + // playing the sound. + virtual bool WasRecentlyAudible() const; + + void set_was_recently_audible_for_testing(bool value) { + was_recently_audible_ = value; + } + + protected: + // Notify WebContents that the audio state has changed. + void Notify(bool new_state); + + // The WebContents instance instance to receive indicator toggle + // notifications. This pointer should be valid for the lifetime of + // AudioStreamMonitor. + WebContents* const web_contents_; + + // The audio state that is being maintained + bool was_recently_audible_; + +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_AUDIO_STATE_PROVIDER_H_
diff --git a/content/browser/media/audio_stream_monitor.cc b/content/browser/media/audio_stream_monitor.cc index 1d2f76f7..4c0bc0a 100644 --- a/content/browser/media/audio_stream_monitor.cc +++ b/content/browser/media/audio_stream_monitor.cc
@@ -21,23 +21,36 @@ WebContentsImpl* const web_contents = static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost( RenderFrameHost::FromID(render_process_id, render_frame_id))); - return web_contents ? web_contents->audio_stream_monitor() : NULL; + + if (!web_contents) + return nullptr; + + AudioStateProvider* audio_provider = web_contents->audio_state_provider(); + return audio_provider ? audio_provider->audio_stream_monitor() : nullptr; } } // namespace AudioStreamMonitor::AudioStreamMonitor(WebContents* contents) - : web_contents_(contents), - clock_(&default_tick_clock_), - was_recently_audible_(false) { - DCHECK(web_contents_); + : AudioStateProvider(contents), + clock_(&default_tick_clock_) +{ } AudioStreamMonitor::~AudioStreamMonitor() {} +bool AudioStreamMonitor::IsAudioStateAvailable() const { + return media::AudioOutputController::will_monitor_audio_levels(); +} + +// This provider is the monitor. +AudioStreamMonitor* AudioStreamMonitor::audio_stream_monitor() { + return this; +} + bool AudioStreamMonitor::WasRecentlyAudible() const { DCHECK(thread_checker_.CalledOnValidThread()); - return was_recently_audible_; + return AudioStateProvider::WasRecentlyAudible(); } // static @@ -46,7 +59,7 @@ int render_frame_id, int stream_id, const ReadPowerAndClipCallback& read_power_callback) { - if (!monitoring_available()) + if (!media::AudioOutputController::will_monitor_audio_levels()) return; BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, @@ -61,7 +74,7 @@ void AudioStreamMonitor::StopMonitoringStream(int render_process_id, int render_frame_id, int stream_id) { - if (!monitoring_available()) + if (!media::AudioOutputController::will_monitor_audio_levels()) return; BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, @@ -138,16 +151,12 @@ } void AudioStreamMonitor::MaybeToggle() { - const bool indicator_was_on = was_recently_audible_; const base::TimeTicks off_time = last_blurt_time_ + base::TimeDelta::FromMilliseconds(kHoldOnMilliseconds); const base::TimeTicks now = clock_->NowTicks(); const bool should_indicator_be_on = now < off_time; - if (should_indicator_be_on != indicator_was_on) { - was_recently_audible_ = should_indicator_be_on; - web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB); - } + Notify(should_indicator_be_on); if (!should_indicator_be_on) { off_timer_.Stop();
diff --git a/content/browser/media/audio_stream_monitor.h b/content/browser/media/audio_stream_monitor.h index d1a32d5..b3cbf16 100644 --- a/content/browser/media/audio_stream_monitor.h +++ b/content/browser/media/audio_stream_monitor.h
@@ -14,6 +14,7 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "build/build_config.h" +#include "content/browser/media/audio_state_provider.h" #include "content/common/content_export.h" #include "media/audio/audio_output_controller.h" @@ -22,7 +23,6 @@ } namespace content { -class WebContents; // Repeatedly polls audio streams for their power levels, and "debounces" the // information into a simple, binary "was recently audible" result for the audio @@ -32,23 +32,23 @@ // to turn on/off repeatedly and annoy the user. AudioStreamMonitor sends UI // update notifications only when needed, but may be queried at any time. // -// Each WebContentsImpl owns an AudioStreamMonitor. -class CONTENT_EXPORT AudioStreamMonitor { +class CONTENT_EXPORT AudioStreamMonitor : public AudioStateProvider { public: explicit AudioStreamMonitor(WebContents* contents); - ~AudioStreamMonitor(); + ~AudioStreamMonitor() override; // Indicates if audio stream monitoring is available. It's only available if // AudioOutputController can and will monitor output power levels. - static bool monitoring_available() { - return media::AudioOutputController::will_monitor_audio_levels(); - } + bool IsAudioStateAvailable() const override; + + // This provider is a monitor, the method returns |this|. + AudioStreamMonitor* audio_stream_monitor() override; // Returns true if audio has recently been audible from the tab. This is // usually called whenever the tab data model is refreshed; but there are // other use cases as well (e.g., the OOM killer uses this to de-prioritize // the killing of tabs making sounds). - bool WasRecentlyAudible() const; + bool WasRecentlyAudible() const override; // Starts or stops audio level monitoring respectively for the stream owned by // the specified renderer. Safe to call from any thread. @@ -66,10 +66,6 @@ int render_frame_id, int stream_id); - void set_was_recently_audible_for_testing(bool value) { - was_recently_audible_ = value; - } - private: friend class AudioStreamMonitorTest; @@ -112,11 +108,6 @@ // on, |off_timer_| is started to re-invoke this method in the future. void MaybeToggle(); - // The WebContents instance instance to receive indicator toggle - // notifications. This pointer should be valid for the lifetime of - // AudioStreamMonitor. - WebContents* const web_contents_; - // Note: |clock_| is always |&default_tick_clock_|, except during unit // testing. base::DefaultTickClock default_tick_clock_; @@ -134,10 +125,6 @@ // Records the last time at which sound was audible from any stream. base::TimeTicks last_blurt_time_; - // Set to true if the last call to MaybeToggle() determined the indicator - // should be turned on. - bool was_recently_audible_; - // Calls Poll() at regular intervals while |poll_callbacks_| is non-empty. base::RepeatingTimer<AudioStreamMonitor> poll_timer_;
diff --git a/content/browser/media/audio_stream_monitor_unittest.cc b/content/browser/media/audio_stream_monitor_unittest.cc index 0d206216..0607b75 100644 --- a/content/browser/media/audio_stream_monitor_unittest.cc +++ b/content/browser/media/audio_stream_monitor_unittest.cc
@@ -52,7 +52,13 @@ WebContentsImpl* web_contents = reinterpret_cast<WebContentsImpl*>( RenderViewHostTestHarness::web_contents()); web_contents->SetDelegate(&mock_web_contents_delegate_); - monitor_ = web_contents->audio_stream_monitor(); + + AudioStateProvider* provider = web_contents->audio_state_provider(); + ASSERT_TRUE(provider); + + monitor_ = provider->audio_stream_monitor(); + ASSERT_TRUE(monitor_); + const_cast<base::TickClock*&>(monitor_->clock_) = &clock_; }
diff --git a/content/browser/media/capture/content_video_capture_device_core.cc b/content/browser/media/capture/content_video_capture_device_core.cc index b470bcd..c43c623 100644 --- a/content/browser/media/capture/content_video_capture_device_core.cc +++ b/content/browser/media/capture/content_video_capture_device_core.cc
@@ -25,6 +25,7 @@ #include "media/base/bind_to_current_loop.h" #include "media/base/video_capture_types.h" #include "media/base/video_frame.h" +#include "media/base/video_frame_metadata.h" #include "media/base/video_util.h" #include "ui/gfx/geometry/rect.h" @@ -48,20 +49,7 @@ oracle_(base::TimeDelta::FromMicroseconds( static_cast<int64>(1000000.0 / params.requested_format.frame_rate + 0.5 /* to round to nearest int */))), - params_(params), - capture_size_updated_(false) { - switch (params_.requested_format.pixel_format) { - case media::PIXEL_FORMAT_I420: - video_frame_format_ = media::VideoFrame::I420; - break; - case media::PIXEL_FORMAT_TEXTURE: - video_frame_format_ = media::VideoFrame::NATIVE_TEXTURE; - break; - default: - LOG(FATAL) << "Unexpected pixel_format " - << params_.requested_format.pixel_format; - } -} + params_(params) {} ThreadSafeCaptureOracle::~ThreadSafeCaptureOracle() {} @@ -71,19 +59,28 @@ base::TimeTicks event_time, scoped_refptr<media::VideoFrame>* storage, CaptureFrameCallback* callback) { + // Grab the current time before waiting to acquire the |lock_|. + const base::TimeTicks capture_begin_time = base::TimeTicks::Now(); + base::AutoLock guard(lock_); if (!client_) return false; // Capture is stopped. + const media::VideoFrame::Format video_frame_format = + params_.requested_format.pixel_format == media::PIXEL_FORMAT_TEXTURE ? + media::VideoFrame::NATIVE_TEXTURE : media::VideoFrame::I420; + + if (capture_size_.IsEmpty()) + capture_size_ = max_frame_size(); + const gfx::Size visible_size = capture_size_; // Always round up the coded size to multiple of 16 pixels. // See http://crbug.com/402151. - const gfx::Size visible_size = params_.requested_format.frame_size; const gfx::Size coded_size((visible_size.width() + 15) & ~15, (visible_size.height() + 15) & ~15); scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer = - client_->ReserveOutputBuffer(video_frame_format_, coded_size); + client_->ReserveOutputBuffer(video_frame_format, coded_size); const bool should_capture = oracle_.ObserveEventAndDecideCapture(event, damage_rect, event_time); const bool content_is_dirty = @@ -126,9 +123,9 @@ "trigger", event_name); // NATIVE_TEXTURE frames wrap a texture mailbox, which we don't have at the // moment. We do not construct those frames. - if (video_frame_format_ != media::VideoFrame::NATIVE_TEXTURE) { + if (video_frame_format != media::VideoFrame::NATIVE_TEXTURE) { *storage = media::VideoFrame::WrapExternalPackedMemory( - video_frame_format_, + video_frame_format, coded_size, gfx::Rect(visible_size), visible_size, @@ -138,40 +135,41 @@ 0, base::TimeDelta(), base::Closure()); + DCHECK(*storage); } *callback = base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame, this, frame_number, - output_buffer); + output_buffer, + capture_begin_time); return true; } gfx::Size ThreadSafeCaptureOracle::GetCaptureSize() const { base::AutoLock guard(lock_); - return params_.requested_format.frame_size; + return capture_size_.IsEmpty() ? max_frame_size() : capture_size_; } void ThreadSafeCaptureOracle::UpdateCaptureSize(const gfx::Size& source_size) { base::AutoLock guard(lock_); - // If this is the first call to UpdateCaptureSize(), or the receiver supports - // variable resolution, then determine the capture size by treating the - // requested width and height as maxima. - if (!capture_size_updated_ || params_.resolution_change_policy == + // Update |capture_size_| based on |source_size| if either: 1) The resolution + // change policy specifies fixed frame sizes and |capture_size_| has not yet + // been set; or 2) The resolution change policy specifies dynamic frame + // sizes. + if (capture_size_.IsEmpty() || params_.resolution_change_policy == media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT) { - // The capture resolution should not exceed the source frame size. - // In other words it should downscale the image but not upscale it. - if (source_size.width() > params_.requested_format.frame_size.width() || - source_size.height() > params_.requested_format.frame_size.height()) { - gfx::Rect capture_rect = media::ComputeLetterboxRegion( - gfx::Rect(params_.requested_format.frame_size), source_size); - params_.requested_format.frame_size.SetSize( - MakeEven(capture_rect.width()), MakeEven(capture_rect.height())); - } else { - params_.requested_format.frame_size.SetSize( - MakeEven(source_size.width()), MakeEven(source_size.height())); + capture_size_ = source_size; + // The capture size should not exceed the maximum frame size. + if (capture_size_.width() > max_frame_size().width() || + capture_size_.height() > max_frame_size().height()) { + capture_size_ = media::ComputeLetterboxRegion( + gfx::Rect(max_frame_size()), capture_size_).size(); } - capture_size_updated_ = true; + // The capture size must be even and not less than the minimum frame size. + capture_size_ = gfx::Size( + std::max(kMinFrameWidth, MakeEven(capture_size_.width())), + std::max(kMinFrameHeight, MakeEven(capture_size_.height()))); } } @@ -189,6 +187,7 @@ void ThreadSafeCaptureOracle::DidCaptureFrame( int frame_number, const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer, + base::TimeTicks capture_begin_time, const scoped_refptr<media::VideoFrame>& frame, base::TimeTicks timestamp, bool success) { @@ -202,13 +201,14 @@ if (success) { if (oracle_.CompleteCapture(frame_number, ×tamp)) { - media::VideoCaptureFormat format = params_.requested_format; - // TODO(miu): Passing VideoCaptureFormat here introduces ambiguities. The - // following is a hack where frame_size takes on a different meaning than - // everywhere else (i.e., coded size, not visible size). Will fix in - // soon-upcoming code change. - format.frame_size = frame->coded_size(); - client_->OnIncomingCapturedVideoFrame(buffer, format, frame, timestamp); + // TODO(miu): Use the locked-in frame rate from AnimatedContentSampler. + frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, + params_.requested_format.frame_rate); + frame->metadata()->SetTimeTicks( + media::VideoFrameMetadata::CAPTURE_BEGIN_TIME, capture_begin_time); + frame->metadata()->SetTimeTicks( + media::VideoFrameMetadata::CAPTURE_END_TIME, base::TimeTicks::Now()); + client_->OnIncomingCapturedVideoFrame(buffer, frame, timestamp); } } }
diff --git a/content/browser/media/capture/content_video_capture_device_core.h b/content/browser/media/capture/content_video_capture_device_core.h index f56c109..00ac6249d 100644 --- a/content/browser/media/capture/content_video_capture_device_core.h +++ b/content/browser/media/capture/content_video_capture_device_core.h
@@ -62,6 +62,10 @@ return oracle_.min_capture_period(); } + gfx::Size max_frame_size() const { + return params_.requested_format.frame_size; + } + // Returns the current capture resolution. gfx::Size GetCaptureSize() const; @@ -83,6 +87,7 @@ void DidCaptureFrame( int frame_number, const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer, + base::TimeTicks capture_begin_time, const scoped_refptr<media::VideoFrame>& frame, base::TimeTicks timestamp, bool success); @@ -97,13 +102,10 @@ VideoCaptureOracle oracle_; // The video capture parameters used to construct the oracle proxy. - media::VideoCaptureParams params_; + const media::VideoCaptureParams params_; - // Indicates if capture size has been updated after construction. - bool capture_size_updated_; - - // The current capturing format, as a media::VideoFrame::Format. - media::VideoFrame::Format video_frame_format_; + // The current video capture size. + gfx::Size capture_size_; }; // Keeps track of the video capture source frames and executes copying on the
diff --git a/content/browser/media/capture/desktop_capture_device_aura.cc b/content/browser/media/capture/desktop_capture_device_aura.cc index 3797961..de1a109 100644 --- a/content/browser/media/capture/desktop_capture_device_aura.cc +++ b/content/browser/media/capture/desktop_capture_device_aura.cc
@@ -145,7 +145,8 @@ scoped_ptr<cc::CopyOutputResult> result); // Helper function to update cursor state. - // |region_in_frame| defines the desktop bound in the captured frame. + // |region_in_frame| defines where the desktop is rendered in the captured + // frame. // Returns the current cursor position in captured frame. gfx::Point UpdateCursorState(const gfx::Rect& region_in_frame); @@ -172,6 +173,7 @@ // Cursor state. ui::Cursor last_cursor_; + gfx::Size desktop_size_when_cursor_last_updated_; gfx::Point cursor_hot_point_; SkBitmap scaled_cursor_bitmap_; @@ -347,6 +349,7 @@ const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, scoped_ptr<cc::CopyOutputResult> result) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (result->IsEmpty() || result->size().IsEmpty() || !desktop_window_) return false; @@ -368,6 +371,8 @@ base::TimeDelta(), false); capture_frame_cb.Run(video_frame, start_time, true); return true; + } else { + DCHECK(video_frame.get()); } // Compute the dest size we want after the letterboxing resize. Make the @@ -430,19 +435,33 @@ gfx::Point DesktopVideoCaptureMachine::UpdateCursorState( const gfx::Rect& region_in_frame) { const gfx::Rect desktop_bounds = desktop_window_->layer()->bounds(); + if (desktop_bounds.IsEmpty()) { + // Return early to prevent divide-by-zero in calculations below. + ClearCursorState(); + return gfx::Point(); + } + gfx::NativeCursor cursor = desktop_window_->GetHost()->last_cursor(); - if (last_cursor_ != cursor) { + if (last_cursor_ != cursor || + desktop_size_when_cursor_last_updated_ != desktop_bounds.size()) { SkBitmap cursor_bitmap; if (ui::GetCursorBitmap(cursor, &cursor_bitmap, &cursor_hot_point_)) { + const int scaled_width = cursor_bitmap.width() * + region_in_frame.width() / desktop_bounds.width(); + const int scaled_height = cursor_bitmap.height() * + region_in_frame.height() / desktop_bounds.height(); + if (scaled_width <= 0 || scaled_height <= 0) { + ClearCursorState(); + return gfx::Point(); + } scaled_cursor_bitmap_ = skia::ImageOperations::Resize( cursor_bitmap, skia::ImageOperations::RESIZE_BEST, - cursor_bitmap.width() * region_in_frame.width() / - desktop_bounds.width(), - cursor_bitmap.height() * region_in_frame.height() / - desktop_bounds.height()); + scaled_width, + scaled_height); last_cursor_ = cursor; + desktop_size_when_cursor_last_updated_ = desktop_bounds.size(); } else { // Clear cursor state if ui::GetCursorBitmap failed so that we do not // render cursor on the captured frame. @@ -466,6 +485,7 @@ void DesktopVideoCaptureMachine::ClearCursorState() { last_cursor_ = ui::Cursor(); + desktop_size_when_cursor_last_updated_ = gfx::Size(); cursor_hot_point_ = gfx::Point(); scaled_cursor_bitmap_.reset(); }
diff --git a/content/browser/media/capture/desktop_capture_device_aura_unittest.cc b/content/browser/media/capture/desktop_capture_device_aura_unittest.cc index fb06dad5..9f259eb 100644 --- a/content/browser/media/capture/desktop_capture_device_aura_unittest.cc +++ b/content/browser/media/capture/desktop_capture_device_aura_unittest.cc
@@ -44,9 +44,8 @@ MOCK_METHOD2(ReserveOutputBuffer, scoped_refptr<Buffer>(media::VideoFrame::Format format, const gfx::Size& dimensions)); - MOCK_METHOD4(OnIncomingCapturedVideoFrame, + MOCK_METHOD3(OnIncomingCapturedVideoFrame, void(const scoped_refptr<Buffer>& buffer, - const media::VideoCaptureFormat& buffer_format, const scoped_refptr<media::VideoFrame>& frame, const base::TimeTicks& timestamp)); MOCK_METHOD1(OnError, void(const std::string& reason));
diff --git a/content/browser/media/capture/desktop_capture_device_unittest.cc b/content/browser/media/capture/desktop_capture_device_unittest.cc index 842b57e..49a4dfd 100644 --- a/content/browser/media/capture/desktop_capture_device_unittest.cc +++ b/content/browser/media/capture/desktop_capture_device_unittest.cc
@@ -62,9 +62,8 @@ MOCK_METHOD2(ReserveOutputBuffer, scoped_refptr<Buffer>(media::VideoFrame::Format format, const gfx::Size& dimensions)); - MOCK_METHOD4(OnIncomingCapturedVideoFrame, + MOCK_METHOD3(OnIncomingCapturedVideoFrame, void(const scoped_refptr<Buffer>& buffer, - const media::VideoCaptureFormat& buffer_format, const scoped_refptr<media::VideoFrame>& frame, const base::TimeTicks& timestamp)); MOCK_METHOD1(OnError, void(const std::string& reason));
diff --git a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc index 59dffc4..84813da 100644 --- a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc +++ b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
@@ -343,15 +343,18 @@ void OnIncomingCapturedVideoFrame( const scoped_refptr<Buffer>& buffer, - const media::VideoCaptureFormat& buffer_format, const scoped_refptr<media::VideoFrame>& frame, const base::TimeTicks& timestamp) override { - EXPECT_EQ(gfx::Size(kTestWidth, kTestHeight), buffer_format.frame_size); - EXPECT_EQ(media::PIXEL_FORMAT_I420, buffer_format.pixel_format); + EXPECT_EQ(gfx::Size(kTestWidth, kTestHeight), frame->visible_rect().size()); EXPECT_EQ(media::VideoFrame::I420, frame->format()); + double frame_rate = 0; + EXPECT_TRUE( + frame->metadata()->GetDouble(media::VideoFrameMetadata::FRAME_RATE, + &frame_rate)); + EXPECT_EQ(kTestFramesPerSecond, frame_rate); uint8 yuv[3]; for (int plane = 0; plane < 3; ++plane) - yuv[plane] = frame->data(plane)[0]; + yuv[plane] = frame->visible_data(plane)[0]; // TODO(nick): We just look at the first pixel presently, because if // the analysis is too slow, the backlog of frames will grow without bound // and trouble erupts. http://crbug.com/174519
diff --git a/content/browser/media/cdm/browser_cdm_manager.cc b/content/browser/media/cdm/browser_cdm_manager.cc index f9fcb81..1b78ba3 100644 --- a/content/browser/media/cdm/browser_cdm_manager.cc +++ b/content/browser/media/cdm/browser_cdm_manager.cc
@@ -365,8 +365,9 @@ #if defined(OS_ANDROID) if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableInfobarForProtectedMediaIdentifier)) { - GenerateRequestIfPermitted(render_frame_id, cdm_id, eme_init_data_type, - init_data, promise.Pass(), true); + GenerateRequestIfPermitted( + render_frame_id, cdm_id, eme_init_data_type, + init_data, promise.Pass(), PERMISSION_STATUS_GRANTED); return; } #endif @@ -532,9 +533,9 @@ media::EmeInitDataType init_data_type, const std::vector<uint8>& init_data, scoped_ptr<media::NewSessionCdmPromise> promise, - bool permitted) { + PermissionStatus permission) { cdm_cancel_permission_map_.erase(GetId(render_frame_id, cdm_id)); - if (!permitted) { + if (permission != PERMISSION_STATUS_GRANTED) { promise->reject(MediaKeys::NOT_SUPPORTED_ERROR, 0, "Permission denied."); return; }
diff --git a/content/browser/media/cdm/browser_cdm_manager.h b/content/browser/media/cdm/browser_cdm_manager.h index 973ecff1..12ee617 100644 --- a/content/browser/media/cdm/browser_cdm_manager.h +++ b/content/browser/media/cdm/browser_cdm_manager.h
@@ -17,6 +17,7 @@ #include "content/common/content_export.h" #include "content/common/media/cdm_messages_enums.h" #include "content/public/browser/browser_message_filter.h" +#include "content/public/common/permission_status.mojom.h" #include "ipc/ipc_message.h" #include "media/base/cdm_promise.h" #include "media/base/eme_constants.h" @@ -163,7 +164,7 @@ media::EmeInitDataType init_data_type, const std::vector<uint8>& init_data, scoped_ptr<media::NewSessionCdmPromise> promise, - bool permitted); + PermissionStatus permission); const int render_process_id_;
diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc index cc90b55e..f87cfb1 100644 --- a/content/browser/media/media_web_contents_observer.cc +++ b/content/browser/media/media_web_contents_observer.cc
@@ -8,11 +8,13 @@ #include "base/stl_util.h" #include "content/browser/media/cdm/browser_cdm_manager.h" #include "content/browser/renderer_host/render_process_host_impl.h" +#include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "ipc/ipc_message_macros.h" #if defined(OS_ANDROID) +#include "content/browser/android/media_players_observer.h" #include "content/browser/media/android/browser_media_player_manager.h" #include "content/common/media/media_player_messages_android.h" #include "media/base/android/media_player_android.h" @@ -22,7 +24,8 @@ MediaWebContentsObserver::MediaWebContentsObserver( WebContents* web_contents) - : WebContentsObserver(web_contents) { + : WebContentsObserver(web_contents) +{ } MediaWebContentsObserver::~MediaWebContentsObserver() { @@ -35,6 +38,10 @@ // Always destroy the media players before CDMs because we do not support // detaching CDMs from media players yet. See http://crbug.com/330324 media_player_managers_.erase(key); + + MediaPlayersObserver* audio_observer = GetMediaPlayersObserver(); + if (audio_observer) + audio_observer->RenderFrameDeleted(render_frame_host); #endif // TODO(xhwang): Currently MediaWebContentsObserver, BrowserMediaPlayerManager // and BrowserCdmManager all run on browser UI thread. So this call is okay. @@ -161,11 +168,24 @@ if (!media_player_managers_.contains(key)) { media_player_managers_.set( key, - make_scoped_ptr(BrowserMediaPlayerManager::Create(render_frame_host))); + make_scoped_ptr(BrowserMediaPlayerManager::Create( + render_frame_host, GetMediaPlayersObserver()))); } return media_player_managers_.get(key); } +MediaPlayersObserver* +MediaWebContentsObserver::GetMediaPlayersObserver() const { + AudioStateProvider* provider = + static_cast<WebContentsImpl*>(web_contents())->audio_state_provider(); + + MediaPlayersObserver* audio_observer = + static_cast<MediaPlayersObserver*>(provider); + + DCHECK(audio_observer); + return audio_observer; +} + #if defined(VIDEO_HOLE) void MediaWebContentsObserver::OnFrameInfoUpdated() { for (MediaPlayerManagerMap::iterator iter = media_player_managers_.begin();
diff --git a/content/browser/media/media_web_contents_observer.h b/content/browser/media/media_web_contents_observer.h index 3b451a8..2eb08c1 100644 --- a/content/browser/media/media_web_contents_observer.h +++ b/content/browser/media/media_web_contents_observer.h
@@ -7,11 +7,16 @@ #include "base/compiler_specific.h" #include "base/containers/scoped_ptr_hash_map.h" +#include "base/memory/scoped_ptr.h" #include "content/common/content_export.h" #include "content/public/browser/web_contents_observer.h" namespace content { +#if defined(OS_ANDROID) +class MediaPlayersObserver; +#endif // defined(OS_ANDROID) + class BrowserCdmManager; class BrowserMediaPlayerManager; @@ -45,6 +50,8 @@ void OnSetCdm(RenderFrameHost* render_frame_host, int player_id, int cdm_id); + MediaPlayersObserver* GetMediaPlayersObserver() const; + #if defined(VIDEO_HOLE) void OnFrameInfoUpdated(); #endif // defined(VIDEO_HOLE)
diff --git a/content/browser/media/midi_host.cc b/content/browser/media/midi_host.cc index b8fcdd0b..349f302 100644 --- a/content/browser/media/midi_host.cc +++ b/content/browser/media/midi_host.cc
@@ -55,7 +55,8 @@ is_session_requested_(false), midi_manager_(midi_manager), sent_bytes_in_flight_(0), - bytes_sent_since_last_acknowledgement_(0) { + bytes_sent_since_last_acknowledgement_(0), + output_port_count_(0) { CHECK(midi_manager_); } @@ -90,6 +91,15 @@ void MidiHost::OnSendData(uint32 port, const std::vector<uint8>& data, double timestamp) { + { + base::AutoLock auto_lock(output_port_count_lock_); + if (output_port_count_ <= port) { + RecordAction(base::UserMetricsAction("BadMessageTerminate_MIDIPort")); + BadMessageReceived(); + return; + } + } + if (data.empty()) return; @@ -142,6 +152,8 @@ } void MidiHost::AddOutputPort(const media::MidiPortInfo& info) { + base::AutoLock auto_lock(output_port_count_lock_); + output_port_count_++; Send(new MidiMsg_AddOutputPort(info)); }
diff --git a/content/browser/media/midi_host.h b/content/browser/media/midi_host.h index 9d9c01f..8a0ae8e 100644 --- a/content/browser/media/midi_host.h +++ b/content/browser/media/midi_host.h
@@ -58,13 +58,14 @@ void OnEndSession(); + protected: + ~MidiHost() override; + private: FRIEND_TEST_ALL_PREFIXES(MidiHostTest, IsValidWebMIDIData); friend class base::DeleteHelper<MidiHost>; friend class BrowserThread; - ~MidiHost() override; - // Returns true if |data| fulfills the requirements of MidiOutput.send API // defined in the WebMIDI spec. // - |data| must be any number of complete MIDI messages (data abbreviation @@ -105,6 +106,12 @@ // Protects access to |sent_bytes_in_flight_|. base::Lock in_flight_lock_; + // How many output port exists. + uint32 output_port_count_; + + // Protects access to |output_port_count_|. + base::Lock output_port_count_lock_; + DISALLOW_COPY_AND_ASSIGN(MidiHost); };
diff --git a/content/browser/media/midi_host_unittest.cc b/content/browser/media/midi_host_unittest.cc index e06e4e4..877c80d 100644 --- a/content/browser/media/midi_host_unittest.cc +++ b/content/browser/media/midi_host_unittest.cc
@@ -4,6 +4,12 @@ #include "content/browser/media/midi_host.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "content/common/media/midi_messages.h" +#include "content/public/test/test_browser_thread.h" +#include "media/midi/midi_manager.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { @@ -27,6 +33,8 @@ const uint8 kBrokenData3[] = { 0xf2, 0x00 }; const uint8 kDataByte0[] = { 0x00 }; +const int kRenderProcessId = 0; + template <typename T, size_t N> const std::vector<T> AsVector(const T(&data)[N]) { std::vector<T> buffer; @@ -39,9 +47,112 @@ buffer->insert(buffer->end(), data, data + N); } +enum MidiEventType { + DISPATCH_SEND_MIDI_DATA, +}; + +struct MidiEvent { + MidiEvent(MidiEventType in_type, + uint32 in_port_index, + const std::vector<uint8>& in_data, + double in_timestamp) + : type(in_type), + port_index(in_port_index), + data(in_data), + timestamp(in_timestamp) {} + + MidiEventType type; + uint32 port_index; + std::vector<uint8> data; + double timestamp; +}; + +class FakeMidiManager : public media::MidiManager { + public: + void DispatchSendMidiData(media::MidiManagerClient* client, + uint32 port_index, + const std::vector<uint8>& data, + double timestamp) override { + events_.push_back(MidiEvent(DISPATCH_SEND_MIDI_DATA, + port_index, + data, + timestamp)); + } + std::vector<MidiEvent> events_; +}; + +class MidiHostForTesting : public MidiHost { + public: + MidiHostForTesting(int renderer_process_id, media::MidiManager* midi_manager) + : MidiHost(renderer_process_id, midi_manager) {} + + private: + ~MidiHostForTesting() override {} + + // BrowserMessageFilter implementation. + // Override BadMessageReceived() so to do nothing since the original + // implementation to kill a malicious renderer process causes a check failure + // in unit tests. + void BadMessageReceived() override {} +}; + +class MidiHostTest : public testing::Test { + public: + MidiHostTest() + : io_browser_thread_(BrowserThread::IO, &message_loop_), + host_(new MidiHostForTesting(kRenderProcessId, &manager_)), + data_(kNoteOn, kNoteOn + arraysize(kNoteOn)), + port_id_(0) {} + + protected: + void AddOutputPort() { + const std::string id = base::StringPrintf("i-can-%d", port_id_++); + const std::string manufacturer("yukatan"); + const std::string name("doki-doki-pi-pine"); + const std::string version("3.14159265359"); + media::MidiPortState state = media::MIDI_PORT_CONNECTED; + media::MidiPortInfo info(id, manufacturer, name, version, state); + + host_->AddOutputPort(info); + } + + void OnSendData(uint32 port) { + scoped_ptr<IPC::Message> message( + new MidiHostMsg_SendData(port, data_, 0.0)); + host_->OnMessageReceived(*message.get()); + } + + size_t GetEventSize() const { + return manager_.events_.size(); + } + + void CheckSendEventAt(size_t at, uint32 port) { + EXPECT_EQ(DISPATCH_SEND_MIDI_DATA, manager_.events_[at].type); + EXPECT_EQ(port, manager_.events_[at].port_index); + EXPECT_EQ(data_, manager_.events_[at].data); + EXPECT_EQ(0.0, manager_.events_[at].timestamp); + } + + void RunLoopUntilIdle() { + base::RunLoop run_loop; + run_loop.RunUntilIdle(); + } + + private: + base::MessageLoop message_loop_; + TestBrowserThread io_browser_thread_; + + FakeMidiManager manager_; + scoped_refptr<MidiHostForTesting> host_; + std::vector<uint8> data_; + int32 port_id_; + + DISALLOW_COPY_AND_ASSIGN(MidiHostTest); +}; + } // namespace -TEST(MidiHostTest, IsValidWebMIDIData) { +TEST_F(MidiHostTest, IsValidWebMIDIData) { // Test single event scenario EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kGMOn))); EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kGSOn))); @@ -88,4 +199,34 @@ } } +// Test if sending data to out of range port is ignored. +TEST_F(MidiHostTest, OutputPortCheck) { + // Only one output port is available. + AddOutputPort(); + + // Sending data to port 0 should be delivered. + uint32 port0 = 0; + OnSendData(port0); + RunLoopUntilIdle(); + EXPECT_EQ(1U, GetEventSize()); + CheckSendEventAt(0, port0); + + // Sending data to port 1 should not be delivered. + uint32 port1 = 1; + OnSendData(port1); + RunLoopUntilIdle(); + EXPECT_EQ(1U, GetEventSize()); + + // Two output ports are available from now on. + AddOutputPort(); + + // Sending data to port 0 and 1 should be delivered now. + OnSendData(port0); + OnSendData(port1); + RunLoopUntilIdle(); + EXPECT_EQ(3U, GetEventSize()); + CheckSendEventAt(1, port0); + CheckSendEventAt(2, port1); +} + } // namespace conent
diff --git a/content/browser/media/webrtc_browsertest.cc b/content/browser/media/webrtc_browsertest.cc index fc613c84..cdd5cb9 100644 --- a/content/browser/media/webrtc_browsertest.cc +++ b/content/browser/media/webrtc_browsertest.cc
@@ -371,9 +371,7 @@ // MediaStream that has been created based on a MediaStream created with // getUserMedia. When video is flowing, the VideoTrack is removed and an // AudioTrack is added instead. -// TODO(phoglund): This test is manual since not all buildbots has an audio -// input. -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, MANUAL_CallAndModifyStream) { +IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, CallAndModifyStream) { MakeTypicalPeerConnectionCall( "callWithNewVideoMediaStreamLaterSwitchToAudio();"); }
diff --git a/content/browser/mojo/mojo_application_host.cc b/content/browser/mojo/mojo_application_host.cc index 883945f9..a9d0002 100644 --- a/content/browser/mojo/mojo_application_host.cc +++ b/content/browser/mojo/mojo_application_host.cc
@@ -63,9 +63,18 @@ mojo::embedder::PlatformChannelPair channel_pair; + scoped_refptr<base::TaskRunner> io_task_runner; + if (io_task_runner_override_) { + io_task_runner = io_task_runner_override_; + } else { + io_task_runner = + BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO) + ->task_runner(); + } + mojo::ScopedMessagePipeHandle message_pipe = channel_init_.Init( PlatformFileFromScopedPlatformHandle(channel_pair.PassServerHandle()), - BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)); + io_task_runner); if (!message_pipe.is_valid()) return false; @@ -93,4 +102,9 @@ channel_init_.WillDestroySoon(); } +void MojoApplicationHost::OverrideIOTaskRunnerForTest( + scoped_refptr<base::TaskRunner> io_task_runner) { + io_task_runner_override_ = io_task_runner; +} + } // namespace content
diff --git a/content/browser/mojo/mojo_application_host.h b/content/browser/mojo/mojo_application_host.h index fc0693a6..216b65a 100644 --- a/content/browser/mojo/mojo_application_host.h +++ b/content/browser/mojo/mojo_application_host.h
@@ -8,8 +8,8 @@ #include "base/memory/scoped_ptr.h" #include "base/process/process_handle.h" #include "content/common/application_setup.mojom.h" +#include "content/common/mojo/channel_init.h" #include "content/common/mojo/service_registry_impl.h" -#include "third_party/mojo/src/mojo/edk/embedder/channel_init.h" #include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h" #if defined(OS_ANDROID) @@ -48,8 +48,11 @@ } #endif + void OverrideIOTaskRunnerForTest( + scoped_refptr<base::TaskRunner> io_task_runner); + private: - mojo::embedder::ChannelInit channel_init_; + ChannelInit channel_init_; mojo::embedder::ScopedPlatformHandle client_handle_; bool did_activate_; @@ -57,6 +60,8 @@ scoped_ptr<ApplicationSetup> application_setup_; ServiceRegistryImpl service_registry_; + scoped_refptr<base::TaskRunner> io_task_runner_override_; + #if defined(OS_ANDROID) scoped_ptr<ServiceRegistryAndroid> service_registry_android_; #endif
diff --git a/content/browser/navigator_connect/navigator_connect_context_impl.cc b/content/browser/navigator_connect/navigator_connect_context_impl.cc index 35a02d10..c5f01f453 100644 --- a/content/browser/navigator_connect/navigator_connect_context_impl.cc +++ b/content/browser/navigator_connect/navigator_connect_context_impl.cc
@@ -68,8 +68,8 @@ if (!factory) { // No factories found. - OnConnectResult(client, client_port, client_port_route_id, - callback, nullptr); + OnConnectResult(client, client_port, client_port_route_id, callback, + nullptr, false); return; } @@ -84,7 +84,8 @@ int client_message_port_id, int client_port_route_id, const ConnectCallback& callback, - MessagePortDelegate* delegate) { + MessagePortDelegate* delegate, + bool data_as_values) { DCHECK_CURRENTLY_ON(BrowserThread::IO); if (delegate) { // Update service side port with delegate. @@ -92,7 +93,7 @@ client.message_port_id, delegate, client.message_port_id); TransferredMessagePort port; port.id = client_message_port_id; - // TODO(mek): Set port.send_value_as_messages depending on connect result. + port.send_messages_as_values = data_as_values; callback.Run(port, client_port_route_id, true); } else { // Destroy ports since connection failed.
diff --git a/content/browser/navigator_connect/navigator_connect_context_impl.h b/content/browser/navigator_connect/navigator_connect_context_impl.h index 1f53c53..ffb4647 100644 --- a/content/browser/navigator_connect/navigator_connect_context_impl.h +++ b/content/browser/navigator_connect/navigator_connect_context_impl.h
@@ -53,7 +53,8 @@ int client_message_port_id, int client_port_route_id, const ConnectCallback& callback, - MessagePortDelegate* delegate); + MessagePortDelegate* delegate, + bool data_as_values); // List of factories to try to handle URLs. ScopedVector<NavigatorConnectServiceFactory> service_factories_;
diff --git a/content/browser/navigator_connect/navigator_connect_service_worker_service_factory.cc b/content/browser/navigator_connect/navigator_connect_service_worker_service_factory.cc index 802ae7207..7f7d350 100644 --- a/content/browser/navigator_connect/navigator_connect_service_worker_service_factory.cc +++ b/content/browser/navigator_connect/navigator_connect_service_worker_service_factory.cc
@@ -185,14 +185,17 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); if (status != SERVICE_WORKER_OK || !accept_connection) { - callback.Run(nullptr); + callback.Run(nullptr, false); return; } - // TODO(mek): Keep track of NavigatorConnectServiceWorkerService instances and - // clean them up when a service worker registration is deleted. - callback.Run(new NavigatorConnectServiceWorkerService( - service_worker_context_, client, service_worker_registration)); + // TODO(mek): http://crbug.com/462744 Keep track of these + // NavigatorConnectServiceWorkerService instances and clean them up when a + // service worker registration is deleted. + callback.Run( + new NavigatorConnectServiceWorkerService(service_worker_context_, client, + service_worker_registration), + false); } } // namespace content
diff --git a/content/browser/permissions/permission_service_impl.cc b/content/browser/permissions/permission_service_impl.cc index bd5c87b..a086c79 100644 --- a/content/browser/permissions/permission_service_impl.cc +++ b/content/browser/permissions/permission_service_impl.cc
@@ -85,12 +85,14 @@ void PermissionServiceImpl::OnRequestPermissionResponse( const mojo::Callback<void(PermissionStatus)>& callback, int request_id, - bool allowed) { + PermissionStatus status) { pending_requests_.Remove(request_id); - // TODO(mlamouri): for now, we only get a boolean back, but we would ideally - // need a ContentSetting, see http://crbug.com/432978 - callback.Run(allowed ? PERMISSION_STATUS_GRANTED : PERMISSION_STATUS_ASK); + // TODO(mlamouri): this is not yet returning a tri-state value because it will + // require some further changes that will be dealt with in + // https://crrev.com/794203004/ + status = status == PERMISSION_STATUS_DENIED ? PERMISSION_STATUS_ASK : status; + callback.Run(status); } void PermissionServiceImpl::CancelPendingRequests() {
diff --git a/content/browser/permissions/permission_service_impl.h b/content/browser/permissions/permission_service_impl.h index afbb8d7..57f1bfd 100644 --- a/content/browser/permissions/permission_service_impl.h +++ b/content/browser/permissions/permission_service_impl.h
@@ -63,7 +63,7 @@ void OnRequestPermissionResponse( const mojo::Callback<void(PermissionStatus)>& callback, int request_id, - bool allowed); + PermissionStatus status); PermissionStatus GetPermissionStatus(PermissionType type, GURL origin); void ResetPermissionStatus(PermissionType type, GURL origin);
diff --git a/content/browser/renderer_host/input/OWNERS b/content/browser/renderer_host/input/OWNERS index 4893edbd..f2dd9a3 100644 --- a/content/browser/renderer_host/input/OWNERS +++ b/content/browser/renderer_host/input/OWNERS
@@ -1,3 +1,3 @@ aelias@chromium.org jdduke@chromium.org -nduca@chromium.org +tdresser@chromium.org
diff --git a/content/browser/renderer_host/input/web_input_event_builders_win.cc b/content/browser/renderer_host/input/web_input_event_builders_win.cc index 73c9174..831f403 100644 --- a/content/browser/renderer_host/input/web_input_event_builders_win.cc +++ b/content/browser/renderer_host/input/web_input_event_builders_win.cc
@@ -6,6 +6,7 @@ #include "base/logging.h" #include "content/browser/renderer_host/input/web_input_event_util.h" +#include "ui/gfx/win/dpi.h" using blink::WebInputEvent; using blink::WebKeyboardEvent; @@ -250,11 +251,24 @@ result.windowX = result.x; result.windowY = result.y; - POINT global_point = { result.x, result.y }; + // The mouse coordinates received here are device independent (DIPs). We need + // to convert them to physical coordinates before calling Windows APIs like + // ClientToScreen, etc. + gfx::Point scaled_screen_point(result.x, result.y); + scaled_screen_point = gfx::win::DIPToScreenPoint(scaled_screen_point); + + POINT global_point = { scaled_screen_point.x(), scaled_screen_point.y() }; ClientToScreen(hwnd, &global_point); - result.globalX = global_point.x; - result.globalY = global_point.y; + scaled_screen_point.set_x(global_point.x); + scaled_screen_point.set_y(global_point.y); + + // We need to convert the point back to DIP before using it. + gfx::Point dip_screen_point = gfx::win::ScreenToDIPPoint( + scaled_screen_point); + + result.globalX = dip_screen_point.x(); + result.globalY = dip_screen_point.y(); // calculate number of clicks:
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc index 7f4a1f60..3fbb2dc 100644 --- a/content/browser/renderer_host/media/video_capture_controller.cc +++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -175,7 +175,6 @@ const gfx::Size& size) override; void OnIncomingCapturedVideoFrame( const scoped_refptr<Buffer>& buffer, - const VideoCaptureFormat& buffer_format, const scoped_refptr<media::VideoFrame>& frame, const base::TimeTicks& timestamp) override; void OnError(const std::string& reason) override; @@ -547,9 +546,9 @@ base::TimeDelta(), base::Closure()); DCHECK(frame.get()); + frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, + frame_format.frame_rate); - VideoCaptureFormat format( - dimensions, frame_format.frame_rate, media::PIXEL_FORMAT_I420); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, @@ -557,7 +556,6 @@ &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, controller_, buffer, - format, frame, timestamp)); } @@ -565,7 +563,6 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( const scoped_refptr<Buffer>& buffer, - const VideoCaptureFormat& buffer_format, const scoped_refptr<media::VideoFrame>& frame, const base::TimeTicks& timestamp) { BrowserThread::PostTask( @@ -575,7 +572,6 @@ &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, controller_, buffer, - buffer_format, frame, timestamp)); } @@ -606,7 +602,6 @@ void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread( const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer, - const media::VideoCaptureFormat& buffer_format, const scoped_refptr<media::VideoFrame>& frame, const base::TimeTicks& timestamp) { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -614,17 +609,33 @@ int count = 0; if (state_ == VIDEO_CAPTURE_STATE_STARTED) { + if (!frame->metadata()->HasKey(media::VideoFrameMetadata::FRAME_RATE)) { + frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, + video_capture_format_.frame_rate); + } + scoped_ptr<base::DictionaryValue> metadata(new base::DictionaryValue()); + frame->metadata()->MergeInternalValuesInto(metadata.get()); + for (const auto& client : controller_clients_) { if (client->session_closed || client->paused) continue; + scoped_ptr<base::DictionaryValue> copy_of_metadata; + if (client == controller_clients_.back()) + copy_of_metadata = metadata.Pass(); + else + copy_of_metadata.reset(metadata->DeepCopy()); + if (frame->format() == media::VideoFrame::NATIVE_TEXTURE) { + DCHECK(frame->coded_size() == frame->visible_rect().size()) + << "Textures are always supposed to be tightly packed."; client->event_handler->OnMailboxBufferReady(client->controller_id, buffer->id(), *frame->mailbox_holder(), - buffer_format, - timestamp); - } else { + frame->coded_size(), + timestamp, + copy_of_metadata.Pass()); + } else if (frame->format() == media::VideoFrame::I420) { bool is_new_buffer = client->known_buffers.insert(buffer->id()).second; if (is_new_buffer) { // On the first use of a buffer on a client, share the memory handle. @@ -636,8 +647,12 @@ } client->event_handler->OnBufferReady( - client->controller_id, buffer->id(), buffer_format, - frame->visible_rect(), timestamp); + client->controller_id, buffer->id(), frame->coded_size(), + frame->visible_rect(), timestamp, copy_of_metadata.Pass()); + } else { + // VideoFrame format not supported. + NOTREACHED(); + break; } bool inserted = @@ -650,14 +665,17 @@ if (!has_received_frames_) { UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width", - buffer_format.frame_size.width()); + frame->visible_rect().width()); UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height", - buffer_format.frame_size.height()); + frame->visible_rect().height()); UMA_HISTOGRAM_ASPECT_RATIO("Media.VideoCapture.AspectRatio", - buffer_format.frame_size.width(), - buffer_format.frame_size.height()); - UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate", - buffer_format.frame_rate); + frame->visible_rect().width(), + frame->visible_rect().height()); + double frame_rate; + if (!frame->metadata()->GetDouble(media::VideoFrameMetadata::FRAME_RATE, + &frame_rate)) + frame_rate = video_capture_format_.frame_rate; + UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate", frame_rate); has_received_frames_ = true; }
diff --git a/content/browser/renderer_host/media/video_capture_controller.h b/content/browser/renderer_host/media/video_capture_controller.h index 43d30046..7b4a75d 100644 --- a/content/browser/renderer_host/media/video_capture_controller.h +++ b/content/browser/renderer_host/media/video_capture_controller.h
@@ -133,7 +133,6 @@ // Worker functions on IO thread. Called by the VideoCaptureDeviceClient. void DoIncomingCapturedVideoFrameOnIOThread( const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer, - const media::VideoCaptureFormat& format, const scoped_refptr<media::VideoFrame>& frame, const base::TimeTicks& timestamp); void DoErrorOnIOThread();
diff --git a/content/browser/renderer_host/media/video_capture_controller_event_handler.h b/content/browser/renderer_host/media/video_capture_controller_event_handler.h index 2bddf694..45dbbea 100644 --- a/content/browser/renderer_host/media/video_capture_controller_event_handler.h +++ b/content/browser/renderer_host/media/video_capture_controller_event_handler.h
@@ -5,12 +5,15 @@ #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_CONTROLLER_EVENT_HANDLER_H_ #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_CONTROLLER_EVENT_HANDLER_H_ +#include "base/memory/scoped_ptr.h" #include "base/memory/shared_memory.h" #include "base/time/time.h" +#include "base/values.h" #include "content/common/content_export.h" namespace gfx { class Rect; +class Size; } // namespace gfx namespace gpu { @@ -54,16 +57,19 @@ // A buffer has been filled with I420 video. virtual void OnBufferReady(const VideoCaptureControllerID& id, int buffer_id, - const media::VideoCaptureFormat& format, + const gfx::Size& coded_size, const gfx::Rect& visible_rect, - base::TimeTicks timestamp) = 0; + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata) = 0; // A texture mailbox buffer has been filled with data. - virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id, - int buffer_id, - const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp) = 0; + virtual void OnMailboxBufferReady( + const VideoCaptureControllerID& id, + int buffer_id, + const gpu::MailboxHolder& mailbox_holder, + const gfx::Size& packed_frame_size, + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata) = 0; // The capture session has ended and no more frames will be sent. virtual void OnEnded(const VideoCaptureControllerID& id) = 0;
diff --git a/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/content/browser/renderer_host/media/video_capture_controller_unittest.cc index abea8277..69f83ae7 100644 --- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc +++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
@@ -63,11 +63,13 @@ int buffer_id) override { DoBufferDestroyed(id); } - virtual void OnBufferReady(const VideoCaptureControllerID& id, - int buffer_id, - const media::VideoCaptureFormat& format, - const gfx::Rect& visible_rect, - base::TimeTicks timestamp) override { + virtual void OnBufferReady( + const VideoCaptureControllerID& id, + int buffer_id, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata) override { DoBufferReady(id); base::MessageLoop::current()->PostTask( FROM_HERE, @@ -78,11 +80,13 @@ buffer_id, 0)); } - virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id, - int buffer_id, - const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp) override { + virtual void OnMailboxBufferReady( + const VideoCaptureControllerID& id, + int buffer_id, + const gpu::MailboxHolder& mailbox_holder, + const gfx::Size& packed_frame_size, + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata) override { DoMailboxBufferReady(id); base::MessageLoop::current()->PostTask( FROM_HERE, @@ -339,9 +343,6 @@ } device_->OnIncomingCapturedVideoFrame( buffer, - media::VideoCaptureFormat(capture_resolution, - device_format.frame_rate, - media::PIXEL_FORMAT_I420), WrapI420Buffer(buffer, capture_resolution), base::TimeTicks()); buffer = NULL; @@ -359,9 +360,6 @@ memset(buffer->data(), buffer_no++, buffer->size()); device_->OnIncomingCapturedVideoFrame( buffer, - media::VideoCaptureFormat(capture_resolution, - device_format.frame_rate, - media::PIXEL_FORMAT_I420), WrapI420Buffer(buffer, capture_resolution), base::TimeTicks()); buffer = NULL; @@ -390,9 +388,6 @@ memset(buffer->data(), buffer_no++, buffer->size()); device_->OnIncomingCapturedVideoFrame( buffer, - media::VideoCaptureFormat(capture_resolution, - device_format.frame_rate, - media::PIXEL_FORMAT_I420), WrapI420Buffer(buffer, capture_resolution), base::TimeTicks()); buffer = NULL; @@ -430,9 +425,6 @@ memset(buffer->data(), buffer_no++, buffer->size()); device_->OnIncomingCapturedVideoFrame( buffer, - media::VideoCaptureFormat(capture_resolution, - device_format.frame_rate, - media::PIXEL_FORMAT_I420), WrapI420Buffer(buffer, capture_resolution), base::TimeTicks()); buffer = NULL; @@ -448,9 +440,6 @@ memset(buffer->data(), buffer_no++, buffer->size()); device_->OnIncomingCapturedVideoFrame( buffer, - media::VideoCaptureFormat(capture_resolution, - device_format.frame_rate, - media::PIXEL_FORMAT_I420), WrapI420Buffer(buffer, capture_resolution), base::TimeTicks()); buffer = NULL; @@ -481,9 +470,6 @@ ASSERT_TRUE(buffer.get()); device_->OnIncomingCapturedVideoFrame( buffer, - media::VideoCaptureFormat(capture_resolution, - device_format.frame_rate, - media::PIXEL_FORMAT_I420), WrapI420Buffer(buffer, capture_resolution), base::TimeTicks()); buffer = NULL; @@ -499,9 +485,6 @@ #endif device_->OnIncomingCapturedVideoFrame( buffer, - media::VideoCaptureFormat(capture_resolution, - device_format.frame_rate, - media::PIXEL_FORMAT_TEXTURE), WrapMailboxBuffer(make_scoped_ptr(new gpu::MailboxHolder( gpu::Mailbox(), 0, mailbox_syncpoints[i])), base::Bind(&CacheSyncPoint, &release_syncpoints[i]), @@ -568,8 +551,6 @@ device_->OnIncomingCapturedVideoFrame( buffer, - media::VideoCaptureFormat( - capture_resolution, 30, media::PIXEL_FORMAT_I420), WrapI420Buffer(buffer, capture_resolution), base::TimeTicks()); buffer = NULL; @@ -608,8 +589,6 @@ device_->OnError("Test error"); device_->OnIncomingCapturedVideoFrame( buffer, - media::VideoCaptureFormat( - dims, device_format.frame_rate, media::PIXEL_FORMAT_I420), WrapI420Buffer(buffer, dims), base::TimeTicks()); buffer = NULL;
diff --git a/content/browser/renderer_host/media/video_capture_host.cc b/content/browser/renderer_host/media/video_capture_host.cc index cc340e3..12bb227c 100644 --- a/content/browser/renderer_host/media/video_capture_host.cc +++ b/content/browser/renderer_host/media/video_capture_host.cc
@@ -5,6 +5,7 @@ #include "content/browser/renderer_host/media/video_capture_host.h" #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/memory/scoped_ptr.h" #include "content/browser/browser_main_loop.h" #include "content/browser/renderer_host/media/media_stream_manager.h" @@ -76,9 +77,10 @@ void VideoCaptureHost::OnBufferReady( const VideoCaptureControllerID& controller_id, int buffer_id, - const media::VideoCaptureFormat& frame_format, + const gfx::Size& coded_size, const gfx::Rect& visible_rect, - base::TimeTicks timestamp) { + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, @@ -86,17 +88,19 @@ this, controller_id, buffer_id, - frame_format, + coded_size, visible_rect, - timestamp)); + timestamp, + base::Passed(&metadata))); } void VideoCaptureHost::OnMailboxBufferReady( const VideoCaptureControllerID& controller_id, int buffer_id, const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& frame_format, - base::TimeTicks timestamp) { + const gfx::Size& packed_frame_size, + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, @@ -105,8 +109,9 @@ controller_id, buffer_id, mailbox_holder, - frame_format, - timestamp)); + packed_frame_size, + timestamp, + base::Passed(&metadata))); } void VideoCaptureHost::OnEnded(const VideoCaptureControllerID& controller_id) { @@ -144,31 +149,47 @@ void VideoCaptureHost::DoSendFilledBufferOnIOThread( const VideoCaptureControllerID& controller_id, int buffer_id, - const media::VideoCaptureFormat& format, + const gfx::Size& coded_size, const gfx::Rect& visible_rect, - base::TimeTicks timestamp) { + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata) { DCHECK_CURRENTLY_ON(BrowserThread::IO); if (entries_.find(controller_id) == entries_.end()) return; - Send(new VideoCaptureMsg_BufferReady( - controller_id.device_id, buffer_id, format, visible_rect, timestamp)); + VideoCaptureMsg_BufferReady_Params params; + params.device_id = controller_id.device_id; + params.buffer_id = buffer_id; + params.coded_size = coded_size; + params.visible_rect = visible_rect; + params.timestamp = timestamp; + if (metadata) + params.metadata.Swap(metadata.get()); + Send(new VideoCaptureMsg_BufferReady(params)); } void VideoCaptureHost::DoSendFilledMailboxBufferOnIOThread( const VideoCaptureControllerID& controller_id, int buffer_id, const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp) { + const gfx::Size& packed_frame_size, + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata) { DCHECK_CURRENTLY_ON(BrowserThread::IO); if (entries_.find(controller_id) == entries_.end()) return; - Send(new VideoCaptureMsg_MailboxBufferReady( - controller_id.device_id, buffer_id, mailbox_holder, format, timestamp)); + VideoCaptureMsg_MailboxBufferReady_Params params; + params.device_id = controller_id.device_id; + params.buffer_id = buffer_id; + params.mailbox_holder = mailbox_holder; + params.packed_frame_size = packed_frame_size; + params.timestamp = timestamp; + if (metadata) + params.metadata.Swap(metadata.get()); + Send(new VideoCaptureMsg_MailboxBufferReady(params)); } void VideoCaptureHost::DoHandleErrorOnIOThread(
diff --git a/content/browser/renderer_host/media/video_capture_host.h b/content/browser/renderer_host/media/video_capture_host.h index 1fd98137..2434abc8 100644 --- a/content/browser/renderer_host/media/video_capture_host.h +++ b/content/browser/renderer_host/media/video_capture_host.h
@@ -85,14 +85,17 @@ int buffer_id) override; void OnBufferReady(const VideoCaptureControllerID& id, int buffer_id, - const media::VideoCaptureFormat& format, + const gfx::Size& coded_size, const gfx::Rect& visible_rect, - base::TimeTicks timestamp) override; - void OnMailboxBufferReady(const VideoCaptureControllerID& id, - int buffer_id, - const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp) override; + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata) override; + void OnMailboxBufferReady( + const VideoCaptureControllerID& id, + int buffer_id, + const gpu::MailboxHolder& mailbox_holder, + const gfx::Size& packed_frame_size, + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata) override; void OnEnded(const VideoCaptureControllerID& id) override; private: @@ -159,17 +162,19 @@ void DoSendFilledBufferOnIOThread( const VideoCaptureControllerID& controller_id, int buffer_id, - const media::VideoCaptureFormat& format, + const gfx::Size& coded_size, const gfx::Rect& visible_rect, - base::TimeTicks timestamp); + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata); // Sends a filled texture mailbox buffer to the VideoCaptureMessageFilter. void DoSendFilledMailboxBufferOnIOThread( const VideoCaptureControllerID& controller_id, int buffer_id, const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp); + const gfx::Size& packed_frame_size, + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata); // Handles error coming from VideoCaptureDevice. void DoHandleErrorOnIOThread(const VideoCaptureControllerID& controller_id);
diff --git a/content/browser/renderer_host/media/video_capture_host_unittest.cc b/content/browser/renderer_host/media/video_capture_host_unittest.cc index 57a47c85..aace519 100644 --- a/content/browser/renderer_host/media/video_capture_host_unittest.cc +++ b/content/browser/renderer_host/media/video_capture_host_unittest.cc
@@ -64,23 +64,27 @@ // verifying the output. class DumpVideo { public: - DumpVideo() : expected_size_(0) {} - void StartDump(int width, int height) { + DumpVideo() {} + const gfx::Size& coded_size() const { return coded_size_; } + void StartDump(const gfx::Size& coded_size) { base::FilePath file_name = base::FilePath(base::StringPrintf( - FILE_PATH_LITERAL("dump_w%d_h%d.yuv"), width, height)); + FILE_PATH_LITERAL("dump_w%d_h%d.yuv"), + coded_size.width(), + coded_size.height())); file_.reset(base::OpenFile(file_name, "wb")); - expected_size_ = media::VideoFrame::AllocationSize( - media::VideoFrame::I420, gfx::Size(width, height)); + coded_size_ = coded_size; } void NewVideoFrame(const void* buffer) { if (file_.get() != NULL) { - ASSERT_EQ(1U, fwrite(buffer, expected_size_, 1, file_.get())); + const int size = media::VideoFrame::AllocationSize( + media::VideoFrame::I420, coded_size_); + ASSERT_EQ(1U, fwrite(buffer, size, 1, file_.get())); } } private: base::ScopedFILE file_; - int expected_size_; + gfx::Size coded_size_; }; class MockMediaStreamRequester : public MediaStreamRequester { @@ -130,18 +134,20 @@ int buffer_id)); MOCK_METHOD2(OnBufferFreed, void(int device_id, int buffer_id)); - MOCK_METHOD5(OnBufferFilled, + MOCK_METHOD6(OnBufferFilled, void(int device_id, int buffer_id, - const media::VideoCaptureFormat& format, + const gfx::Size& coded_size, const gfx::Rect& visible_rect, - base::TimeTicks timestamp)); - MOCK_METHOD5(OnMailboxBufferFilled, + base::TimeTicks timestamp, + const base::DictionaryValue& metadata)); + MOCK_METHOD6(OnMailboxBufferFilled, void(int device_id, int buffer_id, const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp)); + const gfx::Size& packed_frame_size, + base::TimeTicks timestamp, + const base::DictionaryValue& metadata)); MOCK_METHOD2(OnStateChanged, void(int device_id, VideoCaptureState state)); // Use class DumpVideo to write I420 video to file. @@ -224,41 +230,34 @@ filled_dib_.erase(it); } - void OnBufferFilledDispatch(int device_id, - int buffer_id, - const media::VideoCaptureFormat& frame_format, - const gfx::Rect& visible_rect, - base::TimeTicks timestamp) { - base::SharedMemory* dib = filled_dib_[buffer_id]; + void OnBufferFilledDispatch( + const VideoCaptureMsg_BufferReady_Params& params) { + base::SharedMemory* dib = filled_dib_[params.buffer_id]; ASSERT_TRUE(dib != NULL); if (dump_video_) { - if (!format_.IsValid()) { - dumper_.StartDump(frame_format.frame_size.width(), - frame_format.frame_size.height()); - format_ = frame_format; - } - ASSERT_EQ(format_.frame_size.width(), frame_format.frame_size.width()) - << "Dump format does not handle variable resolution."; - ASSERT_EQ(format_.frame_size.height(), frame_format.frame_size.height()) + if (dumper_.coded_size().IsEmpty()) + dumper_.StartDump(params.coded_size); + ASSERT_TRUE(dumper_.coded_size() == params.coded_size) << "Dump format does not handle variable resolution."; dumper_.NewVideoFrame(dib->memory()); } - OnBufferFilled(device_id, buffer_id, frame_format, visible_rect, timestamp); + OnBufferFilled(params.device_id, params.buffer_id, params.coded_size, + params.visible_rect, params.timestamp, params.metadata); if (return_buffers_) { - VideoCaptureHost::OnReceiveEmptyBuffer(device_id, buffer_id, 0); + VideoCaptureHost::OnReceiveEmptyBuffer( + params.device_id, params.buffer_id, 0); } } - void OnMailboxBufferFilledDispatch(int device_id, - int buffer_id, - const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp) { - OnMailboxBufferFilled( - device_id, buffer_id, mailbox_holder, format, timestamp); + void OnMailboxBufferFilledDispatch( + const VideoCaptureMsg_MailboxBufferReady_Params& params) { + OnMailboxBufferFilled(params.device_id, params.buffer_id, + params.mailbox_holder, params.packed_frame_size, + params.timestamp, params.metadata); if (return_buffers_) { - VideoCaptureHost::OnReceiveEmptyBuffer(device_id, buffer_id, 0); + VideoCaptureHost::OnReceiveEmptyBuffer( + params.device_id, params.buffer_id, 0); } } @@ -407,7 +406,7 @@ .WillRepeatedly(Return()); base::RunLoop run_loop; - EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _)) + EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _, _)) .Times(AnyNumber()) .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure())); @@ -441,7 +440,7 @@ .Times(AnyNumber()).WillRepeatedly(Return()); base::RunLoop run_loop; - EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _, _)) + EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _, _, _)) .Times(AnyNumber()) .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure())); @@ -473,7 +472,7 @@ void NotifyPacketReady() { base::RunLoop run_loop; - EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _)) + EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _, _)) .Times(AnyNumber()) .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure())) .RetiresOnSaturation();
diff --git a/content/browser/renderer_host/media/video_capture_manager_unittest.cc b/content/browser/renderer_host/media/video_capture_manager_unittest.cc index f41984b..126186c 100644 --- a/content/browser/renderer_host/media/video_capture_manager_unittest.cc +++ b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
@@ -51,16 +51,20 @@ int length, int buffer_id) override {} virtual void OnBufferDestroyed(const VideoCaptureControllerID& id, int buffer_id) override {} - virtual void OnBufferReady(const VideoCaptureControllerID& id, - int buffer_id, - const media::VideoCaptureFormat& format, - const gfx::Rect& visible_rect, - base::TimeTicks timestamp) override {} - virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id, - int buffer_id, - const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp) override {} + virtual void OnBufferReady( + const VideoCaptureControllerID& id, + int buffer_id, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata) override {} + virtual void OnMailboxBufferReady( + const VideoCaptureControllerID& id, + int buffer_id, + const gpu::MailboxHolder& mailbox_holder, + const gfx::Size& packed_frame_size, + base::TimeTicks timestamp, + scoped_ptr<base::DictionaryValue> metadata) override {} virtual void OnEnded(const VideoCaptureControllerID& id) override {} void OnGotControllerCallback(VideoCaptureControllerID) {}
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc index bcf1aca..f8d4bcfe 100644 --- a/content/browser/renderer_host/render_message_filter.cc +++ b/content/browser/renderer_host/render_message_filter.cc
@@ -306,11 +306,12 @@ media::AudioManager* audio_manager, MediaInternals* media_internals, DOMStorageContextWrapper* dom_storage_context) - : BrowserMessageFilter( - kFilteredMessageClasses, arraysize(kFilteredMessageClasses)), + : BrowserMessageFilter(kFilteredMessageClasses, + arraysize(kFilteredMessageClasses)), resource_dispatcher_host_(ResourceDispatcherHostImpl::Get()), plugin_service_(plugin_service), profile_data_directory_(browser_context->GetPath()), + bitmap_manager_client_(HostSharedBitmapManager::current()), request_context_(request_context), resource_context_(browser_context->GetResourceContext()), render_widget_helper_(render_widget_helper), @@ -329,7 +330,6 @@ // This function should be called on the IO thread. DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(plugin_host_clients_.empty()); - HostSharedBitmapManager::current()->ProcessRemoved(PeerHandle()); BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager = BrowserGpuMemoryBufferManager::current(); if (gpu_memory_buffer_manager) @@ -920,8 +920,8 @@ const cc::SharedBitmapId& id, IPC::Message* reply_msg) { base::SharedMemoryHandle handle; - HostSharedBitmapManager::current()->AllocateSharedBitmapForChild( - PeerHandle(), buffer_size, id, &handle); + bitmap_manager_client_.AllocateSharedBitmapForChild(PeerHandle(), buffer_size, + id, &handle); ChildProcessHostMsg_SyncAllocateSharedBitmap::WriteReplyParams(reply_msg, handle); Send(reply_msg); @@ -944,12 +944,12 @@ size_t buffer_size, const base::SharedMemoryHandle& handle, const cc::SharedBitmapId& id) { - HostSharedBitmapManager::current()->ChildAllocatedSharedBitmap( - buffer_size, handle, PeerHandle(), id); + bitmap_manager_client_.ChildAllocatedSharedBitmap(buffer_size, handle, + PeerHandle(), id); } void RenderMessageFilter::OnDeletedSharedBitmap(const cc::SharedBitmapId& id) { - HostSharedBitmapManager::current()->ChildDeletedSharedBitmap(id); + bitmap_manager_client_.ChildDeletedSharedBitmap(id); } void RenderMessageFilter::OnAllocateLockedDiscardableSharedMemory(
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h index d8582e6a..877ddd0 100644 --- a/content/browser/renderer_host/render_message_filter.h +++ b/content/browser/renderer_host/render_message_filter.h
@@ -20,6 +20,7 @@ #include "base/strings/string16.h" #include "build/build_config.h" #include "cc/resources/shared_bitmap_manager.h" +#include "content/common/host_shared_bitmap_manager.h" #include "content/public/browser/browser_message_filter.h" #include "content/public/common/three_d_api_types.h" #include "ipc/message_filter.h" @@ -310,6 +311,8 @@ PluginServiceImpl* plugin_service_; base::FilePath profile_data_directory_; + HostSharedBitmapManagerClient bitmap_manager_client_; + // Contextual information to be used for requests created here. scoped_refptr<net::URLRequestContextGetter> request_context_;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 6564c438..7f5c54d 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -110,6 +110,7 @@ #include "content/common/frame_messages.h" #include "content/common/gpu/gpu_memory_buffer_factory.h" #include "content/common/gpu/gpu_messages.h" +#include "content/common/mojo/channel_init.h" #include "content/common/mojo/mojo_messages.h" #include "content/common/resource_messages.h" #include "content/common/view_messages.h" @@ -166,8 +167,10 @@ #if defined(OS_WIN) #include "base/win/scoped_com_initializer.h" +#include "base/win/windows_version.h" #include "content/common/font_cache_dispatcher_win.h" #include "content/common/sandbox_win.h" +#include "sandbox/win/src/sandbox_policy.h" #include "ui/gfx/win/dpi.h" #endif @@ -326,6 +329,20 @@ virtual void PreSpawnTarget(sandbox::TargetPolicy* policy, bool* success) { AddBaseHandleClosePolicy(policy); + + if (base::win::GetVersion() >= base::win::VERSION_WIN8) { + // TODO(shrikant): Check if these constants should be different across + // various versions of Chromium code base or could be same. + // If there should be different SID per channel then move this code + // in chrome rather than content and assign SID based on + // VersionInfo::GetChannel(). + const wchar_t kAppContainerSid[] = + L"S-1-15-2-3251537155-1984446955-2931258699-841473695-1938553385-" + L"924012148-129201922"; + + policy->SetLowBox(kAppContainerSid); + } + GetContentClient()->browser()->PreSpawnRenderer(policy, success); } @@ -664,9 +681,15 @@ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); if (ShouldUseMojoChannel()) { VLOG(1) << "Mojo Channel is enabled on host"; + scoped_refptr<base::SequencedTaskRunner> io_task_runner = + BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO) + ->task_runner(); if (!channel_mojo_host_) { - channel_mojo_host_.reset(new IPC::ChannelMojoHost( - BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))); + channel_mojo_host_.reset(new IPC::ChannelMojoHost(io_task_runner)); + } + + if (run_renderer_in_process()) { + ChannelInit::SetSingleProcessIOTaskRunner(io_task_runner); } return IPC::ChannelProxy::Create(
diff --git a/content/browser/renderer_host/render_widget_host_latency_tracker.cc b/content/browser/renderer_host/render_widget_host_latency_tracker.cc index 9cbd986..8de5512 100644 --- a/content/browser/renderer_host/render_widget_host_latency_tracker.cc +++ b/content/browser/renderer_host/render_widget_host_latency_tracker.cc
@@ -150,10 +150,10 @@ 1, 50000, 50) void ComputeScrollLatencyHistograms( - const LatencyInfo::LatencyComponent& swap_component, + const LatencyInfo::LatencyComponent& gpu_swap_component, int64 latency_component_id, - const ui::LatencyInfo& latency) { - DCHECK(!swap_component.event_time.is_null()); + const LatencyInfo& latency) { + DCHECK(!gpu_swap_component.event_time.is_null()); LatencyInfo::LatencyComponent first_original_component, original_component; if (latency.FindLatency( ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, @@ -164,7 +164,7 @@ for (size_t i = 0; i < first_original_component.event_count; i++) { UMA_HISTOGRAM_CUSTOM_COUNTS( "Event.Latency.TouchToFirstScrollUpdateSwap", - (swap_component.event_time - first_original_component.event_time) + (gpu_swap_component.event_time - first_original_component.event_time) .InMicroseconds(), 1, 1000000, 100); } @@ -181,7 +181,7 @@ for (size_t i = 0; i < original_component.event_count; i++) { UMA_HISTOGRAM_CUSTOM_COUNTS( "Event.Latency.TouchToScrollUpdateSwap", - (swap_component.event_time - original_component.event_time) + (gpu_swap_component.event_time - original_component.event_time) .InMicroseconds(), 1, 1000000, 100); } @@ -235,17 +235,19 @@ "Event.Latency.ScrollUpdate.RendererSwapToBrowserNotified", renderer_swap_component, browser_received_swap_component); - LatencyInfo::LatencyComponent gpu_swap_component; - if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, - 0, &gpu_swap_component)) - return; - UMA_HISTOGRAM_SCROLL_LATENCY_LONG( "Event.Latency.ScrollUpdate.BrowserNotifiedToBeforeGpuSwap", browser_received_swap_component, gpu_swap_component); + LatencyInfo::LatencyComponent gpu_swap_ack_component; + if (!latency.FindLatency( + ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, + &gpu_swap_ack_component)) + return; + UMA_HISTOGRAM_SCROLL_LATENCY_SHORT("Event.Latency.ScrollUpdate.GpuSwap", - gpu_swap_component, swap_component); + gpu_swap_component, + gpu_swap_ack_component); } // LatencyComponents generated in the renderer must have component IDs @@ -389,11 +391,10 @@ } void RenderWidgetHostLatencyTracker::OnFrameSwapped( - const ui::LatencyInfo& latency) { - LatencyInfo::LatencyComponent swap_component; - if (!latency.FindLatency( - ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, - &swap_component)) { + const LatencyInfo& latency) { + LatencyInfo::LatencyComponent gpu_swap_component; + if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, + &gpu_swap_component)) { return; } @@ -401,28 +402,21 @@ if (latency.FindLatency(ui::TAB_SHOW_COMPONENT, latency_component_id_, &tab_switch_component)) { base::TimeDelta delta = - swap_component.event_time - tab_switch_component.event_time; + gpu_swap_component.event_time - tab_switch_component.event_time; for (size_t i = 0; i < tab_switch_component.event_count; i++) { UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", delta); } } - LatencyInfo::LatencyComponent rwh_component; if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, - latency_component_id_, &rwh_component)) { + latency_component_id_, nullptr)) { return; } - ComputeScrollLatencyHistograms(swap_component, latency_component_id_, + ComputeScrollLatencyHistograms(gpu_swap_component, latency_component_id_, latency); - ui::LatencyInfo::LatencyComponent gpu_swap_component; - if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, - &gpu_swap_component)) { - return; - } - - ui::LatencyInfo::LatencyComponent browser_swap_component; + LatencyInfo::LatencyComponent browser_swap_component; if (latency.FindLatency( ui::INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT, 0, &browser_swap_component)) {
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index 50ca24c1..02045bd4 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -1867,11 +1867,12 @@ int handles_per_frame = 5; RendererFrameManager::GetInstance()->set_max_handles(handles_per_frame * 2); + HostSharedBitmapManagerClient bitmap_client( + HostSharedBitmapManager::current()); + for (size_t i = 0; i < (renderer_count - 1) * handles_per_frame; i++) { - HostSharedBitmapManager::current()->ChildAllocatedSharedBitmap( - 1, - base::SharedMemory::NULLHandle(), - base::GetCurrentProcessHandle(), + bitmap_client.ChildAllocatedSharedBitmap( + 1, base::SharedMemory::NULLHandle(), base::GetCurrentProcessHandle(), cc::SharedBitmap::GenerateId()); } @@ -1883,8 +1884,6 @@ else EXPECT_TRUE(views[i]->HasFrameData()); } - HostSharedBitmapManager::current()->ProcessRemoved( - base::GetCurrentProcessHandle()); RendererFrameManager::GetInstance()->set_max_handles( base::SharedMemory::GetHandleLimit());
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 7859423..7f3cb354 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -829,6 +829,7 @@ } void RenderWidgetHostViewMac::Show() { + ScopedCAActionDisabler disabler; [cocoa_view_ setHidden:NO]; if (!render_widget_host_->is_hidden()) return; @@ -842,6 +843,7 @@ } void RenderWidgetHostViewMac::Hide() { + ScopedCAActionDisabler disabler; [cocoa_view_ setHidden:YES]; WasOccluded(); DestroySuspendedBrowserCompositorViewIfNeeded();
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc index e28ee728..fbfc454 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.cc +++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -137,8 +137,7 @@ } void EmbeddedWorkerTestHelper::OnInstallEvent(int embedded_worker_id, - int request_id, - int active_version_id) { + int request_id) { // The installing worker may have been doomed and terminated. if (!registry()->GetWorker(embedded_worker_id)) return; @@ -283,15 +282,13 @@ request_id)); } -void EmbeddedWorkerTestHelper::OnInstallEventStub(int request_id, - int active_version_id) { +void EmbeddedWorkerTestHelper::OnInstallEventStub(int request_id) { base::MessageLoopProxy::current()->PostTask( FROM_HERE, base::Bind(&EmbeddedWorkerTestHelper::OnInstallEvent, weak_factory_.GetWeakPtr(), current_embedded_worker_id_, - request_id, - active_version_id)); + request_id)); } void EmbeddedWorkerTestHelper::OnFetchEventStub(
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h index 6640d853..fe1a16e 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.h +++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -92,9 +92,7 @@ // worker. By default they just return success via // SimulateSendReplyToBrowser. virtual void OnActivateEvent(int embedded_worker_id, int request_id); - virtual void OnInstallEvent(int embedded_worker_id, - int request_id, - int active_version_id); + virtual void OnInstallEvent(int embedded_worker_id, int request_id); virtual void OnFetchEvent(int embedded_worker_id, int request_id, const ServiceWorkerFetchRequest& request); @@ -119,7 +117,7 @@ int embedded_worker_id, const IPC::Message& message); void OnActivateEventStub(int request_id); - void OnInstallEventStub(int request_id, int active_version_id); + void OnInstallEventStub(int request_id); void OnFetchEventStub(int request_id, const ServiceWorkerFetchRequest& request);
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc index efaa1fc..9f9a8df 100644 --- a/content/browser/service_worker/service_worker_browsertest.cc +++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -568,7 +568,7 @@ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); version_->SetStatus(ServiceWorkerVersion::INSTALLING); version_->DispatchInstallEvent( - -1, CreateReceiver(BrowserThread::UI, done, result)); + CreateReceiver(BrowserThread::UI, done, result)); } void ActivateOnIOThread(const base::Closure& done,
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc index 4f4e8d1f..4ae67d4 100644 --- a/content/browser/service_worker/service_worker_context_core.cc +++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -141,8 +141,7 @@ ServiceWorkerContextWrapper* wrapper) : wrapper_(wrapper), providers_(old_context->providers_.release()), - cache_manager_(ServiceWorkerCacheStorageManager::Create( - old_context->cache_manager())), + cache_manager_(old_context->cache_manager_.release()), next_handle_id_(old_context->next_handle_id_), next_registration_handle_id_(old_context->next_registration_handle_id_), observer_list_(old_context->observer_list_),
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc index 71afa32..65542795 100644 --- a/content/browser/service_worker/service_worker_context_unittest.cc +++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -81,8 +81,7 @@ : EmbeddedWorkerTestHelper(mock_render_process_id) {} void OnInstallEvent(int embedded_worker_id, - int request_id, - int active_version_id) override { + int request_id) override { SimulateSend( new ServiceWorkerHostMsg_InstallEventFinished( embedded_worker_id, request_id,
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc index 6f1d95f0..872ac573 100644 --- a/content/browser/service_worker/service_worker_dispatcher_host.cc +++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -570,6 +570,9 @@ ServiceWorkerRegistration* registration = GetContext()->GetLiveRegistration(version->registration_id()); DCHECK(registration); + // TODO(ksakamoto): This is a quick fix for crbug.com/459916. + if (!registration) + return; // Set the document URL to the script url in order to allow // register/unregister/getRegistration on ServiceWorkerGlobalScope.
diff --git a/content/browser/service_worker/service_worker_handle_unittest.cc b/content/browser/service_worker/service_worker_handle_unittest.cc index 7b2d708..38dd177 100644 --- a/content/browser/service_worker/service_worker_handle_unittest.cc +++ b/content/browser/service_worker/service_worker_handle_unittest.cc
@@ -134,7 +134,7 @@ // ...dispatch install event. status = SERVICE_WORKER_ERROR_FAILED; version_->SetStatus(ServiceWorkerVersion::INSTALLING); - version_->DispatchInstallEvent(-1, CreateReceiverOnCurrentThread(&status)); + version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status)); base::RunLoop().RunUntilIdle(); EXPECT_EQ(SERVICE_WORKER_OK, status);
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc index ef9c99a6..5e54e07 100644 --- a/content/browser/service_worker/service_worker_job_unittest.cc +++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -1262,8 +1262,7 @@ activate_event_result_(blink::WebServiceWorkerEventResultCompleted) {} void OnInstallEvent(int embedded_worker_id, - int request_id, - int active_version_id) override { + int request_id) override { if (!install_callback_.is_null()) install_callback_.Run(); SimulateSend(
diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc index 0a28dc1..986cae3 100644 --- a/content/browser/service_worker/service_worker_register_job.cc +++ b/content/browser/service_worker/service_worker_register_job.cc
@@ -377,7 +377,6 @@ // "Fire an event named install..." new_version()->DispatchInstallEvent( - -1, base::Bind(&ServiceWorkerRegisterJob::OnInstallFinished, weak_factory_.GetWeakPtr()));
diff --git a/content/browser/service_worker/service_worker_registration_status.cc b/content/browser/service_worker/service_worker_registration_status.cc index 84f293e..e9b55f4 100644 --- a/content/browser/service_worker/service_worker_registration_status.cc +++ b/content/browser/service_worker/service_worker_registration_status.cc
@@ -48,6 +48,9 @@ return; case SERVICE_WORKER_ERROR_ABORT: + *error_type = WebServiceWorkerError::ErrorTypeAbort; + return; + case SERVICE_WORKER_ERROR_IPC_FAILED: case SERVICE_WORKER_ERROR_FAILED: case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
diff --git a/content/browser/service_worker/service_worker_script_cache_map.cc b/content/browser/service_worker/service_worker_script_cache_map.cc index 925fe6e..6d5361ff 100644 --- a/content/browser/service_worker/service_worker_script_cache_map.cc +++ b/content/browser/service_worker/service_worker_script_cache_map.cc
@@ -57,7 +57,8 @@ const std::string& status_message) { DCHECK_NE(kInvalidServiceWorkerResponseId, LookupResourceId(url)); DCHECK(owner_->status() == ServiceWorkerVersion::NEW || - owner_->status() == ServiceWorkerVersion::INSTALLING); + owner_->status() == ServiceWorkerVersion::INSTALLING || + owner_->status() == ServiceWorkerVersion::REDUNDANT); if (!context_) return; // Our storage has been wiped via DeleteAndStartOver. if (!status.is_success()) {
diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc index ad3d3d4..9ae8c51 100644 --- a/content/browser/service_worker/service_worker_storage.cc +++ b/content/browser/service_worker/service_worker_storage.cc
@@ -1126,9 +1126,11 @@ if (registration_data.is_active) { info.active_version.status = ServiceWorkerVersion::ACTIVATED; + info.active_version.script_url = registration_data.script; info.active_version.version_id = registration_data.version_id; } else { info.waiting_version.status = ServiceWorkerVersion::INSTALLED; + info.waiting_version.script_url = registration_data.script; info.waiting_version.version_id = registration_data.version_id; } infos.push_back(info);
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index 747319e..b09be14 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -426,22 +426,6 @@ context_->UpdateServiceWorker(registration); } -void ServiceWorkerVersion::SendMessage( - const IPC::Message& message, const StatusCallback& callback) { - if (running_status() != RUNNING) { - // Schedule calling this method after starting the worker. - StartWorker(base::Bind(&RunTaskAfterStartWorker, - weak_factory_.GetWeakPtr(), callback, - base::Bind(&self::SendMessage, - weak_factory_.GetWeakPtr(), - message, callback))); - return; - } - - ServiceWorkerStatusCode status = embedded_worker_->SendMessage(message); - RunSoon(base::Bind(callback, status)); -} - void ServiceWorkerVersion::DispatchMessageEvent( const base::string16& message, const std::vector<TransferredMessagePort>& sent_message_ports, @@ -479,7 +463,6 @@ } void ServiceWorkerVersion::DispatchInstallEvent( - int active_version_id, const StatusCallback& callback) { DCHECK_EQ(INSTALLING, status()) << status(); @@ -491,10 +474,9 @@ callback, base::Bind(&self::DispatchInstallEventAfterStartWorker, weak_factory_.GetWeakPtr(), - active_version_id, callback))); } else { - DispatchInstallEventAfterStartWorker(active_version_id, callback); + DispatchInstallEventAfterStartWorker(callback); } } @@ -960,14 +942,13 @@ } void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker( - int active_version_id, const StatusCallback& callback) { DCHECK_EQ(RUNNING, running_status()) << "Worker stopped too soon after it was started."; int request_id = install_callbacks_.Add(new StatusCallback(callback)); ServiceWorkerStatusCode status = embedded_worker_->SendMessage( - ServiceWorkerMsg_InstallEvent(request_id, active_version_id)); + ServiceWorkerMsg_InstallEvent(request_id)); if (status != SERVICE_WORKER_OK) { install_callbacks_.Remove(request_id); RunSoon(base::Bind(callback, status));
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index 2aeaabb..5c53d23 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h
@@ -166,13 +166,6 @@ // Starts an update now. void StartUpdate(); - // Sends an IPC message to the worker. - // If the worker is not running this first tries to start it by - // calling StartWorker internally. - // |callback| can be null if the sender does not need to know if the - // message is successfully sent or not. - void SendMessage(const IPC::Message& message, const StatusCallback& callback); - // Sends a message event to the associated embedded worker. void DispatchMessageEvent( const base::string16& message, @@ -182,15 +175,12 @@ // Sends install event to the associated embedded worker and asynchronously // calls |callback| when it errors out or it gets a response from the worker // to notify install completion. - // |active_version_id| must be a valid positive ID - // if there's an activated (previous) version running. // // This must be called when the status() is NEW. Calling this changes // the version's status to INSTALLING. // Upon completion, the version's status will be changed to INSTALLED // on success, or back to NEW on failure. - void DispatchInstallEvent(int active_version_id, - const StatusCallback& callback); + void DispatchInstallEvent(const StatusCallback& callback); // Sends activate event to the associated embedded worker and asynchronously // calls |callback| when it errors out or it gets a response from the worker @@ -348,8 +338,7 @@ void OnStartMessageSent(ServiceWorkerStatusCode status); - void DispatchInstallEventAfterStartWorker(int active_version_id, - const StatusCallback& callback); + void DispatchInstallEventAfterStartWorker(const StatusCallback& callback); void DispatchActivateEventAfterStartWorker(const StatusCallback& callback); void DispatchMessageEventInternal(
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc index 7cf16e2d..2b3739d 100644 --- a/content/browser/service_worker/service_worker_version_unittest.cc +++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -250,31 +250,30 @@ EXPECT_EQ(SERVICE_WORKER_OK, status3); } -TEST_F(ServiceWorkerVersionTest, SendMessage) { +TEST_F(ServiceWorkerVersionTest, DispatchEventToStoppedWorker) { EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status()); - // Send a message without starting the worker. + // Dispatch an event without starting the worker. ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED; - version_->SendMessage(TestMsg_Message(), - CreateReceiverOnCurrentThread(&status)); + version_->SetStatus(ServiceWorkerVersion::INSTALLING); + version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status)); base::RunLoop().RunUntilIdle(); EXPECT_EQ(SERVICE_WORKER_OK, status); // The worker should be now started. EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status()); - // Stop the worker, and then send the message immediately. - ServiceWorkerStatusCode msg_status = SERVICE_WORKER_ERROR_FAILED; + // Stop the worker, and then dispatch an event immediately after that. + status = SERVICE_WORKER_ERROR_FAILED; ServiceWorkerStatusCode stop_status = SERVICE_WORKER_ERROR_FAILED; version_->StopWorker(CreateReceiverOnCurrentThread(&stop_status)); - version_->SendMessage(TestMsg_Message(), - CreateReceiverOnCurrentThread(&msg_status)); + version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status)); base::RunLoop().RunUntilIdle(); EXPECT_EQ(SERVICE_WORKER_OK, stop_status); - // SendMessage should return SERVICE_WORKER_OK since the worker should have - // been restarted to deliver the message. - EXPECT_EQ(SERVICE_WORKER_OK, msg_status); + // Dispatch an event should return SERVICE_WORKER_OK since the worker + // should have been restarted to dispatch the event. + EXPECT_EQ(SERVICE_WORKER_OK, status); // The worker should be now started again. EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status()); @@ -308,7 +307,7 @@ // Dispatch an install event. ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED; - version_->DispatchInstallEvent(-1, CreateReceiverOnCurrentThread(&status)); + version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status)); // Wait for the completion. bool status_change_called = false;
diff --git a/content/browser/speech/speech_recognition_browsertest.cc b/content/browser/speech/speech_recognition_browsertest.cc index 62b22ad23..8bc0749f 100644 --- a/content/browser/speech/speech_recognition_browsertest.cc +++ b/content/browser/speech/speech_recognition_browsertest.cc
@@ -94,7 +94,7 @@ } std::string GetPageFragment() { - return shell()->web_contents()->GetURL().ref(); + return shell()->web_contents()->GetLastCommittedURL().ref(); } const StreamingServerState &streaming_server_state() {
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc index 5e2b128..5a89df6 100644 --- a/content/browser/web_contents/web_contents_android.cc +++ b/content/browser/web_contents/web_contents_android.cc
@@ -170,6 +170,14 @@ return ConvertUTF8ToJavaString(env, web_contents_->GetURL().spec()); } +ScopedJavaLocalRef<jstring> WebContentsAndroid::GetLastCommittedURL( + JNIEnv* env, + jobject) const { + return ConvertUTF8ToJavaString(env, + web_contents_->GetLastCommittedURL().spec()); +} + + jboolean WebContentsAndroid::IsIncognito(JNIEnv* env, jobject obj) { return web_contents_->GetBrowserContext()->IsOffTheRecord(); } @@ -480,4 +488,11 @@ ConvertJavaStringToUTF8(env, message))); } +jboolean WebContentsAndroid::HasAccessedInitialDocument( + JNIEnv* env, + jobject jobj) { + return static_cast<content::WebContentsImpl*>(web_contents_)-> + HasAccessedInitialDocument(); +} + } // namespace content
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h index 4379e3d..7f259efd 100644 --- a/content/browser/web_contents/web_contents_android.h +++ b/content/browser/web_contents/web_contents_android.h
@@ -50,6 +50,8 @@ void Stop(JNIEnv* env, jobject obj); jint GetBackgroundColor(JNIEnv* env, jobject obj); base::android::ScopedJavaLocalRef<jstring> GetURL(JNIEnv* env, jobject) const; + base::android::ScopedJavaLocalRef<jstring> GetLastCommittedURL(JNIEnv* env, + jobject) const; jboolean IsIncognito(JNIEnv* env, jobject obj); void ResumeResponseDeferredAtStart(JNIEnv* env, jobject obj); @@ -109,6 +111,8 @@ jint level, jstring message); + jboolean HasAccessedInitialDocument(JNIEnv* env, jobject jobj); + private: RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid();
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index ede1642..d47a6ef 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -108,6 +108,7 @@ #if defined(OS_ANDROID) #include "content/browser/android/content_video_view.h" #include "content/browser/android/date_time_chooser_android.h" +#include "content/browser/android/media_players_observer.h" #include "content/browser/media/android/browser_media_player_manager.h" #include "content/browser/web_contents/web_contents_android.h" #endif @@ -151,8 +152,10 @@ scoped_refptr<net::URLRequestContextGetter> request_context, const GURL& url, const std::string& http_method) { - request_context->GetURLRequestContext()->http_transaction_factory()-> - GetCache()->OnExternalCacheHit(url, http_method); + net::HttpCache* cache = request_context->GetURLRequestContext()-> + http_transaction_factory()->GetCache(); + if (cache) + cache->OnExternalCacheHit(url, http_method); } // Helper function for retrieving all the sites in a frame tree. @@ -358,7 +361,6 @@ geolocation_service_context_(new GeolocationServiceContext()), accessibility_mode_( BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()), - audio_stream_monitor_(this), virtual_keyboard_requested_(false), loading_weak_factory_(this) { frame_tree_.SetFrameRemoveListener( @@ -367,6 +369,12 @@ #if defined(ENABLE_BROWSER_CDMS) media_web_contents_observer_.reset(new MediaWebContentsObserver(this)); #endif + +#if defined(OS_ANDROID) + audio_state_provider_.reset(new MediaPlayersObserver(this)); +#else + audio_state_provider_.reset(new AudioStreamMonitor(this)); +#endif } WebContentsImpl::~WebContentsImpl() { @@ -1041,7 +1049,7 @@ // Create and release the audio power save blocker depending on whether the // tab is actively producing audio or not. if ((changed_flags & INVALIDATE_TYPE_TAB) && - AudioStreamMonitor::monitoring_available()) { + audio_state_provider_->IsAudioStateAvailable()) { if (WasRecentlyAudible()) { if (!audio_power_save_blocker_) CreateAudioPowerSaveBlocker(); @@ -1272,6 +1280,13 @@ RenderViewCreated(GetRenderViewHost()); GetRenderManager()->current_frame_host()->SetRenderFrameCreated(true); } + + // Ensure that observers are notified of the creation of this WebContents's + // main RenderFrameHost. It must be done here for main frames, since the + // NotifySwappedFromRenderManager expects view_ to already be created and that + // happens after RenderFrameHostManager::Init. + NotifySwappedFromRenderManager( + nullptr, GetRenderManager()->current_frame_host(), true); } void WebContentsImpl::OnWebContentsDestroyed(WebContentsImpl* web_contents) { @@ -2516,7 +2531,7 @@ } bool WebContentsImpl::WasRecentlyAudible() { - return audio_stream_monitor_.WasRecentlyAudible(); + return audio_state_provider_->WasRecentlyAudible(); } void WebContentsImpl::GetManifest(const GetManifestCallback& callback) { @@ -3203,7 +3218,7 @@ // monitoring, release the audio power save blocker here instead of during // NotifyNavigationStateChanged(). if (active_audio_players_.empty() && - !AudioStreamMonitor::monitoring_available()) { + !audio_state_provider_->IsAudioStateAvailable()) { audio_power_save_blocker_.reset(); } @@ -3226,7 +3241,7 @@ // If we don't have audio stream monitoring, allocate the audio power save // blocker here instead of during NotifyNavigationStateChanged(). if (!audio_power_save_blocker_ && - !AudioStreamMonitor::monitoring_available()) { + !audio_state_provider_->IsAudioStateAvailable()) { CreateAudioPowerSaveBlocker(); } } @@ -4184,7 +4199,7 @@ RenderFrameHost* new_host, bool is_main_frame) { if (is_main_frame) { - NotifyViewSwapped(old_host ? old_host->GetRenderViewHost() : NULL, + NotifyViewSwapped(old_host ? old_host->GetRenderViewHost() : nullptr, new_host->GetRenderViewHost()); // Make sure the visible RVH reflects the new delegate's preferences. @@ -4197,6 +4212,12 @@ NotifyFrameSwapped(old_host, new_host); } +void WebContentsImpl::NotifyMainFrameSwappedFromRenderManager( + RenderViewHost* old_host, + RenderViewHost* new_host) { + NotifyViewSwapped(old_host, new_host); +} + int WebContentsImpl::CreateOpenerRenderViewsForRenderManager( SiteInstance* instance) { if (!opener_)
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index ae57bea4..2e0e9661 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -22,7 +22,7 @@ #include "content/browser/frame_host/navigator_delegate.h" #include "content/browser/frame_host/render_frame_host_delegate.h" #include "content/browser/frame_host/render_frame_host_manager.h" -#include "content/browser/media/audio_stream_monitor.h" +#include "content/browser/media/audio_state_provider.h" #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/renderer_host/render_widget_host_delegate.h" #include "content/common/accessibility_mode_enums.h" @@ -568,6 +568,9 @@ void NotifySwappedFromRenderManager(RenderFrameHost* old_host, RenderFrameHost* new_host, bool is_main_frame) override; + void NotifyMainFrameSwappedFromRenderManager( + RenderViewHost* old_host, + RenderViewHost* new_host) override; int CreateOpenerRenderViewsForRenderManager(SiteInstance* instance) override; NavigationControllerImpl& GetControllerForRenderManager() override; scoped_ptr<WebUIImpl> CreateWebUIForRenderManager(const GURL& url) override; @@ -666,8 +669,8 @@ // Forces overscroll to be disabled (used by touch emulation). void SetForceDisableOverscrollContent(bool force_disable); - AudioStreamMonitor* audio_stream_monitor() { - return &audio_stream_monitor_; + AudioStateProvider* audio_state_provider() { + return audio_state_provider_.get(); } bool has_audio_power_save_blocker_for_testing() const { @@ -1022,6 +1025,11 @@ scoped_ptr<PowerSaveBlocker> audio_power_save_blocker_; scoped_ptr<PowerSaveBlocker> video_power_save_blocker_; + // Tells whether this WebContents is actively producing sound. + // Order is important: the |frame_tree_| destruction uses + // |audio_state_provider_|. + scoped_ptr<AudioStateProvider> audio_state_provider_; + // Manages the frame tree of the page and process swaps in each node. FrameTree frame_tree_; @@ -1236,9 +1244,6 @@ // is created, and broadcast to all frames when it changes. AccessibilityMode accessibility_mode_; - // Monitors power levels for audio streams associated with this WebContents. - AudioStreamMonitor audio_stream_monitor_; - // Created on-demand to mute all audio output from this WebContents. scoped_ptr<WebContentsAudioMuter> audio_muter_;
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc index da3c82e..5e322ef3 100644 --- a/content/browser/web_contents/web_contents_impl_unittest.cc +++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -9,7 +9,7 @@ #include "content/browser/frame_host/interstitial_page_impl.h" #include "content/browser/frame_host/navigation_entry_impl.h" #include "content/browser/frame_host/render_frame_host_impl.h" -#include "content/browser/media/audio_stream_monitor.h" +#include "content/browser/media/audio_state_provider.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/site_instance_impl.h" #include "content/browser/webui/web_ui_controller_factory_registry.h" @@ -483,7 +483,7 @@ const GURL url("http://www.google.com"); controller().LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - orig_rfh->PrepareForCommit(url); + orig_rfh->PrepareForCommit(); contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED); // Keep the number of active frames in orig_rfh's SiteInstance non-zero so @@ -501,7 +501,7 @@ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableBrowserSideNavigation)) { - orig_rfh->PrepareForCommit(url2); + orig_rfh->PrepareForCommit(); } EXPECT_TRUE(contents()->cross_navigation_pending()); EXPECT_EQ(url, contents()->GetLastCommittedURL()); @@ -520,7 +520,6 @@ } // DidNavigate from the pending page - pending_rfh->PrepareForCommit(url2); contents()->TestDidNavigate( pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED); SiteInstance* instance2 = contents()->GetSiteInstance(); @@ -547,7 +546,7 @@ controller().GoBack(); if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableBrowserSideNavigation)) { - contents()->GetMainFrame()->PrepareForCommit(url); + contents()->GetMainFrame()->PrepareForCommit(); } TestRenderFrameHost* goback_rfh = contents()->GetPendingMainFrame(); EXPECT_EQ(orig_rfh, goback_rfh); @@ -591,7 +590,7 @@ const GURL url("http://www.google.com"); controller().LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(url); + contents()->GetMainFrame()->PrepareForCommit(); contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED); EXPECT_FALSE(contents()->cross_navigation_pending()); @@ -605,7 +604,7 @@ const GURL url2("http://www.yahoo.com"); controller().LoadURL( url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(url2); + contents()->GetMainFrame()->PrepareForCommit(); TestRenderFrameHost* new_rfh = contents()->GetMainFrame(); EXPECT_FALSE(contents()->cross_navigation_pending()); EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL); @@ -637,7 +636,7 @@ const GURL url("http://www.google.com"); controller().LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(url); + contents()->GetMainFrame()->PrepareForCommit(); contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED); // Open a new contents with the same SiteInstance, navigated to the same site. @@ -646,7 +645,7 @@ contents2->GetController().LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents2->GetMainFrame()->PrepareForCommit(url); + contents2->GetMainFrame()->PrepareForCommit(); // Need this page id to be 2 since the site instance is the same (which is the // scope of page IDs) and we want to consider this a new page. contents2->TestDidNavigate( @@ -656,7 +655,7 @@ const GURL url2a("http://www.yahoo.com"); controller().LoadURL( url2a, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - orig_rfh->PrepareForCommit(url2a); + orig_rfh->PrepareForCommit(); TestRenderFrameHost* pending_rfh_a = contents()->GetPendingMainFrame(); contents()->TestDidNavigate( pending_rfh_a, 1, url2a, ui::PAGE_TRANSITION_TYPED); @@ -669,7 +668,7 @@ ui::PAGE_TRANSITION_TYPED, std::string()); TestRenderFrameHost* rfh2 = contents2->GetMainFrame(); - rfh2->PrepareForCommit(url2b); + rfh2->PrepareForCommit(); TestRenderFrameHost* pending_rfh_b = contents2->GetPendingMainFrame(); EXPECT_TRUE(pending_rfh_b != NULL); EXPECT_TRUE(contents2->cross_navigation_pending()); @@ -704,7 +703,7 @@ const GURL native_url("non-site-url://stuffandthings"); controller().LoadURL( native_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(native_url); + contents()->GetMainFrame()->PrepareForCommit(); contents()->TestDidNavigate( orig_rfh, 1, native_url, ui::PAGE_TRANSITION_TYPED); @@ -721,7 +720,7 @@ const GURL url("http://www.google.com"); controller().LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(url); + contents()->GetMainFrame()->PrepareForCommit(); EXPECT_FALSE(contents()->cross_navigation_pending()); EXPECT_EQ(native_url, contents()->GetLastCommittedURL()); EXPECT_EQ(url, contents()->GetVisibleURL()); @@ -744,7 +743,7 @@ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableBrowserSideNavigation)) { - orig_rfh->PrepareForCommit(url2); + orig_rfh->PrepareForCommit(); } EXPECT_TRUE(contents()->cross_navigation_pending()); EXPECT_EQ(url, contents()->GetLastCommittedURL()); @@ -854,7 +853,7 @@ ASSERT_EQ(0u, entries.size()); ASSERT_EQ(1, controller().GetEntryCount()); controller().GoToIndex(0); - orig_rfh->PrepareForCommit(regular_url); + orig_rfh->PrepareForCommit(); contents()->TestDidNavigate( orig_rfh, 0, regular_url, ui::PAGE_TRANSITION_RELOAD); EXPECT_EQ(orig_instance, contents()->GetSiteInstance()); @@ -864,7 +863,7 @@ const GURL url("http://www.google.com"); controller().LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - orig_rfh->PrepareForCommit(url); + orig_rfh->PrepareForCommit(); contents()->TestDidNavigate( contents()->GetPendingMainFrame(), 2, url, ui::PAGE_TRANSITION_TYPED); EXPECT_NE(orig_instance, contents()->GetSiteInstance()); @@ -882,14 +881,14 @@ const GURL url("http://www.google.com"); controller().LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - orig_rfh->PrepareForCommit(url); + orig_rfh->PrepareForCommit(); contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED); // Start to navigate first tab to a new site, so that it has a pending RVH. const GURL url2("http://www.yahoo.com"); controller().LoadURL( url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - orig_rfh->PrepareForCommit(url2); + orig_rfh->PrepareForCommit(); TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame(); // While it is still pending, simulate opening a new tab with the first tab @@ -913,7 +912,7 @@ const GURL url("http://www.google.com"); controller().LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(url); + contents()->GetMainFrame()->PrepareForCommit(); contents()->TestDidNavigate( orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED); @@ -924,7 +923,7 @@ contents2->GetController().LoadURL(url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents2->GetMainFrame()->PrepareForCommit(url2); + contents2->GetMainFrame()->PrepareForCommit(); // The first RVH in contents2 isn't live yet, so we shortcut the cross site // pending. TestRenderFrameHost* rfh2 = contents2->GetMainFrame(); @@ -948,7 +947,7 @@ controller().LoadURL( url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); EXPECT_FALSE(contents()->cross_navigation_pending()); - contents()->GetMainFrame()->PrepareForCommit(url3); + contents()->GetMainFrame()->PrepareForCommit(); contents()->TestDidNavigate( orig_rfh, 3, url3, ui::PAGE_TRANSITION_TYPED); SiteInstance* instance4 = contents()->GetSiteInstance(); @@ -965,7 +964,7 @@ const GURL url("http://www.google.com"); controller().LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(url); + contents()->GetMainFrame()->PrepareForCommit(); contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED); EXPECT_FALSE(contents()->cross_navigation_pending()); EXPECT_EQ(orig_rfh, contents()->GetMainFrame()); @@ -987,7 +986,7 @@ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK()); now = base::TimeTicks::Now(); - orig_rfh->PrepareForCommit(url2); + orig_rfh->PrepareForCommit(); EXPECT_FALSE(orig_rfh->IsWaitingForBeforeUnloadACK()); EXPECT_TRUE(contents()->cross_navigation_pending()); TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame(); @@ -1015,7 +1014,7 @@ const GURL url("http://www.google.com"); controller().LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(url); + contents()->GetMainFrame()->PrepareForCommit(); contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED); EXPECT_FALSE(contents()->cross_navigation_pending()); EXPECT_EQ(orig_rfh, contents()->GetMainFrame()); @@ -1025,7 +1024,7 @@ controller().LoadURL( url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK()); - orig_rfh->PrepareForCommit(url2); + orig_rfh->PrepareForCommit(); EXPECT_TRUE(contents()->cross_navigation_pending()); // Suppose the original renderer navigates before the new one is ready. @@ -1046,7 +1045,7 @@ controller().LoadURL( url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame(); - ntp_rfh->PrepareForCommit(url1); + ntp_rfh->PrepareForCommit(); contents()->TestDidNavigate(ntp_rfh, 1, url1, ui::PAGE_TRANSITION_TYPED); NavigationEntry* entry1 = controller().GetLastCommittedEntry(); SiteInstance* instance1 = contents()->GetSiteInstance(); @@ -1069,7 +1068,7 @@ // Simulate beforeunload approval. EXPECT_TRUE(ntp_rfh->IsWaitingForBeforeUnloadACK()); base::TimeTicks now = base::TimeTicks::Now(); - ntp_rfh->PrepareForCommit(url2); + ntp_rfh->PrepareForCommit(); // DidNavigate from the pending page. contents()->TestDidNavigate( @@ -1092,7 +1091,7 @@ controller().LoadURL( url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); EXPECT_FALSE(contents()->cross_navigation_pending()); - contents()->GetMainFrame()->PrepareForCommit(url3); + contents()->GetMainFrame()->PrepareForCommit(); contents()->TestDidNavigate( google_rfh, 2, url3, ui::PAGE_TRANSITION_TYPED); NavigationEntry* entry3 = controller().GetLastCommittedEntry(); @@ -1120,7 +1119,7 @@ // Simulate beforeunload approval. EXPECT_TRUE(google_rfh->IsWaitingForBeforeUnloadACK()); now = base::TimeTicks::Now(); - google_rfh->PrepareForCommit(url2); + google_rfh->PrepareForCommit(); google_rfh->OnMessageReceived( FrameHostMsg_BeforeUnload_ACK(0, true, now, now)); @@ -1152,7 +1151,7 @@ const GURL url("http://www.google.com"); controller().LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(url); + contents()->GetMainFrame()->PrepareForCommit(); contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED); EXPECT_FALSE(contents()->cross_navigation_pending()); EXPECT_EQ(orig_rfh, contents()->GetMainFrame()); @@ -1171,7 +1170,7 @@ // Now simulate the onbeforeunload approval and verify the navigation is // not canceled. - orig_rfh->PrepareForCommit(url2); + orig_rfh->PrepareForCommit(); EXPECT_FALSE(orig_rfh->IsWaitingForBeforeUnloadACK()); EXPECT_TRUE(contents()->cross_navigation_pending()); } @@ -1220,7 +1219,7 @@ const GURL url("http://www.google.com"); controller().LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(url); + contents()->GetMainFrame()->PrepareForCommit(); contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED); EXPECT_FALSE(contents()->cross_navigation_pending()); EXPECT_EQ(orig_rfh, contents()->GetMainFrame()); @@ -1230,7 +1229,7 @@ controller().LoadURL( url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK()); - contents()->GetMainFrame()->PrepareForCommit(url2); + contents()->GetMainFrame()->PrepareForCommit(); EXPECT_TRUE(contents()->cross_navigation_pending()); // Simulate swap out message when the response arrives. @@ -1335,7 +1334,7 @@ const GURL url("http://www.google.com"); controller().LoadURL( url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(url); + contents()->GetMainFrame()->PrepareForCommit(); contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED); EXPECT_EQ(orig_rfh, contents()->GetMainFrame()); @@ -1353,7 +1352,7 @@ const GURL url2("http://www.yahoo.com"); controller().LoadURL( url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents()->GetMainFrame()->PrepareForCommit(url2); + contents()->GetMainFrame()->PrepareForCommit(); TestRenderFrameHost* const pending_rfh = contents()->GetPendingMainFrame(); contents()->TestDidNavigate( pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED); @@ -2700,7 +2699,10 @@ Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents->GetMainFrame()->PrepareForCommit(kUrl); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation)) { + contents->GetMainFrame()->SendBeforeUnloadACK(true); + } EXPECT_TRUE(contents->cross_navigation_pending()); EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount()); contents->CommitPendingNavigation(); @@ -2731,7 +2733,10 @@ Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - contents->GetMainFrame()->PrepareForCommit(GURL(kTestWebUIUrl)); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation)) { + contents->GetMainFrame()->SendBeforeUnloadACK(true); + } EXPECT_TRUE(contents->cross_navigation_pending()); scoped_refptr<SiteInstance> instance_webui( contents->GetPendingMainFrame()->GetSiteInstance()); @@ -2891,20 +2896,20 @@ EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing()); TestRenderFrameHost* rfh = contents()->GetMainFrame(); - AudioStreamMonitor* monitor = contents()->audio_stream_monitor(); + AudioStateProvider* audio_state = contents()->audio_state_provider(); // The audio power save blocker should not be based on having a media player // when audio stream monitoring is available. - if (AudioStreamMonitor::monitoring_available()) { + if (audio_state->IsAudioStateAvailable()) { // Send a fake audio stream monitor notification. The audio power save // blocker should be created. - monitor->set_was_recently_audible_for_testing(true); + audio_state->set_was_recently_audible_for_testing(true); contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB); EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing()); // Send another fake notification, this time when WasRecentlyAudible() will // be false. The power save blocker should be released. - monitor->set_was_recently_audible_for_testing(false); + audio_state->set_was_recently_audible_for_testing(false); contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB); EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing()); } @@ -2916,7 +2921,7 @@ 0, kPlayerAudioVideoId, true, true, false)); EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(), - !AudioStreamMonitor::monitoring_available()); + !audio_state->IsAudioStateAvailable()); // Upon hiding the video power save blocker should be released. contents()->WasHidden(); @@ -2929,7 +2934,7 @@ 0, kPlayerVideoOnlyId, true, false, false)); EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(), - !AudioStreamMonitor::monitoring_available()); + !audio_state->IsAudioStateAvailable()); // Showing the WebContents should result in the creation of the blocker. contents()->WasShown(); @@ -2941,7 +2946,7 @@ 0, kPlayerAudioOnlyId, false, true, false)); EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(), - !AudioStreamMonitor::monitoring_available()); + !audio_state->IsAudioStateAvailable()); // Start a remote player. There should be no change in the power save // blockers. @@ -2949,7 +2954,7 @@ 0, kPlayerRemoteId, true, true, true)); EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(), - !AudioStreamMonitor::monitoring_available()); + !audio_state->IsAudioStateAvailable()); // Destroy the original audio video player. Both power save blockers should // remain. @@ -2957,7 +2962,7 @@ FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId)); EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(), - !AudioStreamMonitor::monitoring_available()); + !audio_state->IsAudioStateAvailable()); // Destroy the audio only player. The video power save blocker should remain. rfh->OnMessageReceived( @@ -2984,7 +2989,7 @@ 0, kPlayerAudioVideoId, true, true, false)); EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(), - !AudioStreamMonitor::monitoring_available()); + !audio_state->IsAudioStateAvailable()); // Crash the renderer. contents()->GetMainFrame()->OnMessageReceived(
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc index f4d609b2..672e7cd 100644 --- a/content/child/blink_platform_impl.cc +++ b/content/child/blink_platform_impl.cc
@@ -13,7 +13,6 @@ #include "base/files/file_path.h" #include "base/memory/scoped_ptr.h" #include "base/memory/singleton.h" -#include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" #include "base/metrics/sparse_histogram.h" #include "base/process/process_metrics.h" @@ -417,8 +416,7 @@ shared_timer_func_(NULL), shared_timer_fire_time_(0.0), shared_timer_fire_time_was_set_while_suspended_(false), - shared_timer_suspended_(0), - current_thread_slot_(&DestroyCurrentThread) { + shared_timer_suspended_(0) { InternalInit(); } @@ -428,8 +426,7 @@ shared_timer_func_(NULL), shared_timer_fire_time_(0.0), shared_timer_fire_time_was_set_while_suspended_(false), - shared_timer_suspended_(0), - current_thread_slot_(&DestroyCurrentThread) { + shared_timer_suspended_(0) { // TODO(alexclarke): Use c++11 delegated constructors when allowed. InternalInit(); } @@ -452,6 +449,11 @@ } } +void BlinkPlatformImpl::UpdateWebThreadTLS(blink::WebThread* thread) { + DCHECK(!current_thread_slot_.Get()); + current_thread_slot_.Set(thread); +} + BlinkPlatformImpl::~BlinkPlatformImpl() { } @@ -499,23 +501,15 @@ } blink::WebThread* BlinkPlatformImpl::createThread(const char* name) { - return new WebThreadImpl(name); + WebThreadImpl* thread = new WebThreadImpl(name); + thread->TaskRunner()->PostTask( + FROM_HERE, base::Bind(&BlinkPlatformImpl::UpdateWebThreadTLS, + base::Unretained(this), thread)); + return thread; } blink::WebThread* BlinkPlatformImpl::currentThread() { - WebThreadImplForMessageLoop* thread = - static_cast<WebThreadImplForMessageLoop*>(current_thread_slot_.Get()); - if (thread) - return (thread); - - scoped_refptr<base::SingleThreadTaskRunner> task_runner = - MainTaskRunnerForCurrentThread(); - if (!task_runner.get()) - return NULL; - - thread = new WebThreadImplForMessageLoop(task_runner); - current_thread_slot_.Set(thread); - return thread; + return static_cast<blink::WebThread*>(current_thread_slot_.Get()); } void BlinkPlatformImpl::yieldCurrentThread() { @@ -1244,13 +1238,6 @@ } } -// static -void BlinkPlatformImpl::DestroyCurrentThread(void* thread) { - WebThreadImplForMessageLoop* impl = - static_cast<WebThreadImplForMessageLoop*>(thread); - delete impl; -} - WebString BlinkPlatformImpl::domCodeStringFromEnum(int dom_code) { return WebString::fromUTF8(ui::KeycodeConverter::DomCodeToCodeString( static_cast<ui::DomCode>(dom_code)));
diff --git a/content/child/blink_platform_impl.h b/content/child/blink_platform_impl.h index a21c7fd4..f4957396 100644 --- a/content/child/blink_platform_impl.h +++ b/content/child/blink_platform_impl.h
@@ -168,14 +168,13 @@ virtual int domEnumFromCodeString(const blink::WebString& codeString); private: - static void DestroyCurrentThread(void*); - void DoTimeout() { if (shared_timer_func_ && !shared_timer_suspended_) shared_timer_func_(); } void InternalInit(); + void UpdateWebThreadTLS(blink::WebThread* thread); scoped_refptr<base::SingleThreadTaskRunner> MainTaskRunnerForCurrentThread();
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc index 5df6631..f62222c7 100644 --- a/content/child/child_thread_impl.cc +++ b/content/child/child_thread_impl.cc
@@ -49,12 +49,14 @@ #include "content/child/thread_safe_sender.h" #include "content/child/websocket_dispatcher.h" #include "content/common/child_process_messages.h" +#include "content/common/mojo/channel_init.h" #include "content/public/common/content_switches.h" #include "ipc/ipc_logging.h" #include "ipc/ipc_switches.h" #include "ipc/ipc_sync_channel.h" #include "ipc/ipc_sync_message_filter.h" #include "ipc/mojo/ipc_channel_mojo.h" +#include "ipc/mojo/scoped_ipc_support.h" #if defined(OS_WIN) #include "content/common/handle_enumerator_win.h" @@ -203,6 +205,42 @@ return ChildThreadImpl::current(); } +// Mojo client channel delegate to be used in single process mode. +class ChildThreadImpl::SingleProcessChannelDelegate + : public IPC::ChannelMojo::Delegate { + public: + explicit SingleProcessChannelDelegate() : weak_factory_(this) {} + + ~SingleProcessChannelDelegate() override {} + + base::WeakPtr<IPC::ChannelMojo::Delegate> ToWeakPtr() override { + return weak_factory_.GetWeakPtr(); + } + + scoped_refptr<base::TaskRunner> GetIOTaskRunner() override { + return ChannelInit::GetSingleProcessIOTaskRunner(); + } + + void OnChannelCreated(base::WeakPtr<IPC::ChannelMojo> channel) override {} + + void DeleteSoon() { + ChannelInit::GetSingleProcessIOTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&base::DeletePointer<SingleProcessChannelDelegate>, + base::Unretained(this))); + } + + private: + base::WeakPtrFactory<IPC::ChannelMojo::Delegate> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(SingleProcessChannelDelegate); +}; + +void ChildThreadImpl::SingleProcessChannelDelegateDeleter::operator()( + SingleProcessChannelDelegate* delegate) const { + delegate->DeleteSoon(); +} + ChildThreadImpl::Options::Options() : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kProcessChannelID)), @@ -210,20 +248,42 @@ in_browser_process(false) { } -ChildThreadImpl::Options::Options(bool mojo) - : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kProcessChannelID)), - use_mojo_channel(mojo), - in_browser_process(true) { -} - -ChildThreadImpl::Options::Options(std::string name, bool mojo) - : channel_name(name), use_mojo_channel(mojo), in_browser_process(true) { -} - ChildThreadImpl::Options::~Options() { } +ChildThreadImpl::Options::Builder::Builder() { +} + +ChildThreadImpl::Options::Builder& +ChildThreadImpl::Options::Builder::InBrowserProcess(bool in_browser_process) { + options_.in_browser_process = in_browser_process; + return *this; +} + +ChildThreadImpl::Options::Builder& +ChildThreadImpl::Options::Builder::UseMojoChannel(bool use_mojo_channel) { + options_.use_mojo_channel = use_mojo_channel; + return *this; +} + +ChildThreadImpl::Options::Builder& +ChildThreadImpl::Options::Builder::WithChannelName( + const std::string& channel_name) { + options_.channel_name = channel_name; + return *this; +} + +ChildThreadImpl::Options::Builder& +ChildThreadImpl::Options::Builder::AddStartupFilter( + IPC::MessageFilter* filter) { + options_.startup_filters.push_back(filter); + return *this; +} + +ChildThreadImpl::Options ChildThreadImpl::Options::Builder::Build() { + return options_; +} + ChildThreadImpl::ChildThreadMessageRouter::ChildThreadMessageRouter( IPC::Sender* sender) : sender_(sender) {} @@ -236,7 +296,7 @@ : router_(this), in_browser_process_(false), channel_connected_factory_(this) { - Init(Options()); + Init(Options::Builder().Build()); } ChildThreadImpl::ChildThreadImpl(const Options& options) @@ -250,8 +310,20 @@ bool create_pipe_now = true; if (use_mojo_channel) { VLOG(1) << "Mojo is enabled on child"; - channel_->Init(IPC::ChannelMojo::CreateClientFactory(channel_name_), - create_pipe_now); + scoped_refptr<base::TaskRunner> io_task_runner = + ChannelInit::GetSingleProcessIOTaskRunner(); + if (io_task_runner) { + single_process_channel_delegate_.reset(new SingleProcessChannelDelegate); + } else { + io_task_runner = ChildProcess::current()->io_message_loop_proxy(); + } + DCHECK(io_task_runner); + ipc_support_.reset(new IPC::ScopedIPCSupport(io_task_runner)); + channel_->Init( + IPC::ChannelMojo::CreateClientFactory( + single_process_channel_delegate_.get(), + channel_name_), + create_pipe_now); return; }
diff --git a/content/child/child_thread_impl.h b/content/child/child_thread_impl.h index 4016861..03727d6 100644 --- a/content/child/child_thread_impl.h +++ b/content/child/child_thread_impl.h
@@ -29,6 +29,7 @@ namespace IPC { class MessageFilter; +class ScopedIPCSupport; class SyncChannel; class SyncMessageFilter; } // namespace IPC @@ -61,17 +62,7 @@ : public IPC::Listener, virtual public ChildThread { public: - struct CONTENT_EXPORT Options { - Options(); - explicit Options(bool mojo); - Options(std::string name, bool mojo); - ~Options(); - - std::string channel_name; - bool use_mojo_channel; - bool in_browser_process; - std::vector<IPC::MessageFilter*> startup_filters; - }; + struct CONTENT_EXPORT Options; // Creates the thread. ChildThreadImpl(); @@ -239,6 +230,15 @@ void EnsureConnected(); + class SingleProcessChannelDelegate; + class SingleProcessChannelDelegateDeleter { + public: + void operator()(SingleProcessChannelDelegate* delegate) const; + }; + + scoped_ptr<IPC::ScopedIPCSupport> ipc_support_; + scoped_ptr<SingleProcessChannelDelegate, SingleProcessChannelDelegateDeleter> + single_process_channel_delegate_; scoped_ptr<MojoApplication> mojo_application_; std::string channel_name_; @@ -305,6 +305,37 @@ DISALLOW_COPY_AND_ASSIGN(ChildThreadImpl); }; +struct ChildThreadImpl::Options { + ~Options(); + + class Builder; + + std::string channel_name; + bool use_mojo_channel; + bool in_browser_process; + std::vector<IPC::MessageFilter*> startup_filters; + + private: + Options(); +}; + +class ChildThreadImpl::Options::Builder { + public: + Builder(); + + Builder& InBrowserProcess(bool in_browser_process); + Builder& UseMojoChannel(bool use_mojo_channel); + Builder& WithChannelName(const std::string& channel_name); + Builder& AddStartupFilter(IPC::MessageFilter* filter); + + Options Build(); + + private: + struct Options options_; + + DISALLOW_COPY_AND_ASSIGN(Builder); +}; + } // namespace content #endif // CONTENT_CHILD_CHILD_THREAD_IMPL_H_
diff --git a/content/child/mojo/mojo_application.cc b/content/child/mojo/mojo_application.cc index 34fc314..f896dc6 100644 --- a/content/child/mojo/mojo_application.cc +++ b/content/child/mojo/mojo_application.cc
@@ -6,6 +6,7 @@ #include "content/child/child_process.h" #include "content/common/application_setup.mojom.h" +#include "content/common/mojo/channel_init.h" #include "content/common/mojo/mojo_messages.h" #include "ipc/ipc_message.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h" @@ -34,9 +35,15 @@ #elif defined(OS_WIN) base::PlatformFile handle = file; #endif + scoped_refptr<base::TaskRunner> io_task_runner = + ChannelInit::GetSingleProcessIOTaskRunner(); + if (!io_task_runner) { + io_task_runner = ChildProcess::current()->io_message_loop_proxy(); + } + DCHECK(io_task_runner); + mojo::ScopedMessagePipeHandle message_pipe = - channel_init_.Init(handle, - ChildProcess::current()->io_message_loop_proxy()); + channel_init_.Init(handle, io_task_runner); DCHECK(message_pipe.is_valid()); ApplicationSetupPtr application_setup;
diff --git a/content/child/mojo/mojo_application.h b/content/child/mojo/mojo_application.h index 481c072..5b89ddba 100644 --- a/content/child/mojo/mojo_application.h +++ b/content/child/mojo/mojo_application.h
@@ -5,9 +5,9 @@ #ifndef CONTENT_CHILD_MOJO_MOJO_APPLICATION_H_ #define CONTENT_CHILD_MOJO_MOJO_APPLICATION_H_ +#include "content/common/mojo/channel_init.h" #include "content/common/mojo/service_registry_impl.h" #include "ipc/ipc_platform_file.h" -#include "third_party/mojo/src/mojo/edk/embedder/channel_init.h" namespace IPC { class Message; @@ -31,7 +31,7 @@ private: void OnActivate(const IPC::PlatformFileForTransit& file); - mojo::embedder::ChannelInit channel_init_; + ChannelInit channel_init_; ServiceRegistryImpl service_registry_;
diff --git a/content/child/webcrypto/openssl/hmac_openssl.cc b/content/child/webcrypto/openssl/hmac_openssl.cc index 0872390d..69b55bf 100644 --- a/content/child/webcrypto/openssl/hmac_openssl.cc +++ b/content/child/webcrypto/openssl/hmac_openssl.cc
@@ -38,22 +38,14 @@ return Status::ErrorUnsupported(); unsigned int hmac_expected_length = EVP_MD_size(digest_algorithm); - // OpenSSL wierdness here. - // First, HMAC() needs a void* for the key data, so make one up front as a - // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key, - // which will result if the raw_key vector is empty; an entirely valid - // case. Handle this specific case by pointing to a fresh array. - const unsigned char null_key[] = {0}; - const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key; - buffer->resize(hmac_expected_length); crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result( vector_as_array(buffer), hmac_expected_length); unsigned int hmac_actual_length; - unsigned char* const success = - HMAC(digest_algorithm, raw_key_voidp, raw_key.size(), data.bytes(), - data.byte_length(), hmac_result.safe_buffer(), &hmac_actual_length); + unsigned char* const success = HMAC( + digest_algorithm, vector_as_array(&raw_key), raw_key.size(), data.bytes(), + data.byte_length(), hmac_result.safe_buffer(), &hmac_actual_length); if (!success || hmac_actual_length != hmac_expected_length) return Status::OperationError();
diff --git a/content/child/webthread_impl.cc b/content/child/webthread_impl.cc index 8a1d7cdd..572e589 100644 --- a/content/child/webthread_impl.cc +++ b/content/child/webthread_impl.cc
@@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/bind_helpers.h" -#include "base/message_loop/message_loop.h" #include "base/pending_task.h" #include "base/threading/platform_thread.h" #include "third_party/WebKit/public/platform/WebTraceLocation.h" @@ -119,12 +118,14 @@ void WebThreadBase::enterRunLoop() { CHECK(isCurrentThread()); + CHECK(MessageLoop()); CHECK(!MessageLoop()->is_running()); // We don't support nesting. MessageLoop()->Run(); } void WebThreadBase::exitRunLoop() { CHECK(isCurrentThread()); + CHECK(MessageLoop()); CHECK(MessageLoop()->is_running()); MessageLoop()->Quit(); } @@ -147,33 +148,11 @@ } base::MessageLoop* WebThreadImpl::MessageLoop() const { - return thread_->message_loop(); + return nullptr; } base::SingleThreadTaskRunner* WebThreadImpl::TaskRunner() const { return thread_->message_loop_proxy().get(); } -WebThreadImplForMessageLoop::WebThreadImplForMessageLoop( - scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner) - : owning_thread_task_runner_(owning_thread_task_runner), - thread_id_(base::PlatformThread::CurrentId()) { -} - -blink::PlatformThreadId WebThreadImplForMessageLoop::threadId() const { - return thread_id_; -} - -WebThreadImplForMessageLoop::~WebThreadImplForMessageLoop() { -} - -base::MessageLoop* WebThreadImplForMessageLoop::MessageLoop() const { - DCHECK(isCurrentThread()); - return base::MessageLoop::current(); -} - -base::SingleThreadTaskRunner* WebThreadImplForMessageLoop::TaskRunner() const { - return owning_thread_task_runner_.get(); -} - } // namespace content
diff --git a/content/child/webthread_impl.h b/content/child/webthread_impl.h index edd3956..c502952 100644 --- a/content/child/webthread_impl.h +++ b/content/child/webthread_impl.h
@@ -80,25 +80,6 @@ scoped_ptr<base::Thread> thread_; }; -class WebThreadImplForMessageLoop : public WebThreadBase { - public: - CONTENT_EXPORT explicit WebThreadImplForMessageLoop( - scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner); - CONTENT_EXPORT virtual ~WebThreadImplForMessageLoop(); - - // blink::WebThread implementation. - blink::PlatformThreadId threadId() const override; - - // WebThreadBase implementation. - base::MessageLoop* MessageLoop() const override; - - private: - base::SingleThreadTaskRunner* TaskRunner() const override; - - scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner_; - blink::PlatformThreadId thread_id_; -}; - } // namespace content #endif // CONTENT_CHILD_WEBTHREAD_IMPL_H_
diff --git a/content/common/DEPS b/content/common/DEPS index 1e63887..64cd684 100644 --- a/content/common/DEPS +++ b/content/common/DEPS
@@ -20,8 +20,6 @@ "+third_party/WebKit/public/platform/WebGeofencingEventType.h", "+third_party/WebKit/public/platform/WebGraphicsContext3D.h", "+third_party/WebKit/public/platform/WebHTTPBody.h", - "+third_party/WebKit/public/platform/WebIDBCursor.h", - "+third_party/WebKit/public/platform/WebIDBDatabase.h", "+third_party/WebKit/public/platform/WebIDBTypes.h", "+third_party/WebKit/public/platform/WebLockOrientationError.h", "+third_party/WebKit/public/platform/WebPageVisibilityState.h",
diff --git a/content/common/cc_messages.h b/content/common/cc_messages.h index 29b7480..78382603 100644 --- a/content/common/cc_messages.h +++ b/content/common/cc_messages.h
@@ -158,6 +158,7 @@ IPC_STRUCT_TRAITS_BEGIN(cc::CheckerboardDrawQuad) IPC_STRUCT_TRAITS_PARENT(cc::DrawQuad) IPC_STRUCT_TRAITS_MEMBER(color) + IPC_STRUCT_TRAITS_MEMBER(scale) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(cc::DebugBorderDrawQuad)
diff --git a/content/common/cc_messages_unittest.cc b/content/common/cc_messages_unittest.cc index 8bcb1e7..1807f96 100644 --- a/content/common/cc_messages_unittest.cc +++ b/content/common/cc_messages_unittest.cc
@@ -129,6 +129,7 @@ void Compare(const CheckerboardDrawQuad* a, const CheckerboardDrawQuad* b) { EXPECT_EQ(a->color, b->color); + EXPECT_EQ(a->scale, b->scale); } void Compare(const DebugBorderDrawQuad* a, const DebugBorderDrawQuad* b) { @@ -316,12 +317,10 @@ CheckerboardDrawQuad* checkerboard_in = pass_in->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); - checkerboard_in->SetAll(shared_state1_in, - arbitrary_rect1, + checkerboard_in->SetAll(shared_state1_in, arbitrary_rect1, arbitrary_rect2_inside_rect1, - arbitrary_rect1_inside_rect1, - arbitrary_bool1, - arbitrary_color); + arbitrary_rect1_inside_rect1, arbitrary_bool1, + arbitrary_color, arbitrary_float1); pass_cmp->CopyFromAndAppendDrawQuad(checkerboard_in, checkerboard_in->shared_quad_state); @@ -567,12 +566,8 @@ CheckerboardDrawQuad* quad1 = pass_in->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); - quad1->SetAll(shared_state1_in, - gfx::Rect(10, 10), - gfx::Rect(10, 10), - gfx::Rect(10, 10), - false, - SK_ColorRED); + quad1->SetAll(shared_state1_in, gfx::Rect(10, 10), gfx::Rect(10, 10), + gfx::Rect(10, 10), false, SK_ColorRED, 1.f); // The second and third SharedQuadStates are not used. SharedQuadState* shared_state2_in = pass_in->CreateAndAppendSharedQuadState(); @@ -608,12 +603,8 @@ CheckerboardDrawQuad* quad2 = pass_in->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); - quad2->SetAll(shared_state4_in, - gfx::Rect(10, 10), - gfx::Rect(10, 10), - gfx::Rect(10, 10), - false, - SK_ColorRED); + quad2->SetAll(shared_state4_in, gfx::Rect(10, 10), gfx::Rect(10, 10), + gfx::Rect(10, 10), false, SK_ColorRED, 1.f); // The fifth is not used again. SharedQuadState* shared_state5_in = pass_in->CreateAndAppendSharedQuadState();
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h index a9ca4b86..c3b5b62 100644 --- a/content/common/frame_messages.h +++ b/content/common/frame_messages.h
@@ -212,6 +212,8 @@ IPC_STRUCT_TRAITS_MEMBER(allow_download) IPC_STRUCT_TRAITS_MEMBER(ui_timestamp) IPC_STRUCT_TRAITS_MEMBER(report_type) + IPC_STRUCT_TRAITS_MEMBER(base_url_for_data_url) + IPC_STRUCT_TRAITS_MEMBER(history_url_for_data_url) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(content::BeginNavigationParams) @@ -284,14 +286,6 @@ // succesful when the navigation commits. IPC_STRUCT_MEMBER(bool, should_clear_history_list) - // Base URL for use in WebKit's SubstituteData. - // Is only used with data: URLs. - IPC_STRUCT_MEMBER(GURL, base_url_for_data_url) - - // History URL for use in WebKit's SubstituteData. - // Is only used with data: URLs. - IPC_STRUCT_MEMBER(GURL, history_url_for_data_url) - // Any redirect URLs that occurred before |url|. Useful for cross-process // navigations; defaults to empty. IPC_STRUCT_MEMBER(std::vector<GURL>, redirects)
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.cc b/content/common/gpu/client/command_buffer_proxy_impl.cc index 75cffa2..8241812 100644 --- a/content/common/gpu/client/command_buffer_proxy_impl.cc +++ b/content/common/gpu/client/command_buffer_proxy_impl.cc
@@ -371,6 +371,8 @@ channel_->ShareGpuMemoryBufferToGpuProcess(gpu_memory_buffer->GetHandle(), &requires_sync_point); + DCHECK(gpu::ImageFactory::IsImageSizeValidForGpuMemoryBufferFormat( + gfx::Size(width, height), gpu_memory_buffer->GetFormat())); DCHECK(gpu::ImageFactory::IsImageFormatCompatibleWithGpuMemoryBufferFormat( internalformat, gpu_memory_buffer->GetFormat())); if (!Send(new GpuCommandBufferMsg_CreateImage(route_id_,
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl.cc b/content/common/gpu/client/gpu_memory_buffer_impl.cc index e2a48be..0c0426f 100644 --- a/content/common/gpu/client/gpu_memory_buffer_impl.cc +++ b/content/common/gpu/client/gpu_memory_buffer_impl.cc
@@ -8,7 +8,6 @@ #include "base/numerics/safe_math.h" #include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h" #include "ui/gl/gl_bindings.h" -#include "ui/gl/gl_image_memory.h" #if defined(OS_MACOSX) #include "content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h" @@ -34,7 +33,6 @@ callback_(callback), mapped_(false), destruction_sync_point_(0) { - DCHECK(gfx::GLImageMemory::ValidSize(size, format)); } GpuMemoryBufferImpl::~GpuMemoryBufferImpl() {
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc b/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc index ade8e1a..8daff2a 100644 --- a/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc +++ b/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc
@@ -24,6 +24,8 @@ scoped_ptr<base::SharedMemory> shared_memory) : GpuMemoryBufferImpl(id, size, format, callback), shared_memory_(shared_memory.Pass()) { + DCHECK(IsFormatSupported(format)); + DCHECK(IsSizeValidForFormat(size, format)); } GpuMemoryBufferImplSharedMemory::~GpuMemoryBufferImplSharedMemory() { @@ -131,6 +133,29 @@ return false; } +// static +bool GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat( + const gfx::Size& size, + Format format) { + switch (format) { + case ATC: + case ATCIA: + case DXT1: + case DXT5: + case ETC1: + // Compressed images must have a width and height that's evenly divisible + // by the block size. + return size.width() % 4 == 0 && size.height() % 4 == 0; + case RGBA_8888: + case BGRA_8888: + case RGBX_8888: + return true; + } + + NOTREACHED(); + return false; +} + void* GpuMemoryBufferImplSharedMemory::Map() { DCHECK(!mapped_); mapped_ = true;
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h b/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h index e76e317..022c320e 100644 --- a/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h +++ b/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h
@@ -31,6 +31,7 @@ const DestructionCallback& callback); static bool IsFormatSupported(Format format); + static bool IsSizeValidForFormat(const gfx::Size& size, Format format); // Overridden from gfx::GpuMemoryBuffer: void* Map() override;
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc index c108a99..e14cf98 100644 --- a/content/common/gpu/gpu_command_buffer_stub.cc +++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -27,6 +27,7 @@ #include "gpu/command_buffer/common/mailbox.h" #include "gpu/command_buffer/service/gl_context_virtual.h" #include "gpu/command_buffer/service/gl_state_restorer_impl.h" +#include "gpu/command_buffer/service/image_factory.h" #include "gpu/command_buffer/service/image_manager.h" #include "gpu/command_buffer/service/logger.h" #include "gpu/command_buffer/service/mailbox_manager.h" @@ -140,29 +141,6 @@ return new DevToolsChannelData(res.release()); } -bool IsSupportedImageFormat(const gpu::Capabilities& capabilities, - gfx::GpuMemoryBuffer::Format format) { - switch (format) { - case gfx::GpuMemoryBuffer::ATC: - case gfx::GpuMemoryBuffer::ATCIA: - return capabilities.texture_format_atc; - case gfx::GpuMemoryBuffer::BGRA_8888: - return capabilities.texture_format_bgra8888; - case gfx::GpuMemoryBuffer::DXT1: - return capabilities.texture_format_dxt1; - case gfx::GpuMemoryBuffer::DXT5: - return capabilities.texture_format_dxt5; - case gfx::GpuMemoryBuffer::ETC1: - return capabilities.texture_format_etc1; - case gfx::GpuMemoryBuffer::RGBA_8888: - case gfx::GpuMemoryBuffer::RGBX_8888: - return true; - } - - NOTREACHED(); - return false; -} - } // namespace GpuCommandBufferStub::GpuCommandBufferStub( @@ -979,8 +957,21 @@ return; } - if (!IsSupportedImageFormat(decoder_->GetCapabilities(), format)) { - LOG(ERROR) << "Image format is not supported."; + if (!gpu::ImageFactory::IsGpuMemoryBufferFormatSupported( + format, decoder_->GetCapabilities())) { + LOG(ERROR) << "Format is not supported."; + return; + } + + if (!gpu::ImageFactory::IsImageSizeValidForGpuMemoryBufferFormat(size, + format)) { + LOG(ERROR) << "Invalid image size for format."; + return; + } + + if (!gpu::ImageFactory::IsImageFormatCompatibleWithGpuMemoryBufferFormat( + internalformat, format)) { + LOG(ERROR) << "Incompatible image format."; return; }
diff --git a/content/common/gpu/image_transport_surface.cc b/content/common/gpu/image_transport_surface.cc index 02fbdfa4..b6367dd4 100644 --- a/content/common/gpu/image_transport_surface.cc +++ b/content/common/gpu/image_transport_surface.cc
@@ -191,8 +191,12 @@ // GetVsyncValues before SwapBuffers to work around Mali driver bug: // crbug.com/223558. SendVSyncUpdateIfAvailable(); - for (auto& latency : latency_info_) - latency.AddLatencyNumber(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0); + + base::TimeTicks swap_time = base::TimeTicks::Now(); + for (auto& latency : latency_info_) { + latency.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1); + } // We use WeakPtr here to avoid manual management of life time of an instance // of this class. Callback will not be called once the instance of this class @@ -206,6 +210,13 @@ bool PassThroughImageTransportSurface::PostSubBuffer( int x, int y, int width, int height) { SendVSyncUpdateIfAvailable(); + + base::TimeTicks swap_time = base::TimeTicks::Now(); + for (auto& latency : latency_info_) { + latency.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1); + } + // We use WeakPtr here to avoid manual management of life time of an instance // of this class. Callback will not be called once the instance of this class // is destroyed. However, this also means that the callback can be run on @@ -216,9 +227,11 @@ } void PassThroughImageTransportSurface::SwapBuffersCallBack() { - for (size_t i = 0; i < latency_info_.size(); i++) { - latency_info_[i].AddLatencyNumber( - ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0); + base::TimeTicks swap_ack_time = base::TimeTicks::Now(); + for (auto& latency : latency_info_) { + latency.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0, + swap_ack_time, 1); } helper_->stub()->SendSwapBuffersCompleted(latency_info_);
diff --git a/content/common/gpu/image_transport_surface_linux.cc b/content/common/gpu/image_transport_surface_linux.cc index b648b19..db36efe 100644 --- a/content/common/gpu/image_transport_surface_linux.cc +++ b/content/common/gpu/image_transport_surface_linux.cc
@@ -13,9 +13,13 @@ const gfx::GLSurfaceHandle& handle) { DCHECK(handle.handle); DCHECK(handle.transport_type == gfx::NATIVE_DIRECT); - scoped_refptr<gfx::GLSurface> surface = - gfx::GLSurface::CreateViewGLSurface(handle.handle); - if (!surface.get()) + scoped_refptr<gfx::GLSurface> surface; +#if defined(USE_OZONE) + surface = gfx::GLSurface::CreateSurfacelessViewGLSurface(handle.handle); +#endif + if (!surface) + surface = gfx::GLSurface::CreateViewGLSurface(handle.handle); + if (!surface) return surface; return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface( manager, stub, surface.get()));
diff --git a/content/common/gpu/media/generic_v4l2_device.h b/content/common/gpu/media/generic_v4l2_device.h index 1211a5b6..94d656c65 100644 --- a/content/common/gpu/media/generic_v4l2_device.h +++ b/content/common/gpu/media/generic_v4l2_device.h
@@ -35,7 +35,7 @@ gfx::Size frame_buffer_size, unsigned int buffer_index, uint32_t v4l2_pixfmt, - size_t num_v4l2_planes); + size_t num_v4l2_planes) override; EGLBoolean DestroyEGLImage(EGLDisplay egl_display, EGLImageKHR egl_image) override; GLenum GetTextureTarget() override;
diff --git a/content/common/gpu/media/h264_decoder.cc b/content/common/gpu/media/h264_decoder.cc index 3ad82f0..02ba468c 100644 --- a/content/common/gpu/media/h264_decoder.cc +++ b/content/common/gpu/media/h264_decoder.cc
@@ -1269,6 +1269,10 @@ } } +gfx::Size H264Decoder::GetPicSize() const { + return pic_size_; +} + size_t H264Decoder::GetRequiredNumOfPictures() const { return dpb_.max_num_pics() + kPicsInPipeline; }
diff --git a/content/common/gpu/media/h264_decoder.h b/content/common/gpu/media/h264_decoder.h index 3ec83f56..32bedaa 100644 --- a/content/common/gpu/media/h264_decoder.h +++ b/content/common/gpu/media/h264_decoder.h
@@ -105,7 +105,7 @@ void Reset() override; void SetStream(const uint8_t* ptr, size_t size) override; DecodeResult Decode() override WARN_UNUSED_RESULT; - gfx::Size GetPicSize() const override { return pic_size_; } + gfx::Size GetPicSize() const override; size_t GetRequiredNumOfPictures() const override; private:
diff --git a/content/common/gpu/media/rendering_helper.cc b/content/common/gpu/media/rendering_helper.cc index cf83611..3ceea1f 100644 --- a/content/common/gpu/media/rendering_helper.cc +++ b/content/common/gpu/media/rendering_helper.cc
@@ -314,6 +314,9 @@ message_loop_ = base::MessageLoop::current(); gl_surface_ = gfx::GLSurface::CreateViewGLSurface(window_); +#if defined(USE_OZONE) + gl_surface_->Resize(platform_window_delegate_->GetSize()); +#endif // defined(USE_OZONE) screen_size_ = gl_surface_->GetSize(); gl_context_ = gfx::GLContext::CreateGLContext( @@ -364,7 +367,8 @@ CHECK(fb_status == GL_FRAMEBUFFER_COMPLETE) << fb_status; glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); - glBindFramebufferEXT(GL_FRAMEBUFFER, 0); + glBindFramebufferEXT(GL_FRAMEBUFFER, + gl_surface_->GetBackingFrameBufferObject()); } // These vertices and texture coords. map (0,0) in the texture to the @@ -504,6 +508,7 @@ glDeleteFramebuffersEXT(1, &thumbnails_fbo_id_); } + gl_surface_->Destroy(); gl_context_->ReleaseCurrent(gl_surface_.get()); gl_context_ = NULL; gl_surface_ = NULL; @@ -570,7 +575,8 @@ glBindFramebufferEXT(GL_FRAMEBUFFER, thumbnails_fbo_id_); GLSetViewPort(area); RenderTexture(texture_target, texture_id); - glBindFramebufferEXT(GL_FRAMEBUFFER, 0); + glBindFramebufferEXT(GL_FRAMEBUFFER, + gl_surface_->GetBackingFrameBufferObject()); // Need to flush the GL commands before we return the tnumbnail texture to // the decoder. @@ -661,7 +667,8 @@ GL_RGBA, GL_UNSIGNED_BYTE, &rgba[0]); - glBindFramebufferEXT(GL_FRAMEBUFFER, 0); + glBindFramebufferEXT(GL_FRAMEBUFFER, + gl_surface_->GetBackingFrameBufferObject()); rgb->resize(num_pixels * 3); // Drop the alpha channel, but check as we go that it is all 0xff. bool solid = true; @@ -698,7 +705,13 @@ static_cast<base::WaitableEvent*>(NULL))); } - glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1); + int tex_flip = 1; +#if defined(USE_OZONE) + // Ozone surfaceless renders flipped from normal GL, so there's no need to + // do an extra flip. + tex_flip = 0; +#endif // defined(USE_OZONE) + glUniform1i(glGetUniformLocation(program_, "tex_flip"), tex_flip); // Frames that will be returned to the client (via the no_longer_needed_cb) // after this vector falls out of scope at the end of this method. We need
diff --git a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc index ac567b7..3fcba61 100644 --- a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc +++ b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
@@ -240,7 +240,7 @@ : public H264Decoder::H264Accelerator { public: V4L2H264Accelerator(V4L2SliceVideoDecodeAccelerator* v4l2_dec); - virtual ~V4L2H264Accelerator() override; + ~V4L2H264Accelerator() override; // H264Decoder::H264Accelerator implementation. scoped_refptr<H264Picture> CreateH264Picture() override; @@ -322,7 +322,6 @@ public: V4L2H264Picture(const scoped_refptr< V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>& dec_surface); - virtual ~V4L2H264Picture() override; V4L2H264Picture* AsV4L2H264Picture() override { return this; } scoped_refptr<V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface> @@ -331,6 +330,8 @@ } private: + ~V4L2H264Picture() override; + scoped_refptr<V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface> dec_surface_; @@ -349,7 +350,6 @@ public: V4L2VP8Picture(const scoped_refptr< V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>& dec_surface); - virtual ~V4L2VP8Picture() override; V4L2VP8Picture* AsV4L2VP8Picture() override { return this; } scoped_refptr<V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface> @@ -358,6 +358,8 @@ } private: + ~V4L2VP8Picture() override; + scoped_refptr<V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface> dec_surface_;
diff --git a/content/common/gpu/media/v4l2_video_decode_accelerator.cc b/content/common/gpu/media/v4l2_video_decode_accelerator.cc index 019446b..7667f8b 100644 --- a/content/common/gpu/media/v4l2_video_decode_accelerator.cc +++ b/content/common/gpu/media/v4l2_video_decode_accelerator.cc
@@ -21,6 +21,7 @@ #include "content/common/gpu/media/v4l2_video_decode_accelerator.h" #include "media/base/media_switches.h" #include "media/filters/h264_parser.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gl/scoped_binders.h" #define NOTIFY_ERROR(x) \ @@ -339,7 +340,7 @@ // thread is waiting on pictures_assigned_. DCHECK(free_output_buffers_.empty()); for (size_t i = 0; i < output_buffer_map_.size(); ++i) { - DCHECK(buffers[i].size() == frame_buffer_size_); + DCHECK(buffers[i].size() == coded_size_); OutputRecord& output_record = output_buffer_map_[i]; DCHECK(!output_record.at_device); @@ -352,7 +353,7 @@ EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, egl_context_, buffers[i].texture_id(), - frame_buffer_size_, + coded_size_, i, output_format_fourcc_, output_planes_count_); @@ -729,8 +730,9 @@ // Check and see if we have format info yet. struct v4l2_format format; + gfx::Size visible_size; bool again = false; - if (!GetFormatInfo(&format, &again)) + if (!GetFormatInfo(&format, &visible_size, &again)) return false; if (again) { @@ -743,7 +745,7 @@ if (decoder_state_ == kInitialized) { DVLOG(3) << "DecodeBufferInitial(): running initialization"; // Success! Setup our parameters. - if (!CreateBuffersForFormat(format)) + if (!CreateBuffersForFormat(format, visible_size)) return false; // We expect to process the initial buffer once during stream init to @@ -1085,7 +1087,7 @@ << " as picture_id=" << output_record.picture_id; const media::Picture& picture = media::Picture(output_record.picture_id, dqbuf.timestamp.tv_sec, - gfx::Rect(frame_buffer_size_), false); + gfx::Rect(visible_size_), false); pending_picture_ready_.push( PictureRecord(output_record.cleared, picture)); SendPictureReady(); @@ -1533,14 +1535,15 @@ struct v4l2_format format; bool again; - bool ret = GetFormatInfo(&format, &again); + gfx::Size visible_size; + bool ret = GetFormatInfo(&format, &visible_size, &again); if (!ret || again) { LOG(ERROR) << "Couldn't get format information after resolution change"; NOTIFY_ERROR(PLATFORM_FAILURE); return; } - if (!CreateBuffersForFormat(format)) { + if (!CreateBuffersForFormat(format, visible_size)) { LOG(ERROR) << "Couldn't reallocate buffers after resolution change"; NOTIFY_ERROR(PLATFORM_FAILURE); return; @@ -1615,7 +1618,8 @@ } bool V4L2VideoDecodeAccelerator::GetFormatInfo(struct v4l2_format* format, - bool* again) { + gfx::Size* visible_size, + bool* again) { DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); *again = false; @@ -1639,17 +1643,23 @@ return false; } + gfx::Size coded_size(format->fmt.pix_mp.width, format->fmt.pix_mp.height); + if (visible_size != nullptr) + *visible_size = GetVisibleSize(coded_size); + return true; } bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat( - const struct v4l2_format& format) { + const struct v4l2_format& format, + const gfx::Size& visible_size) { DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); output_planes_count_ = format.fmt.pix_mp.num_planes; - frame_buffer_size_.SetSize( - format.fmt.pix_mp.width, format.fmt.pix_mp.height); + coded_size_.SetSize(format.fmt.pix_mp.width, format.fmt.pix_mp.height); + visible_size_ = visible_size; DVLOG(3) << "CreateBuffersForFormat(): new resolution: " - << frame_buffer_size_.ToString(); + << coded_size_.ToString() << ", visible size: " + << visible_size_.ToString(); if (!CreateOutputBuffers()) return false; @@ -1657,6 +1667,42 @@ return true; } +gfx::Size V4L2VideoDecodeAccelerator::GetVisibleSize( + const gfx::Size& coded_size) { + DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); + + struct v4l2_crop crop_arg; + memset(&crop_arg, 0, sizeof(crop_arg)); + crop_arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + if (device_->Ioctl(VIDIOC_G_CROP, &crop_arg) != 0) { + PLOG(ERROR) << "GetVisibleSize(): ioctl() VIDIOC_G_CROP failed"; + return coded_size; + } + + gfx::Rect rect(crop_arg.c.left, crop_arg.c.top, crop_arg.c.width, + crop_arg.c.height); + DVLOG(3) << "visible rectangle is " << rect.ToString(); + if (!gfx::Rect(coded_size).Contains(rect)) { + DLOG(ERROR) << "visible rectangle " << rect.ToString() + << " is not inside coded size " << coded_size.ToString(); + return coded_size; + } + if (rect.IsEmpty()) { + DLOG(ERROR) << "visible size is empty"; + return coded_size; + } + + // Chrome assume picture frame is coded at (0, 0). + if (!rect.origin().IsOrigin()) { + DLOG(ERROR) << "Unexpected visible rectangle " << rect.ToString() + << ", top-left is not origin"; + return coded_size; + } + + return rect.size(); +} + bool V4L2VideoDecodeAccelerator::CreateInputBuffers() { DVLOG(3) << "CreateInputBuffers()"; // We always run this as we prepare to initialize. @@ -1786,13 +1832,12 @@ DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): " << "buffer_count=" << output_buffer_map_.size() - << ", width=" << frame_buffer_size_.width() - << ", height=" << frame_buffer_size_.height(); + << ", coded_size=" << coded_size_.ToString(); child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(&Client::ProvidePictureBuffers, client_, output_buffer_map_.size(), - frame_buffer_size_, + coded_size_, device_->GetTextureTarget())); // Wait for the client to call AssignPictureBuffers() on the Child thread. @@ -1966,14 +2011,14 @@ } struct v4l2_format format; bool again = false; - bool ret = GetFormatInfo(&format, &again); + bool ret = GetFormatInfo(&format, nullptr, &again); if (!ret || again) { DVLOG(3) << "IsResolutionChangeNecessary(): GetFormatInfo() failed"; return false; } - gfx::Size new_size(base::checked_cast<int>(format.fmt.pix_mp.width), - base::checked_cast<int>(format.fmt.pix_mp.height)); - if (frame_buffer_size_ != new_size) { + gfx::Size new_coded_size(base::checked_cast<int>(format.fmt.pix_mp.width), + base::checked_cast<int>(format.fmt.pix_mp.height)); + if (coded_size_ != new_coded_size) { DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; return true; }
diff --git a/content/common/gpu/media/v4l2_video_decode_accelerator.h b/content/common/gpu/media/v4l2_video_decode_accelerator.h index 09143946..fbb973e0 100644 --- a/content/common/gpu/media/v4l2_video_decode_accelerator.h +++ b/content/common/gpu/media/v4l2_video_decode_accelerator.h
@@ -242,11 +242,19 @@ void StartResolutionChangeIfNeeded(); void FinishResolutionChange(); - // Try to get output format, detected after parsing the beginning - // of the stream. Sets |again| to true if more parsing is needed. - bool GetFormatInfo(struct v4l2_format* format, bool* again); - // Create output buffers for the given |format|. - bool CreateBuffersForFormat(const struct v4l2_format& format); + // Try to get output format and visible size, detected after parsing the + // beginning of the stream. Sets |again| to true if more parsing is needed. + // |visible_size| could be nullptr and ignored. + bool GetFormatInfo(struct v4l2_format* format, + gfx::Size* visible_size, + bool* again); + // Create output buffers for the given |format| and |visible_size|. + bool CreateBuffersForFormat(const struct v4l2_format& format, + const gfx::Size& visible_size); + + // Try to get |visible_size|. Return visible size, or, if querying it is not + // supported or produces invalid size, return |coded_size| instead. + gfx::Size GetVisibleSize(const gfx::Size& coded_size); // // Device tasks, to be run on device_poll_thread_. @@ -415,8 +423,11 @@ // to avoid races with potential Reset requests. base::WaitableEvent pictures_assigned_; - // Output picture size. - gfx::Size frame_buffer_size_; + // Output picture coded size. + gfx::Size coded_size_; + + // Output picture visible size. + gfx::Size visible_size_; // // The device polling thread handles notifications of V4L2 device changes.
diff --git a/content/common/gpu/media/video_decode_accelerator_unittest.cc b/content/common/gpu/media/video_decode_accelerator_unittest.cc index f88b2c5..be59e0d35 100644 --- a/content/common/gpu/media/video_decode_accelerator_unittest.cc +++ b/content/common/gpu/media/video_decode_accelerator_unittest.cc
@@ -231,17 +231,23 @@ done.Wait(); #if defined(USE_OZONE) + gpu_helper_.reset(new ui::OzoneGpuTestHelper()); // Need to initialize after the rendering side since the rendering side // initializes the "GPU" parts of Ozone. // // This also needs to be done in the test environment since this shouldn't // be initialized multiple times for the same Ozone platform. - gpu_helper_.Initialize(base::ThreadTaskRunnerHandle::Get(), - GetRenderingTaskRunner()); + gpu_helper_->Initialize(base::ThreadTaskRunnerHandle::Get(), + GetRenderingTaskRunner()); #endif } - void TearDown() override { rendering_thread_.Stop(); } + void TearDown() override { +#if defined(USE_OZONE) + gpu_helper_.reset(); +#endif + rendering_thread_.Stop(); + } scoped_refptr<base::SingleThreadTaskRunner> GetRenderingTaskRunner() const { return rendering_thread_.task_runner(); @@ -250,7 +256,7 @@ private: base::Thread rendering_thread_; #if defined(USE_OZONE) - ui::OzoneGpuTestHelper gpu_helper_; + scoped_ptr<ui::OzoneGpuTestHelper> gpu_helper_; #endif DISALLOW_COPY_AND_ASSIGN(VideoDecodeAcceleratorTestEnvironment);
diff --git a/content/common/gpu/media/vp8_decoder.cc b/content/common/gpu/media/vp8_decoder.cc index 258372e5..eed6b59a 100644 --- a/content/common/gpu/media/vp8_decoder.cc +++ b/content/common/gpu/media/vp8_decoder.cc
@@ -184,6 +184,10 @@ return true; } +gfx::Size VP8Decoder::GetPicSize() const { + return pic_size_; +} + size_t VP8Decoder::GetRequiredNumOfPictures() const { const size_t kVP8NumFramesActive = 4; const size_t kPicsInPipeline = media::limits::kMaxVideoFrames + 2;
diff --git a/content/common/gpu/media/vp8_decoder.h b/content/common/gpu/media/vp8_decoder.h index a0c29b96b..e05ab51 100644 --- a/content/common/gpu/media/vp8_decoder.h +++ b/content/common/gpu/media/vp8_decoder.h
@@ -66,7 +66,7 @@ void Reset() override; void SetStream(const uint8_t* ptr, size_t size) override; DecodeResult Decode() override WARN_UNUSED_RESULT; - gfx::Size GetPicSize() const override { return pic_size_; } + gfx::Size GetPicSize() const override; size_t GetRequiredNumOfPictures() const override; private:
diff --git a/content/common/host_shared_bitmap_manager.cc b/content/common/host_shared_bitmap_manager.cc index 778260b..b95820c 100644 --- a/content/common/host_shared_bitmap_manager.cc +++ b/content/common/host_shared_bitmap_manager.cc
@@ -55,6 +55,41 @@ base::LazyInstance<HostSharedBitmapManager> g_shared_memory_manager = LAZY_INSTANCE_INITIALIZER; +HostSharedBitmapManagerClient::HostSharedBitmapManagerClient( + HostSharedBitmapManager* manager) + : manager_(manager) { +} + +HostSharedBitmapManagerClient::~HostSharedBitmapManagerClient() { + for (const auto& id : owned_bitmaps_) + manager_->ChildDeletedSharedBitmap(id); +} + +void HostSharedBitmapManagerClient::AllocateSharedBitmapForChild( + base::ProcessHandle process_handle, + size_t buffer_size, + const cc::SharedBitmapId& id, + base::SharedMemoryHandle* shared_memory_handle) { + manager_->AllocateSharedBitmapForChild(process_handle, buffer_size, id, + shared_memory_handle); + owned_bitmaps_.insert(id); +} + +void HostSharedBitmapManagerClient::ChildAllocatedSharedBitmap( + size_t buffer_size, + const base::SharedMemoryHandle& handle, + base::ProcessHandle process_handle, + const cc::SharedBitmapId& id) { + manager_->ChildAllocatedSharedBitmap(buffer_size, handle, process_handle, id); + owned_bitmaps_.insert(id); +} + +void HostSharedBitmapManagerClient::ChildDeletedSharedBitmap( + const cc::SharedBitmapId& id) { + manager_->ChildDeletedSharedBitmap(id); + owned_bitmaps_.erase(id); +} + HostSharedBitmapManager::HostSharedBitmapManager() {} HostSharedBitmapManager::~HostSharedBitmapManager() { DCHECK(handle_map_.empty()); @@ -123,7 +158,6 @@ 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(handle, false, data->process_handle)); @@ -157,7 +191,6 @@ data->memory = shared_memory.Pass(); handle_map_[id] = data; - process_map_[process_handle].insert(id); if (!data->memory->ShareToProcess(process_handle, shared_memory_handle)) { LOG(ERROR) << "Cannot share shared memory buffer"; *shared_memory_handle = base::SharedMemory::NULLHandle(); @@ -169,29 +202,7 @@ void HostSharedBitmapManager::ChildDeletedSharedBitmap( const cc::SharedBitmapId& id) { base::AutoLock lock(lock_); - BitmapMap::iterator it = handle_map_.find(id); - if (it == handle_map_.end()) - return; - base::hash_set<cc::SharedBitmapId>& res = - process_map_[it->second->process_handle]; - res.erase(id); - handle_map_.erase(it); -} - -void HostSharedBitmapManager::ProcessRemoved( - base::ProcessHandle process_handle) { - base::AutoLock lock(lock_); - ProcessMap::iterator proc_it = process_map_.find(process_handle); - if (proc_it == process_map_.end()) - return; - base::hash_set<cc::SharedBitmapId>& res = proc_it->second; - - for (base::hash_set<cc::SharedBitmapId>::iterator it = res.begin(); - it != res.end(); - ++it) { - handle_map_.erase(*it); - } - process_map_.erase(proc_it); + handle_map_.erase(id); } size_t HostSharedBitmapManager::AllocatedBitmapCount() const {
diff --git a/content/common/host_shared_bitmap_manager.h b/content/common/host_shared_bitmap_manager.h index 423023ab..ce95f76b 100644 --- a/content/common/host_shared_bitmap_manager.h +++ b/content/common/host_shared_bitmap_manager.h
@@ -29,6 +29,31 @@ namespace content { class BitmapData; +class HostSharedBitmapManager; + +class CONTENT_EXPORT HostSharedBitmapManagerClient { + public: + explicit HostSharedBitmapManagerClient(HostSharedBitmapManager* manager); + + ~HostSharedBitmapManagerClient(); + + void AllocateSharedBitmapForChild( + base::ProcessHandle process_handle, + size_t buffer_size, + const cc::SharedBitmapId& id, + base::SharedMemoryHandle* shared_memory_handle); + void ChildAllocatedSharedBitmap(size_t buffer_size, + const base::SharedMemoryHandle& handle, + base::ProcessHandle process_handle, + const cc::SharedBitmapId& id); + void ChildDeletedSharedBitmap(const cc::SharedBitmapId& id); + + private: + HostSharedBitmapManager* manager_; + base::hash_set<cc::SharedBitmapId> owned_bitmaps_; + + DISALLOW_COPY_AND_ASSIGN(HostSharedBitmapManagerClient); +}; class CONTENT_EXPORT HostSharedBitmapManager : public cc::SharedBitmapManager { public: @@ -44,6 +69,13 @@ const gfx::Size& size, const cc::SharedBitmapId&) override; + size_t AllocatedBitmapCount() const; + + void FreeSharedMemoryFromMap(const cc::SharedBitmapId& id); + + private: + friend class HostSharedBitmapManagerClient; + void AllocateSharedBitmapForChild( base::ProcessHandle process_handle, size_t buffer_size, @@ -54,22 +86,14 @@ base::ProcessHandle process_handle, const cc::SharedBitmapId& id); void ChildDeletedSharedBitmap(const cc::SharedBitmapId& id); - void ProcessRemoved(base::ProcessHandle process_handle); - size_t AllocatedBitmapCount() const; - - void FreeSharedMemoryFromMap(const cc::SharedBitmapId& id); - - private: mutable base::Lock lock_; typedef base::hash_map<cc::SharedBitmapId, scoped_refptr<BitmapData> > BitmapMap; BitmapMap handle_map_; - typedef base::hash_map<base::ProcessHandle, - base::hash_set<cc::SharedBitmapId> > ProcessMap; - ProcessMap process_map_; + DISALLOW_COPY_AND_ASSIGN(HostSharedBitmapManager); }; } // namespace content
diff --git a/content/common/host_shared_bitmap_manager_unittest.cc b/content/common/host_shared_bitmap_manager_unittest.cc index 1cade6a..308402e3 100644 --- a/content/common/host_shared_bitmap_manager_unittest.cc +++ b/content/common/host_shared_bitmap_manager_unittest.cc
@@ -23,10 +23,11 @@ memset(bitmap->memory(), 0xff, size_in_bytes); cc::SharedBitmapId id = cc::SharedBitmap::GenerateId(); + HostSharedBitmapManagerClient client(manager_.get()); base::SharedMemoryHandle handle; bitmap->ShareToProcess(base::GetCurrentProcessHandle(), &handle); - manager_->ChildAllocatedSharedBitmap( - size_in_bytes, handle, base::GetCurrentProcessHandle(), id); + client.ChildAllocatedSharedBitmap(size_in_bytes, handle, + base::GetCurrentProcessHandle(), id); scoped_ptr<cc::SharedBitmap> large_bitmap; large_bitmap = manager_->GetSharedBitmapFromId(gfx::Size(1024, 1024), id); @@ -63,7 +64,7 @@ EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes), 0); - manager_->ChildDeletedSharedBitmap(id); + client.ChildDeletedSharedBitmap(id); memset(bitmap->memory(), 0, size_in_bytes); @@ -78,9 +79,10 @@ size_t size_in_bytes; EXPECT_TRUE(cc::SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes)); cc::SharedBitmapId id = cc::SharedBitmap::GenerateId(); + HostSharedBitmapManagerClient client(manager_.get()); base::SharedMemoryHandle handle; - manager_->AllocateSharedBitmapForChild( - base::GetCurrentProcessHandle(), size_in_bytes, id, &handle); + client.AllocateSharedBitmapForChild(base::GetCurrentProcessHandle(), + size_in_bytes, id, &handle); EXPECT_TRUE(base::SharedMemory::IsHandleValid(handle)); scoped_ptr<base::SharedMemory> bitmap(new base::SharedMemory(handle, false)); @@ -93,7 +95,7 @@ EXPECT_TRUE( memcmp(bitmap->memory(), shared_bitmap->pixels(), size_in_bytes) == 0); - manager_->ChildDeletedSharedBitmap(id); + client.ChildDeletedSharedBitmap(id); } TEST_F(HostSharedBitmapManagerTest, RemoveProcess) { @@ -106,17 +108,19 @@ cc::SharedBitmapId id = cc::SharedBitmap::GenerateId(); base::SharedMemoryHandle handle; + scoped_ptr<HostSharedBitmapManagerClient> client( + new HostSharedBitmapManagerClient(manager_.get())); bitmap->ShareToProcess(base::GetCurrentProcessHandle(), &handle); - manager_->ChildAllocatedSharedBitmap( - size_in_bytes, handle, base::GetCurrentProcessHandle(), id); - - manager_->ProcessRemoved(base::kNullProcessHandle); + client->ChildAllocatedSharedBitmap(size_in_bytes, handle, + base::GetCurrentProcessHandle(), id); scoped_ptr<cc::SharedBitmap> shared_bitmap; shared_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id); ASSERT_TRUE(shared_bitmap.get() != NULL); - manager_->ProcessRemoved(base::GetCurrentProcessHandle()); + EXPECT_EQ(1u, manager_->AllocatedBitmapCount()); + client.reset(); + EXPECT_EQ(0u, manager_->AllocatedBitmapCount()); scoped_ptr<cc::SharedBitmap> shared_bitmap2; shared_bitmap2 = manager_->GetSharedBitmapFromId(bitmap_size, id); @@ -125,9 +129,6 @@ 0); shared_bitmap.reset(); - - // Should no-op. - manager_->ChildDeletedSharedBitmap(id); } TEST_F(HostSharedBitmapManagerTest, AddDuplicate) { @@ -138,25 +139,26 @@ bitmap->CreateAndMapAnonymous(size_in_bytes); memset(bitmap->memory(), 0xff, size_in_bytes); cc::SharedBitmapId id = cc::SharedBitmap::GenerateId(); + HostSharedBitmapManagerClient client(manager_.get()); base::SharedMemoryHandle handle; bitmap->ShareToProcess(base::GetCurrentProcessHandle(), &handle); - manager_->ChildAllocatedSharedBitmap( - size_in_bytes, handle, base::GetCurrentProcessHandle(), id); + client.ChildAllocatedSharedBitmap(size_in_bytes, handle, + base::GetCurrentProcessHandle(), id); scoped_ptr<base::SharedMemory> bitmap2(new base::SharedMemory()); bitmap2->CreateAndMapAnonymous(size_in_bytes); memset(bitmap2->memory(), 0x00, size_in_bytes); - manager_->ChildAllocatedSharedBitmap( - size_in_bytes, bitmap2->handle(), base::GetCurrentProcessHandle(), id); + client.ChildAllocatedSharedBitmap(size_in_bytes, bitmap2->handle(), + base::GetCurrentProcessHandle(), id); scoped_ptr<cc::SharedBitmap> shared_bitmap; shared_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id); ASSERT_TRUE(shared_bitmap.get() != NULL); EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes), 0); - manager_->ChildDeletedSharedBitmap(id); + client.ChildDeletedSharedBitmap(id); } } // namespace
diff --git a/content/common/input/input_param_traits.cc b/content/common/input/input_param_traits.cc index 33769fe0..1f4b7e4 100644 --- a/content/common/input/input_param_traits.cc +++ b/content/common/input/input_param_traits.cc
@@ -6,6 +6,7 @@ #include "content/common/content_param_traits.h" #include "content/common/input/synthetic_pinch_gesture_params.h" +#include "content/common/input/synthetic_smooth_drag_gesture_params.h" #include "content/common/input/synthetic_smooth_scroll_gesture_params.h" #include "content/common/input/web_input_event_traits.h" #include "content/common/input_messages.h" @@ -62,6 +63,10 @@ WriteParam(m, *content::SyntheticSmoothScrollGestureParams::Cast( p.gesture_params())); break; + case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE: + WriteParam(m, *content::SyntheticSmoothDragGestureParams::Cast( + p.gesture_params())); + break; case content::SyntheticGestureParams::PINCH_GESTURE: WriteParam(m, *content::SyntheticPinchGestureParams::Cast( p.gesture_params())); @@ -70,10 +75,6 @@ WriteParam(m, *content::SyntheticTapGestureParams::Cast( p.gesture_params())); break; - // TODO(ssid): When API and IPC messages are set up, implement this. - case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE: - NOTIMPLEMENTED(); - break; } } @@ -90,6 +91,10 @@ ReadGestureParams<content::SyntheticSmoothScrollGestureParams>(m, iter); break; + case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE: + gesture_params = + ReadGestureParams<content::SyntheticSmoothDragGestureParams>(m, iter); + break; case content::SyntheticGestureParams::PINCH_GESTURE: gesture_params = ReadGestureParams<content::SyntheticPinchGestureParams>(m, iter); @@ -116,6 +121,11 @@ p.gesture_params()), l); break; + case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE: + LogParam( + *content::SyntheticSmoothDragGestureParams::Cast(p.gesture_params()), + l); + break; case content::SyntheticGestureParams::PINCH_GESTURE: LogParam( *content::SyntheticPinchGestureParams::Cast(p.gesture_params()), @@ -126,10 +136,6 @@ *content::SyntheticTapGestureParams::Cast(p.gesture_params()), l); break; - // TODO(ssid): When API and IPC messages are set up, implement this. - case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE: - NOTIMPLEMENTED(); - break; } }
diff --git a/content/common/input_messages.h b/content/common/input_messages.h index 14967b48..5bdda8f 100644 --- a/content/common/input_messages.h +++ b/content/common/input_messages.h
@@ -17,6 +17,7 @@ #include "content/common/input/synthetic_gesture_packet.h" #include "content/common/input/synthetic_gesture_params.h" #include "content/common/input/synthetic_pinch_gesture_params.h" +#include "content/common/input/synthetic_smooth_drag_gesture_params.h" #include "content/common/input/synthetic_smooth_scroll_gesture_params.h" #include "content/common/input/synthetic_tap_gesture_params.h" #include "content/common/input/touch_action.h" @@ -77,6 +78,13 @@ IPC_STRUCT_TRAITS_MEMBER(gesture_source_type) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_TRAITS_BEGIN(content::SyntheticSmoothDragGestureParams) + IPC_STRUCT_TRAITS_PARENT(content::SyntheticGestureParams) + IPC_STRUCT_TRAITS_MEMBER(start_point) + IPC_STRUCT_TRAITS_MEMBER(distances) + IPC_STRUCT_TRAITS_MEMBER(speed_in_pixels_s) +IPC_STRUCT_TRAITS_END() + IPC_STRUCT_TRAITS_BEGIN(content::SyntheticSmoothScrollGestureParams) IPC_STRUCT_TRAITS_PARENT(content::SyntheticGestureParams) IPC_STRUCT_TRAITS_MEMBER(anchor)
diff --git a/content/common/mac/font_loader.mm b/content/common/mac/font_loader.mm index be0b530..d829175b8 100644 --- a/content/common/mac/font_loader.mm +++ b/content/common/mac/font_loader.mm
@@ -93,12 +93,10 @@ result->font_id = 0; NSFont* font_to_encode = font.ToNSFont(); - // Used only for logging. - std::string font_name([[font_to_encode fontName] UTF8String]); // Load appropriate NSFont. if (!font_to_encode) { - DLOG(ERROR) << "Failed to load font " << font_name; + DLOG(ERROR) << "Failed to load font " << font.font_name; return; } @@ -115,7 +113,7 @@ base::mac::CFToNSCast(base::mac::CFCastStrict<CFURLRef>( CTFontCopyAttribute(ct_font_to_encode, kCTFontURLAttribute)))); if (![font_url isFileURL]) { - DLOG(ERROR) << "Failed to find font file for " << font_name; + DLOG(ERROR) << "Failed to find font file for " << font.font_name; return; } @@ -135,7 +133,7 @@ int32 font_file_size_32 = static_cast<int32>(font_file_size_64); if (!result->font_data.CreateAndMapAnonymous(font_file_size_32)) { - DLOG(ERROR) << "Failed to create shmem area for " << font_name; + DLOG(ERROR) << "Failed to create shmem area for " << font.font_name; return; }
diff --git a/content/common/media/video_capture_messages.h b/content/common/media/video_capture_messages.h index bebe487a..77f95bf 100644 --- a/content/common/media/video_capture_messages.h +++ b/content/common/media/video_capture_messages.h
@@ -25,6 +25,24 @@ IPC_STRUCT_TRAITS_MEMBER(resolution_change_policy) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_BEGIN(VideoCaptureMsg_BufferReady_Params) + IPC_STRUCT_MEMBER(int, device_id) + IPC_STRUCT_MEMBER(int, buffer_id) + IPC_STRUCT_MEMBER(gfx::Size, coded_size) + IPC_STRUCT_MEMBER(gfx::Rect, visible_rect) + IPC_STRUCT_MEMBER(base::TimeTicks, timestamp) + IPC_STRUCT_MEMBER(base::DictionaryValue, metadata) +IPC_STRUCT_END() + +IPC_STRUCT_BEGIN(VideoCaptureMsg_MailboxBufferReady_Params) + IPC_STRUCT_MEMBER(int, device_id) + IPC_STRUCT_MEMBER(int, buffer_id) + IPC_STRUCT_MEMBER(gpu::MailboxHolder, mailbox_holder) + IPC_STRUCT_MEMBER(gfx::Size, packed_frame_size) + IPC_STRUCT_MEMBER(base::TimeTicks, timestamp) + IPC_STRUCT_MEMBER(base::DictionaryValue, metadata) +IPC_STRUCT_END() + // TODO(nick): device_id in these messages is basically just a route_id. We // should shift to IPC_MESSAGE_ROUTED and use MessageRouter in the filter impls. @@ -48,21 +66,13 @@ int /* buffer_id */) // Tell the renderer process that a buffer is available from video capture. -IPC_MESSAGE_CONTROL5(VideoCaptureMsg_BufferReady, - int /* device id */, - int /* buffer_id */, - media::VideoCaptureFormat /* format */, - gfx::Rect /* visible_rect */, - base::TimeTicks /* timestamp */) +IPC_MESSAGE_CONTROL1(VideoCaptureMsg_BufferReady, + VideoCaptureMsg_BufferReady_Params) // Tell the renderer process that a texture mailbox buffer is available from // video capture. -IPC_MESSAGE_CONTROL5(VideoCaptureMsg_MailboxBufferReady, - int /* device_id */, - int /* buffer_id */, - gpu::MailboxHolder /* mailbox_holder */, - media::VideoCaptureFormat /* format */, - base::TimeTicks /* timestamp */) +IPC_MESSAGE_CONTROL1(VideoCaptureMsg_MailboxBufferReady, + VideoCaptureMsg_MailboxBufferReady_Params) // Notify the renderer about a device's supported formats; this is a response // to a VideoCaptureHostMsg_GetDeviceSupportedFormats request.
diff --git a/content/common/mojo/channel_init.cc b/content/common/mojo/channel_init.cc new file mode 100644 index 0000000..1599eb11 --- /dev/null +++ b/content/common/mojo/channel_init.cc
@@ -0,0 +1,80 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/mojo/channel_init.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/lazy_instance.h" +#include "base/message_loop/message_loop.h" +#include "third_party/mojo/src/mojo/edk/embedder/embedder.h" + +namespace content { + +namespace { + +base::LazyInstance<scoped_refptr<base::TaskRunner>> + g_single_process_task_runner = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +ChannelInit::ChannelInit() : channel_info_(nullptr), weak_factory_(this) {} + +ChannelInit::~ChannelInit() { + if (channel_info_) + mojo::embedder::DestroyChannel(channel_info_, + base::Bind(&base::DoNothing), nullptr); +} + +mojo::ScopedMessagePipeHandle ChannelInit::Init( + base::PlatformFile file, + scoped_refptr<base::TaskRunner> io_thread_task_runner) { + scoped_ptr<IPC::ScopedIPCSupport> ipc_support( + new IPC::ScopedIPCSupport(io_thread_task_runner)); + mojo::ScopedMessagePipeHandle message_pipe = + mojo::embedder::CreateChannel( + mojo::embedder::ScopedPlatformHandle( + mojo::embedder::PlatformHandle(file)), + io_thread_task_runner, + base::Bind(&ChannelInit::OnCreatedChannel, + weak_factory_.GetWeakPtr(), + base::Passed(&ipc_support)), + base::MessageLoop::current()->task_runner()).Pass(); + return message_pipe.Pass(); +} + +void ChannelInit::WillDestroySoon() { + if (channel_info_) + mojo::embedder::WillDestroyChannelSoon(channel_info_); +} + +// static +scoped_refptr<base::TaskRunner> ChannelInit::GetSingleProcessIOTaskRunner() { + return g_single_process_task_runner.Get(); +} + +// static +void ChannelInit::SetSingleProcessIOTaskRunner( + scoped_refptr<base::TaskRunner> io_task_runner) { + g_single_process_task_runner.Get() = io_task_runner; +} + +// static +void ChannelInit::OnCreatedChannel( + base::WeakPtr<ChannelInit> self, + scoped_ptr<IPC::ScopedIPCSupport> ipc_support, + mojo::embedder::ChannelInfo* channel) { + // If |self| was already destroyed, shut the channel down. + if (!self) { + mojo::embedder::DestroyChannel(channel, + base::Bind(&base::DoNothing), nullptr); + return; + } + + DCHECK(!self->channel_info_); + self->channel_info_ = channel; + self->ipc_support_ = ipc_support.Pass(); +} + +} // namespace content
diff --git a/content/common/mojo/channel_init.h b/content/common/mojo/channel_init.h new file mode 100644 index 0000000..659d4bb --- /dev/null +++ b/content/common/mojo/channel_init.h
@@ -0,0 +1,64 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMON_MOJO_CHANNEL_INIT_H_ +#define CONTENT_COMMON_MOJO_CHANNEL_INIT_H_ + +#include "base/files/file.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "content/common/content_export.h" +#include "ipc/mojo/scoped_ipc_support.h" +#include "third_party/mojo/src/mojo/edk/embedder/channel_info_forward.h" +#include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.h" + +namespace base { +class MessageLoopProxy; +class TaskRunner; +} + +namespace content { + +// ChannelInit handles creation and destruction of the Mojo channel. It is not +// thread-safe, but may be used on any single thread with a MessageLoop. +class CONTENT_EXPORT ChannelInit { + public: + ChannelInit(); + ~ChannelInit(); + + // Initializes the channel. This takes ownership of |file|. Returns the + // primordial MessagePipe for the channel. + mojo::ScopedMessagePipeHandle Init( + base::PlatformFile file, + scoped_refptr<base::TaskRunner> io_thread_task_runner); + + // Notifies the channel that we (hence it) will soon be destroyed. + void WillDestroySoon(); + + // Get/Set a shared I/O TaskRunner for children to use in single process mode. + static scoped_refptr<base::TaskRunner> GetSingleProcessIOTaskRunner(); + static void SetSingleProcessIOTaskRunner( + scoped_refptr<base::TaskRunner> io_task_runner); + + private: + // Invoked on the thread on which this object lives once the channel has been + // established. This is a static method that takes a weak pointer to self, + // since we want to destroy the channel if we were destroyed first. + static void OnCreatedChannel( + base::WeakPtr<ChannelInit> self, + scoped_ptr<IPC::ScopedIPCSupport> ipc_support, + mojo::embedder::ChannelInfo* channel); + + // If non-null the channel has been established. + mojo::embedder::ChannelInfo* channel_info_; + + scoped_ptr<IPC::ScopedIPCSupport> ipc_support_; + base::WeakPtrFactory<ChannelInit> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ChannelInit); +}; + +} // namespace content + +#endif // CONTENT_COMMON_MOJO_CHANNEL_INIT_H_
diff --git a/content/common/navigation_params.cc b/content/common/navigation_params.cc index 4171937..3213337f 100644 --- a/content/common/navigation_params.cc +++ b/content/common/navigation_params.cc
@@ -7,6 +7,7 @@ #include "base/memory/ref_counted_memory.h" namespace content { + CommonNavigationParams::CommonNavigationParams() : transition(ui::PAGE_TRANSITION_LINK), navigation_type(FrameMsg_Navigate_Type::NORMAL), @@ -21,14 +22,18 @@ FrameMsg_Navigate_Type::Value navigation_type, bool allow_download, base::TimeTicks ui_timestamp, - FrameMsg_UILoadMetricsReportType::Value report_type) + FrameMsg_UILoadMetricsReportType::Value report_type, + const GURL& base_url_for_data_url, + const GURL& history_url_for_data_url) : url(url), referrer(referrer), transition(transition), navigation_type(navigation_type), allow_download(allow_download), ui_timestamp(ui_timestamp), - report_type(report_type) { + report_type(report_type), + base_url_for_data_url(base_url_for_data_url), + history_url_for_data_url(history_url_for_data_url) { } CommonNavigationParams::~CommonNavigationParams() {
diff --git a/content/common/navigation_params.h b/content/common/navigation_params.h index 757d1a7..58e2ca5 100644 --- a/content/common/navigation_params.h +++ b/content/common/navigation_params.h
@@ -38,7 +38,9 @@ FrameMsg_Navigate_Type::Value navigation_type, bool allow_download, base::TimeTicks ui_timestamp, - FrameMsg_UILoadMetricsReportType::Value report_type); + FrameMsg_UILoadMetricsReportType::Value report_type, + const GURL& base_url_for_data_url, + const GURL& history_url_for_data_url); ~CommonNavigationParams(); // The URL to navigate to. @@ -66,6 +68,14 @@ // The report type to be used when recording the metric using |ui_timestamp|. FrameMsg_UILoadMetricsReportType::Value report_type; + + // Base URL for use in Blink's SubstituteData. + // Is only used with data: URLs. + GURL base_url_for_data_url; + + // History URL for use in Blink's SubstituteData. + // Is only used with data: URLs. + GURL history_url_for_data_url; }; // PlzNavigate: parameters needed to start a navigation on the IO thread.
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h index f883f37..29c42a16 100644 --- a/content/common/service_worker/service_worker_messages.h +++ b/content/common/service_worker/service_worker_messages.h
@@ -75,7 +75,6 @@ IPC_STRUCT_TRAITS_MEMBER(ignore_search) IPC_STRUCT_TRAITS_MEMBER(ignore_method) IPC_STRUCT_TRAITS_MEMBER(ignore_vary) - IPC_STRUCT_TRAITS_MEMBER(prefix_match) IPC_STRUCT_TRAITS_MEMBER(cache_name) IPC_STRUCT_TRAITS_END() @@ -426,9 +425,8 @@ std::vector<int> /* new_routing_ids */) // Sent via EmbeddedWorker to dispatch events. -IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_InstallEvent, - int /* request_id */, - int /* active_version_id */) +IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_InstallEvent, + int /* request_id */) IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_ActivateEvent, int /* request_id */) IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_FetchEvent,
diff --git a/content/common/service_worker/service_worker_types.cc b/content/common/service_worker/service_worker_types.cc index 2f371e6..a93d7c59 100644 --- a/content/common/service_worker/service_worker_types.cc +++ b/content/common/service_worker/service_worker_types.cc
@@ -74,8 +74,7 @@ ServiceWorkerCacheQueryParams::ServiceWorkerCacheQueryParams() : ignore_search(false), ignore_method(false), - ignore_vary(false), - prefix_match(false) {} + ignore_vary(false) {} ServiceWorkerBatchOperation::ServiceWorkerBatchOperation() {}
diff --git a/content/common/service_worker/service_worker_types.h b/content/common/service_worker/service_worker_types.h index fb671f6f9..26324937 100644 --- a/content/common/service_worker/service_worker_types.h +++ b/content/common/service_worker/service_worker_types.h
@@ -149,7 +149,6 @@ bool ignore_search; bool ignore_method; bool ignore_vary; - bool prefix_match; base::string16 cache_name; };
diff --git a/content/content.gyp b/content/content.gyp index ef9d21a..3d73378c 100644 --- a/content/content.gyp +++ b/content/content.gyp
@@ -444,6 +444,7 @@ 'content_strings_grd', 'content_gamepad_mapping', 'gesture_event_type_java', + 'invalidate_types_java', 'navigation_controller_java', 'popup_item_type_java', 'result_codes_java', @@ -496,6 +497,14 @@ 'includes': [ '../build/android/java_cpp_enum.gypi' ], }, { + 'target_name': 'invalidate_types_java', + 'type': 'none', + 'variables': { + 'source_file': 'public/browser/invalidate_type.h', + }, + 'includes': [ '../build/android/java_cpp_enum.gypi' ], + }, + { 'target_name': 'navigation_controller_java', 'type': 'none', 'variables': {
diff --git a/content/content_browser.gypi b/content/content_browser.gypi index e0afa125..6a2897f9 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi
@@ -355,6 +355,8 @@ 'browser/android/interstitial_page_delegate_android.h', 'browser/android/load_url_params.cc', 'browser/android/load_url_params.h', + 'browser/android/media_players_observer.cc', + 'browser/android/media_players_observer.h', 'browser/android/overscroll_controller_android.cc', 'browser/android/overscroll_controller_android.h', 'browser/android/overscroll_glow.cc', @@ -367,8 +369,8 @@ 'browser/android/tracing_controller_android.h', 'browser/android/url_request_content_job.cc', 'browser/android/url_request_content_job.h', - 'browser/android/web_contents_observer_android.cc', - 'browser/android/web_contents_observer_android.h', + 'browser/android/web_contents_observer_proxy.cc', + 'browser/android/web_contents_observer_proxy.h', 'browser/appcache/appcache.cc', 'browser/appcache/appcache.h', 'browser/appcache/appcache_backend_impl.cc', @@ -527,8 +529,6 @@ 'browser/devtools/protocol/tethering_handler.h', 'browser/devtools/protocol/tracing_handler.cc', 'browser/devtools/protocol/tracing_handler.h', - 'browser/devtools/protocol/usage_and_quota_query.cc', - 'browser/devtools/protocol/usage_and_quota_query.h', 'browser/devtools/protocol/worker_handler.cc', 'browser/devtools/protocol/worker_handler.h', 'browser/devtools/render_frame_devtools_agent_host.cc', @@ -928,6 +928,8 @@ 'browser/media/android/media_drm_credential_manager.h', 'browser/media/android/media_resource_getter_impl.cc', 'browser/media/android/media_resource_getter_impl.h', + 'browser/media/audio_state_provider.cc', + 'browser/media/audio_state_provider.h', 'browser/media/audio_stream_monitor.cc', 'browser/media/audio_stream_monitor.h', 'browser/media/capture/audio_mirroring_manager.cc',
diff --git a/content/content_common.gypi b/content/content_common.gypi index c62e10f..3a63205 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi
@@ -416,6 +416,8 @@ 'common/message_router.cc', 'common/message_router.h', 'common/mime_registry_messages.h', + 'common/mojo/channel_init.cc', + 'common/mojo/channel_init.h', 'common/mojo/mojo_messages.h', 'common/mojo/service_registry_impl.cc', 'common/mojo/service_registry_impl.h',
diff --git a/content/content_jni.gypi b/content/content_jni.gypi index a1f098f..744e9e1 100644 --- a/content/content_jni.gypi +++ b/content/content_jni.gypi
@@ -37,9 +37,9 @@ 'public/android/java/src/org/chromium/content/browser/TimeZoneMonitor.java', 'public/android/java/src/org/chromium/content/browser/TouchEventSynthesizer.java', 'public/android/java/src/org/chromium/content/browser/TracingControllerAndroid.java', - 'public/android/java/src/org/chromium/content/browser/WebContentsObserver.java', 'public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java', 'public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java', + 'public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java', 'public/android/java/src/org/chromium/content_public/browser/LoadUrlParams.java', ], 'variables': {
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 7c9acb0..6a0de9e 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi
@@ -588,6 +588,8 @@ 'renderer/render_widget_fullscreen_pepper.h', ], 'public_renderer_webrtc_sources': [ + 'public/renderer/media_stream_api.cc', + 'public/renderer/media_stream_api.h', 'public/renderer/media_stream_audio_sink.cc', 'public/renderer/media_stream_audio_sink.h', 'public/renderer/media_stream_sink.h',
diff --git a/content/content_shell.gypi b/content/content_shell.gypi index 8a7ebdd..fa9ba12 100644 --- a/content/content_shell.gypi +++ b/content/content_shell.gypi
@@ -112,6 +112,8 @@ 'shell/browser/layout_test/layout_test_javascript_dialog_manager.h', 'shell/browser/layout_test/layout_test_message_filter.cc', 'shell/browser/layout_test/layout_test_message_filter.h', + 'shell/browser/layout_test/layout_test_navigator_connect_service_factory.cc', + 'shell/browser/layout_test/layout_test_navigator_connect_service_factory.h', 'shell/browser/layout_test/layout_test_notification_manager.cc', 'shell/browser/layout_test/layout_test_notification_manager.h', 'shell/browser/layout_test/layout_test_push_messaging_service.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 602f098a..9d5a2dc 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi
@@ -99,6 +99,7 @@ 'public/test/test_synchronous_compositor_android.h', 'public/test/test_utils.cc', 'public/test/test_utils.h', + 'public/test/test_web_contents_factory.h', 'public/test/unittest_test_suite.cc', 'public/test/unittest_test_suite.h', 'public/test/web_contents_observer_sanity_checker.cc', @@ -164,6 +165,7 @@ 'test/test_render_view_host_factory.h', 'test/test_web_contents.cc', 'test/test_web_contents.h', + 'test/test_web_contents_factory.cc', 'test/web_gesture_curve_mock.cc', 'test/web_gesture_curve_mock.h', 'test/web_layer_tree_view_impl_for_testing.cc', @@ -1118,6 +1120,7 @@ 'sources!': [ 'browser/geolocation/network_location_provider_unittest.cc', 'browser/geolocation/wifi_data_provider_common_unittest.cc', + 'browser/media/audio_stream_monitor_unittest.cc', 'browser/webui/url_data_manager_backend_unittest.cc', ], 'dependencies': [
diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc index 1064a70..901618e 100644 --- a/content/gpu/gpu_child_thread.cc +++ b/content/gpu/gpu_child_thread.cc
@@ -45,17 +45,17 @@ } ChildThreadImpl::Options GetOptions() { - ChildThreadImpl::Options options; + ChildThreadImpl::Options::Builder builder; #if defined(USE_OZONE) IPC::MessageFilter* message_filter = ui::OzonePlatform::GetInstance() ->GetGpuPlatformSupport() ->GetMessageFilter(); if (message_filter) - options.startup_filters.push_back(message_filter); + builder.AddStartupFilter(message_filter); #endif - return options; + return builder.Build(); } } // namespace @@ -77,7 +77,10 @@ } GpuChildThread::GpuChildThread(const std::string& channel_id) - : ChildThreadImpl(Options(channel_id, false)), + : ChildThreadImpl(Options::Builder() + .InBrowserProcess(true) + .WithChannelName(channel_id) + .Build()), dead_on_arrival_(false), in_browser_process_(true) { #if defined(OS_WIN)
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc index f73bb0d1..b34d42f9 100644 --- a/content/gpu/gpu_main.cc +++ b/content/gpu/gpu_main.cc
@@ -61,6 +61,7 @@ #if defined(SANITIZER_COVERAGE) #include <sanitizer/common_interface_defs.h> +#include <sanitizer/coverage_interface.h> #endif const int kGpuTimeout = 10000;
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index 74b47ed..98c67be3 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -111,6 +111,7 @@ "//content/browser/android/content_view_core_impl.cc", "//content/browser/android/gesture_event_type.h", "//content/browser/gamepad/gamepad_standard_mappings.h", + "//content/public/browser/invalidate_type.h", "//content/public/browser/navigation_controller.h", "//content/public/common/console_message_level.h", "//content/public/common/result_codes.h", @@ -123,6 +124,7 @@ "org/chromium/content/browser/input/CanonicalAxisIndex.java", "org/chromium/content/browser/input/CanonicalButtonIndex.java", "org/chromium/content/browser/input/PopupItemType.java", + "org/chromium/content_public/browser/InvalidateTypes.java", "org/chromium/content_public/browser/navigation_controller/LoadURLType.java", "org/chromium/content_public/browser/navigation_controller/UserAgentOverrideOption.java", "org/chromium/content_public/common/ConsoleMessageLevel.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index 226e4ea..ac9c1041 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -5,6 +5,7 @@ package org.chromium.content.browser; import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.app.Activity; import android.app.SearchManager; import android.content.ClipboardManager; @@ -76,6 +77,7 @@ import org.chromium.content.common.ContentSwitches; import org.chromium.content_public.browser.GestureStateListener; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.base.ViewAndroid; import org.chromium.ui.base.ViewAndroidDelegate; @@ -85,6 +87,7 @@ import org.chromium.ui.touch_selection.SelectionEventType; import java.lang.annotation.Annotation; +import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; @@ -277,6 +280,77 @@ } /** + * A {@link WebContentsObserver} that listens to frame navigation events. + */ + private static class ContentViewWebContentsObserver extends WebContentsObserver { + // Using a weak reference avoids cycles that might prevent GC of WebView's WebContents. + private final WeakReference<ContentViewCore> mWeakContentViewCore; + + ContentViewWebContentsObserver(ContentViewCore contentViewCore) { + super(contentViewCore.getWebContents()); + mWeakContentViewCore = new WeakReference<ContentViewCore>(contentViewCore); + } + + @Override + public void didStartLoading(String url) { + ContentViewCore contentViewCore = mWeakContentViewCore.get(); + if (contentViewCore == null) return; + contentViewCore.mAccessibilityInjector.onPageLoadStarted(); + } + + @Override + public void didStopLoading(String url) { + ContentViewCore contentViewCore = mWeakContentViewCore.get(); + if (contentViewCore == null) return; + contentViewCore.mAccessibilityInjector.onPageLoadStopped(); + } + + @Override + public void didFailLoad(boolean isProvisionalLoad, boolean isMainFrame, int errorCode, + String description, String failingUrl) { + // Navigation that fails the provisional load will have the strong binding removed + // here. One for which the provisional load is commited will have the strong binding + // removed in navigationEntryCommitted() below. + if (isProvisionalLoad) determinedProcessVisibility(); + } + + @Override + public void didNavigateMainFrame(String url, String baseUrl, + boolean isNavigationToDifferentPage, boolean isFragmentNavigation, int statusCode) { + if (!isNavigationToDifferentPage) return; + resetPopupsAndInput(); + } + + @Override + public void renderProcessGone(boolean wasOomProtected) { + resetPopupsAndInput(); + } + + @Override + public void navigationEntryCommitted() { + determinedProcessVisibility(); + } + + private void resetPopupsAndInput() { + ContentViewCore contentViewCore = mWeakContentViewCore.get(); + if (contentViewCore == null) return; + contentViewCore.mIsMobileOptimizedHint = false; + contentViewCore.hidePopupsAndClearSelection(); + contentViewCore.resetScrollInProgress(); + } + + private void determinedProcessVisibility() { + ContentViewCore contentViewCore = mWeakContentViewCore.get(); + if (contentViewCore == null) return; + // Signal to the process management logic that we can now rely on the process + // visibility signal for binding management. Before the navigation commits, its + // renderer is considered background even if the pending navigation happens in the + // foreground renderer. + ChildProcessLauncher.determinedVisibility(contentViewCore.getCurrentRenderProcessId()); + } + } + + /** * Interface that consumers of {@link ContentViewCore} must implement to allow the proper * dispatching of view methods through the containing view. * @@ -746,56 +820,7 @@ mAccessibilityInjector = AccessibilityInjector.newInstance(this); - mWebContentsObserver = new WebContentsObserver(mWebContents) { - @Override - public void didStartLoading(String url) { - mAccessibilityInjector.onPageLoadStarted(); - } - - @Override - public void didStopLoading(String url) { - mAccessibilityInjector.onPageLoadStopped(); - } - - @Override - public void didFailLoad(boolean isProvisionalLoad, boolean isMainFrame, int errorCode, - String description, String failingUrl) { - // Navigation that fails the provisional load will have the strong binding removed - // here. One for which the provisional load is commited will have the strong binding - // removed in navigationEntryCommitted() below. - if (isProvisionalLoad) determinedProcessVisibility(); - } - - @Override - public void didNavigateMainFrame(String url, String baseUrl, - boolean isNavigationToDifferentPage, boolean isFragmentNavigation) { - if (!isNavigationToDifferentPage) return; - mIsMobileOptimizedHint = false; - hidePopupsAndClearSelection(); - resetScrollInProgress(); - } - - @Override - public void renderProcessGone(boolean wasOomProtected) { - hidePopupsAndClearSelection(); - resetScrollInProgress(); - // No need to reset gesture detection as the detector will have - // been destroyed in the RenderWidgetHostView. - } - - @Override - public void navigationEntryCommitted() { - determinedProcessVisibility(); - } - - private void determinedProcessVisibility() { - // Signal to the process management logic that we can now rely on the process - // visibility signal for binding management. Before the navigation commits, its - // renderer is considered background even if the pending navigation happens in the - // foreground renderer. - ChildProcessLauncher.determinedVisibility(getCurrentRenderProcessId()); - } - }; + mWebContentsObserver = new ContentViewWebContentsObserver(this); } @VisibleForTesting @@ -945,7 +970,7 @@ if (mNativeContentViewCore != 0) { nativeOnJavaContentViewCoreDestroyed(mNativeContentViewCore); } - mWebContentsObserver.detachFromWebContents(); + mWebContentsObserver.destroy(); mWebContentsObserver = null; setSmartClipDataListener(null); setZoomControlsDelegate(null); @@ -2806,6 +2831,7 @@ /** * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) */ + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) public void onInitializeAccessibilityEvent(AccessibilityEvent event) { // Note: this is only used by the script-injecting accessibility code. event.setClassName(this.getClass().getName()); @@ -2820,9 +2846,7 @@ int maxScrollYPix = Math.max(0, mRenderCoordinates.getMaxVerticalScrollPixInt()); event.setScrollable(maxScrollXPix > 0 || maxScrollYPix > 0); - // Setting the maximum scroll values requires API level 15 or higher. - final int sdkVersionRequiredToSetScroll = 15; - if (Build.VERSION.SDK_INT >= sdkVersionRequiredToSetScroll) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { event.setMaxScrollX(maxScrollXPix); event.setMaxScrollY(maxScrollYPix); }
diff --git a/content/public/android/java/src/org/chromium/content/browser/WebContentsObserver.java b/content/public/android/java/src/org/chromium/content/browser/WebContentsObserver.java deleted file mode 100644 index f1bf6a2f..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/WebContentsObserver.java +++ /dev/null
@@ -1,219 +0,0 @@ -// Copyright 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. - -package org.chromium.content.browser; - -import org.chromium.base.CalledByNative; -import org.chromium.base.JNINamespace; -import org.chromium.base.ThreadUtils; -import org.chromium.content_public.browser.WebContents; - -/** - * This class receives callbacks that act as hooks for various a native web contents events related - * to loading a url. A single web contents can have multiple WebContentObservers. - */ -@JNINamespace("content") -public abstract class WebContentsObserver { - private long mNativeWebContentsObserverAndroid; - - public WebContentsObserver(WebContents webContents) { - ThreadUtils.assertOnUiThread(); - mNativeWebContentsObserverAndroid = nativeInit(webContents); - } - - /** - * Called when the RenderView of the current RenderViewHost is ready, e.g. because we recreated - * it after a crash. - */ - @CalledByNative - public void renderViewReady() { - } - - @CalledByNative - public void renderProcessGone(boolean wasOomProtected) { - } - - /** - * Called when the a page starts loading. - * @param url The validated url for the loading page. - */ - @CalledByNative - public void didStartLoading(String url) { - } - - /** - * Called when the a page finishes loading. - * @param url The validated url for the page. - */ - @CalledByNative - public void didStopLoading(String url) { - } - - /** - * Called when an error occurs while loading a page and/or the page fails to load. - * @param errorCode Error code for the occurring error. - * @param description The description for the error. - * @param failingUrl The url that was loading when the error occurred. - */ - @CalledByNative - public void didFailLoad(boolean isProvisionalLoad, - boolean isMainFrame, int errorCode, String description, String failingUrl) { - } - - /** - * Called when the main frame of the page has committed. - * TODO(pedrosimonetti): Remove this method once downstream changes are landed. - * @param url The validated url for the page. - * @param baseUrl The validated base url for the page. - * @param isNavigationToDifferentPage Whether the main frame navigated to a different page. - * @param isFragmentNavigation Whether the main frame navigation did not cause changes to the - * document (for example scrolling to a named anchor or PopState). - */ - public void didNavigateMainFrame(String url, String baseUrl, - boolean isNavigationToDifferentPage, boolean isFragmentNavigation) { - } - - /** - * Called when the main frame of the page has committed. - * @param url The validated url for the page. - * @param baseUrl The validated base url for the page. - * @param isNavigationToDifferentPage Whether the main frame navigated to a different page. - * @param isFragmentNavigation Whether the main frame navigation did not cause changes to the - * document (for example scrolling to a named anchor or PopState). - * @param statusCode The HTTP status code of the navigation. - */ - @CalledByNative - public void didNavigateMainFrame(String url, String baseUrl, - boolean isNavigationToDifferentPage, boolean isFragmentNavigation, int statusCode) { - didNavigateMainFrame(url, baseUrl, isNavigationToDifferentPage, isFragmentNavigation); - } - - /** - * Called when the page had painted something non-empty. - */ - @CalledByNative - public void didFirstVisuallyNonEmptyPaint() { - } - - /** - * Similar to didNavigateMainFrame but also called on subframe navigations. - * @param url The validated url for the page. - * @param baseUrl The validated base url for the page. - * @param isReload True if this navigation is a reload. - */ - @CalledByNative - public void didNavigateAnyFrame(String url, String baseUrl, boolean isReload) { - } - - /** - * Called once the window.document object of the main frame was created. - */ - @CalledByNative - public void documentAvailableInMainFrame() { - } - - /** - * Notifies that a load is started for a given frame. - * @param frameId A positive, non-zero integer identifying the navigating frame. - * @param parentFrameId The frame identifier of the frame containing the navigating frame, - * or -1 if the frame is not contained in another frame. - * @param isMainFrame Whether the load is happening for the main frame. - * @param validatedUrl The validated URL that is being navigated to. - * @param isErrorPage Whether this is navigating to an error page. - * @param isIframeSrcdoc Whether this is navigating to about:srcdoc. - */ - @CalledByNative - public void didStartProvisionalLoadForFrame( - long frameId, - long parentFrameId, - boolean isMainFrame, - String validatedUrl, - boolean isErrorPage, - boolean isIframeSrcdoc) { - } - - /** - * Notifies that the provisional load was successfully committed. The RenderViewHost is now - * the current RenderViewHost of the WebContents. - * @param frameId A positive, non-zero integer identifying the navigating frame. - * @param isMainFrame Whether the load is happening for the main frame. - * @param url The committed URL being navigated to. - * @param transitionType The transition type as defined in - * {@link org.chromium.ui.base.PageTransition} for the load. - */ - @CalledByNative - public void didCommitProvisionalLoadForFrame( - long frameId, boolean isMainFrame, String url, int transitionType) { - - } - - /** - * Notifies that a load has finished for a given frame. - * @param frameId A positive, non-zero integer identifying the navigating frame. - * @param validatedUrl The validated URL that is being navigated to. - * @param isMainFrame Whether the load is happening for the main frame. - */ - @CalledByNative - public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) { - } - - /** - * Notifies that the document has finished loading for the given frame. - * @param frameId A positive, non-zero integer identifying the navigating frame. - */ - @CalledByNative - public void documentLoadedInFrame(long frameId) { - } - - /** - * Notifies that a navigation entry has been committed. - */ - @CalledByNative - public void navigationEntryCommitted() { - } - - /** - * Called when an interstitial page gets attached to the tab content. - */ - @CalledByNative - public void didAttachInterstitialPage() { - } - - /** - * Called when an interstitial page gets detached from the tab content. - */ - @CalledByNative - public void didDetachInterstitialPage() { - } - - /** - * Called when the theme color was changed. - * @param color the new color in ARGB format - */ - @CalledByNative - public void didChangeThemeColor(int color) { - } - - /** - * Called when we started navigation to the pending entry. - * @param url The URL that we are navigating to. - */ - @CalledByNative - public void didStartNavigationToPendingEntry(String url) { - } - - /** - * Destroy the corresponding native object. - */ - @CalledByNative - public void detachFromWebContents() { - if (mNativeWebContentsObserverAndroid != 0) { - nativeDestroy(mNativeWebContentsObserverAndroid); - mNativeWebContentsObserverAndroid = 0; - } - } - - private native long nativeInit(WebContents webContents); - private native void nativeDestroy(long nativeWebContentsObserverAndroid); -}
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java index b77c88ce..b0ebf0c7 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java
@@ -4,6 +4,7 @@ package org.chromium.content.browser.accessibility; +import android.annotation.TargetApi; import android.content.Context; import android.graphics.Rect; import android.os.Build; @@ -38,6 +39,7 @@ * accessibility. */ @JNINamespace("content") +@TargetApi(Build.VERSION_CODES.JELLY_BEAN) public class BrowserAccessibilityManager { private static final String TAG = "BrowserAccessibilityManager";
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanAccessibilityInjector.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanAccessibilityInjector.java index abdeae7..67b4dca 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanAccessibilityInjector.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanAccessibilityInjector.java
@@ -4,7 +4,9 @@ package org.chromium.content.browser.accessibility; +import android.annotation.TargetApi; import android.content.Context; +import android.os.Build; import android.os.Bundle; import android.os.SystemClock; import android.view.accessibility.AccessibilityNodeInfo; @@ -22,6 +24,7 @@ * Handles injecting accessibility Javascript and related Javascript -> Java APIs for JB and newer * devices. */ +@TargetApi(Build.VERSION_CODES.JELLY_BEAN) class JellyBeanAccessibilityInjector extends AccessibilityInjector { private CallbackHandler mCallback; private JSONObject mAccessibilityJSONObject;
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanBrowserAccessibilityManager.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanBrowserAccessibilityManager.java index 62185c2..98f8863 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanBrowserAccessibilityManager.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanBrowserAccessibilityManager.java
@@ -4,6 +4,8 @@ package org.chromium.content.browser.accessibility; +import android.annotation.TargetApi; +import android.os.Build; import android.os.Bundle; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeProvider; @@ -18,6 +20,7 @@ * AccessibilityNodeProvider and delegates its implementation to this object. */ @JNINamespace("content") +@TargetApi(Build.VERSION_CODES.JELLY_BEAN) public class JellyBeanBrowserAccessibilityManager extends BrowserAccessibilityManager { private AccessibilityNodeProvider mAccessibilityNodeProvider;
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopAccessibilityInjector.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopAccessibilityInjector.java index d61484fc..d7737eb5 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopAccessibilityInjector.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopAccessibilityInjector.java
@@ -4,7 +4,9 @@ package org.chromium.content.browser.accessibility; +import android.annotation.TargetApi; import android.content.Context; +import android.os.Build; import android.os.Bundle; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; @@ -20,6 +22,7 @@ * Handles injecting accessibility Javascript and related Javascript -> Java APIs for Lollipop and * newer devices. */ +@TargetApi(Build.VERSION_CODES.LOLLIPOP) class LollipopAccessibilityInjector extends JellyBeanAccessibilityInjector { /** * Constructs an instance of the LollipopAccessibilityInjector.
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopBrowserAccessibilityManager.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopBrowserAccessibilityManager.java index a966ed6..f5c3af1 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopBrowserAccessibilityManager.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopBrowserAccessibilityManager.java
@@ -4,6 +4,8 @@ package org.chromium.content.browser.accessibility; +import android.annotation.TargetApi; +import android.os.Build; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; @@ -17,6 +19,7 @@ * AccessibilityNodeProvider and delegates its implementation to this object. */ @JNINamespace("content") +@TargetApi(Build.VERSION_CODES.LOLLIPOP) public class LollipopBrowserAccessibilityManager extends JellyBeanBrowserAccessibilityManager { LollipopBrowserAccessibilityManager(long nativeBrowserAccessibilityManagerAndroid, ContentViewCore contentViewCore) {
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 d6cb714..216be3a9 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
@@ -10,6 +10,7 @@ import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.NavigationTransitionDelegate; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; /** * The WebContentsImpl Java wrapper to allow communicating with the native WebContentsImpl @@ -23,6 +24,9 @@ private long mNativeWebContentsAndroid; private NavigationController mNavigationController; + // Lazily created proxy observer for handling all Java-based WebContentsObservers. + private WebContentsObserverProxy mObserverProxy; + private NavigationTransitionDelegate mNavigationTransitionDelegate = null; private WebContentsImpl( @@ -41,6 +45,10 @@ private void clearNativePtr() { mNativeWebContentsAndroid = 0; mNavigationController = null; + if (mObserverProxy != null) { + mObserverProxy.destroy(); + mObserverProxy = null; + } } @CalledByNative @@ -166,6 +174,11 @@ } @Override + public String getLastCommittedUrl() { + return nativeGetLastCommittedURL(mNativeWebContentsAndroid); + } + + @Override public boolean isIncognito() { return nativeIsIncognito(mNativeWebContentsAndroid); } @@ -296,12 +309,30 @@ nativeAddMessageToDevToolsConsole(mNativeWebContentsAndroid, level, message); } + @Override + public boolean hasAccessedInitialDocument() { + return nativeHasAccessedInitialDocument(mNativeWebContentsAndroid); + } + @CalledByNative private static void onEvaluateJavaScriptResult( String jsonResult, JavaScriptCallback callback) { callback.handleJavaScriptResult(jsonResult); } + @Override + public void addObserver(WebContentsObserver observer) { + assert mNativeWebContentsAndroid != 0; + if (mObserverProxy == null) mObserverProxy = new WebContentsObserverProxy(this); + mObserverProxy.addObserver(observer); + } + + @Override + public void removeObserver(WebContentsObserver observer) { + if (mObserverProxy == null) return; + mObserverProxy.removeObserver(observer); + } + // This is static to avoid exposing a public destroy method on the native side of this class. private static native void nativeDestroyWebContents(long webContentsAndroidPtr); @@ -328,6 +359,7 @@ private native void nativeScrollFocusedEditableNodeIntoView(long nativeWebContentsAndroid); private native void nativeSelectWordAroundCaret(long nativeWebContentsAndroid); private native String nativeGetURL(long nativeWebContentsAndroid); + private native String nativeGetLastCommittedURL(long nativeWebContentsAndroid); private native boolean nativeIsIncognito(long nativeWebContentsAndroid); private native void nativeResumeResponseDeferredAtStart(long nativeWebContentsAndroid); private native void nativeSetHasPendingNavigationTransitionForTesting( @@ -347,4 +379,6 @@ String script, JavaScriptCallback callback); private native void nativeAddMessageToDevToolsConsole( long nativeWebContentsAndroid, int level, String message); + private native boolean nativeHasAccessedInitialDocument( + long nativeWebContentsAndroid); }
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java new file mode 100644 index 0000000..1e678cc --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java
@@ -0,0 +1,237 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.content.browser.webcontents; + +import org.chromium.base.CalledByNative; +import org.chromium.base.JNINamespace; +import org.chromium.base.ObserverList; +import org.chromium.base.ObserverList.RewindableIterator; +import org.chromium.base.ThreadUtils; +import org.chromium.content_public.browser.WebContentsObserver; + +/** + * Serves as a compound observer proxy for dispatching WebContentsObserver callbacks, + * avoiding redundant JNI-related work when there are multiple Java-based observers. + */ +@JNINamespace("content") +class WebContentsObserverProxy extends WebContentsObserver { + private long mNativeWebContentsObserverProxy; + private final ObserverList<WebContentsObserver> mObservers; + private final RewindableIterator<WebContentsObserver> mObserversIterator; + + /** + * Constructs a new WebContentsObserverProxy for a given WebContents + * instance. A native WebContentsObserver instance will be created, which + * will observe the native counterpart to the provided WebContents. + * + * @param webContents The WebContents instance to observe. + */ + public WebContentsObserverProxy(WebContentsImpl webContents) { + ThreadUtils.assertOnUiThread(); + mNativeWebContentsObserverProxy = nativeInit(webContents); + mObservers = new ObserverList<WebContentsObserver>(); + mObserversIterator = mObservers.rewindableIterator(); + } + + /** + * Add an observer to the list of proxied observers. + * @param observer The WebContentsObserver instance to add. + */ + void addObserver(WebContentsObserver observer) { + assert mNativeWebContentsObserverProxy != 0; + mObservers.addObserver(observer); + } + + /** + * Remove an observer from the list of proxied observers. + * @param observer The WebContentsObserver instance to remove. + */ + void removeObserver(WebContentsObserver observer) { + mObservers.removeObserver(observer); + } + + /** + * @return Whether there are any active, proxied observers. + */ + boolean hasObservers() { + return !mObservers.isEmpty(); + } + + @Override + @CalledByNative + public void renderViewReady() { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().renderViewReady(); + } + } + + @Override + @CalledByNative + public void renderProcessGone(boolean wasOomProtected) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().renderProcessGone(wasOomProtected); + } + } + + @Override + @CalledByNative + public void didStartLoading(String url) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didStartLoading(url); + } + } + + @Override + @CalledByNative + public void didStopLoading(String url) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didStopLoading(url); + } + } + + @Override + @CalledByNative + public void didFailLoad(boolean isProvisionalLoad, boolean isMainFrame, int errorCode, + String description, String failingUrl) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didFailLoad( + isProvisionalLoad, isMainFrame, errorCode, description, failingUrl); + } + } + + @Override + @CalledByNative + public void didNavigateMainFrame(String url, String baseUrl, + boolean isNavigationToDifferentPage, boolean isFragmentNavigation, int statusCode) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didNavigateMainFrame( + url, baseUrl, isNavigationToDifferentPage, isFragmentNavigation, statusCode); + } + } + + @Override + @CalledByNative + public void didFirstVisuallyNonEmptyPaint() { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didFirstVisuallyNonEmptyPaint(); + } + } + + @Override + @CalledByNative + public void didNavigateAnyFrame(String url, String baseUrl, boolean isReload) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didNavigateAnyFrame(url, baseUrl, isReload); + } + } + + @Override + @CalledByNative + public void documentAvailableInMainFrame() { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().documentAvailableInMainFrame(); + } + } + + @Override + @CalledByNative + public void didStartProvisionalLoadForFrame(long frameId, long parentFrameId, + boolean isMainFrame, String validatedUrl, boolean isErrorPage, boolean isIframeSrcdoc) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didStartProvisionalLoadForFrame( + frameId, parentFrameId, isMainFrame, validatedUrl, isErrorPage, isIframeSrcdoc); + } + } + + @Override + @CalledByNative + public void didCommitProvisionalLoadForFrame( + long frameId, boolean isMainFrame, String url, int transitionType) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didCommitProvisionalLoadForFrame( + frameId, isMainFrame, url, transitionType); + } + } + + @Override + @CalledByNative + public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didFinishLoad(frameId, validatedUrl, isMainFrame); + } + } + + @Override + @CalledByNative + public void documentLoadedInFrame(long frameId) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().documentLoadedInFrame(frameId); + } + } + + @Override + @CalledByNative + public void navigationEntryCommitted() { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().navigationEntryCommitted(); + } + } + + @Override + @CalledByNative + public void didAttachInterstitialPage() { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didAttachInterstitialPage(); + } + } + + @Override + @CalledByNative + public void didDetachInterstitialPage() { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didDetachInterstitialPage(); + } + } + + @Override + @CalledByNative + public void didChangeThemeColor(int color) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didChangeThemeColor(color); + } + } + + @Override + @CalledByNative + public void didStartNavigationToPendingEntry(String url) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didStartNavigationToPendingEntry(url); + } + } + + @Override + @CalledByNative + public void destroy() { + // Super destruction semantics (removing the observer from the + // Java-based WebContents) are quite different, so we explicitly avoid + // calling it here. + ThreadUtils.assertOnUiThread(); + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().destroy(); + } + // All observer destroy() implementations should result in their removal + // from the proxy. + assert mObservers.isEmpty(); + mObservers.clear(); + + if (mNativeWebContentsObserverProxy != 0) { + nativeDestroy(mNativeWebContentsObserverProxy); + mNativeWebContentsObserverProxy = 0; + } + } + + private native long nativeInit(WebContentsImpl webContents); + private native void nativeDestroy(long nativeWebContentsObserverProxy); +}
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java index 1902161..06bf7ae9 100644 --- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -139,6 +139,14 @@ public String getUrl(); /** + * Gets the last committed URL. It represents the current page that is + * displayed in this WebContents. It represents the current security context. + * + * @return The last committed URL. + */ + public String getLastCommittedUrl(); + + /** * Get the InCognito state of WebContents. * * @return whether this WebContents is in InCognito mode or not @@ -213,4 +221,26 @@ * org.chromium.content_public.common.ConsoleMessageLevel. */ public void addMessageToDevToolsConsole(int level, String message); + + /** + * Returns whether the initial empty page has been accessed by a script from another + * page. Always false after the first commit. + * + * @return Whether the initial empty page has been accessed by a script. + */ + public boolean hasAccessedInitialDocument(); + + /** + * Add an observer to the WebContents + * + * @param observer The observer to add. + */ + void addObserver(WebContentsObserver observer); + + /** + * Remove an observer from the WebContents + * + * @param observer The observer to remove. + */ + void removeObserver(WebContentsObserver observer); }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java new file mode 100644 index 0000000..39185a3 --- /dev/null +++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java
@@ -0,0 +1,162 @@ +// Copyright 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. + +package org.chromium.content_public.browser; + +import java.lang.ref.WeakReference; + +/** + * This class receives callbacks that act as hooks for various a native web contents events related + * to loading a url. A single web contents can have multiple WebContentObservers. + */ +public abstract class WebContentsObserver { + // TODO(jdduke): Remove the destroy method and hold observer embedders + // responsible for explicit observer detachment. + // Using a weak reference avoids cycles that might prevent GC of WebView's WebContents. + private WeakReference<WebContents> mWebContents; + + public WebContentsObserver(WebContents webContents) { + mWebContents = new WeakReference<WebContents>(webContents); + webContents.addObserver(this); + } + + /** + * Called when the RenderView of the current RenderViewHost is ready, e.g. because we recreated + * it after a crash. + */ + public void renderViewReady() {} + + public void renderProcessGone(boolean wasOomProtected) {} + + /** + * Called when the a page starts loading. + * @param url The validated url for the loading page. + */ + public void didStartLoading(String url) {} + + /** + * Called when the a page finishes loading. + * @param url The validated url for the page. + */ + public void didStopLoading(String url) {} + + /** + * Called when an error occurs while loading a page and/or the page fails to load. + * @param errorCode Error code for the occurring error. + * @param description The description for the error. + * @param failingUrl The url that was loading when the error occurred. + */ + public void didFailLoad(boolean isProvisionalLoad, boolean isMainFrame, int errorCode, + String description, String failingUrl) {} + + /** + * Called when the main frame of the page has committed. + * @param url The validated url for the page. + * @param baseUrl The validated base url for the page. + * @param isNavigationToDifferentPage Whether the main frame navigated to a different page. + * @param isFragmentNavigation Whether the main frame navigation did not cause changes to the + * document (for example scrolling to a named anchor or PopState). + * @param statusCode The HTTP status code of the navigation. + */ + public void didNavigateMainFrame(String url, String baseUrl, + boolean isNavigationToDifferentPage, boolean isFragmentNavigation, int statusCode) {} + + /** + * Called when the page had painted something non-empty. + */ + public void didFirstVisuallyNonEmptyPaint() {} + + /** + * Similar to didNavigateMainFrame but also called on subframe navigations. + * @param url The validated url for the page. + * @param baseUrl The validated base url for the page. + * @param isReload True if this navigation is a reload. + */ + public void didNavigateAnyFrame(String url, String baseUrl, boolean isReload) {} + + /** + * Called once the window.document object of the main frame was created. + */ + public void documentAvailableInMainFrame() {} + + /** + * Notifies that a load is started for a given frame. + * @param frameId A positive, non-zero integer identifying the navigating frame. + * @param parentFrameId The frame identifier of the frame containing the navigating frame, + * or -1 if the frame is not contained in another frame. + * @param isMainFrame Whether the load is happening for the main frame. + * @param validatedUrl The validated URL that is being navigated to. + * @param isErrorPage Whether this is navigating to an error page. + * @param isIframeSrcdoc Whether this is navigating to about:srcdoc. + */ + public void didStartProvisionalLoadForFrame(long frameId, long parentFrameId, + boolean isMainFrame, String validatedUrl, boolean isErrorPage, boolean isIframeSrcdoc) { + } + + /** + * Notifies that the provisional load was successfully committed. The RenderViewHost is now + * the current RenderViewHost of the WebContents. + * @param frameId A positive, non-zero integer identifying the navigating frame. + * @param isMainFrame Whether the load is happening for the main frame. + * @param url The committed URL being navigated to. + * @param transitionType The transition type as defined in + * {@link org.chromium.ui.base.PageTransition} for the load. + */ + public void didCommitProvisionalLoadForFrame( + long frameId, boolean isMainFrame, String url, int transitionType) {} + + /** + * Notifies that a load has finished for a given frame. + * @param frameId A positive, non-zero integer identifying the navigating frame. + * @param validatedUrl The validated URL that is being navigated to. + * @param isMainFrame Whether the load is happening for the main frame. + */ + public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) {} + + /** + * Notifies that the document has finished loading for the given frame. + * @param frameId A positive, non-zero integer identifying the navigating frame. + */ + public void documentLoadedInFrame(long frameId) {} + + /** + * Notifies that a navigation entry has been committed. + */ + public void navigationEntryCommitted() {} + + /** + * Called when an interstitial page gets attached to the tab content. + */ + public void didAttachInterstitialPage() {} + + /** + * Called when an interstitial page gets detached from the tab content. + */ + public void didDetachInterstitialPage() {} + + /** + * Called when the theme color was changed. + * @param color the new color in ARGB format + */ + public void didChangeThemeColor(int color) {} + + /** + * Called when we started navigation to the pending entry. + * @param url The URL that we are navigating to. + */ + public void didStartNavigationToPendingEntry(String url) {} + + /** + * Stop observing the web contents and clean up associated references. + */ + public void destroy() { + if (mWebContents == null) return; + final WebContents webContents = mWebContents.get(); + mWebContents = null; + if (webContents == null) return; + webContents.removeObserver(this); + } + + protected WebContentsObserver() {} +}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java b/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java index e339897..f7542b7 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java
@@ -13,6 +13,7 @@ import org.chromium.content.browser.test.util.CriteriaHelper; import org.chromium.content.browser.test.util.TouchCommon; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.content_shell_apk.ContentShellActivity; import org.chromium.content_shell_apk.ContentShellTestBase;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/WebContentsObserverAndroidTest.java b/content/public/android/javatests/src/org/chromium/content/browser/WebContentsObserverAndroidTest.java index b5ed7bf..0ab51f1 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/WebContentsObserverAndroidTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/WebContentsObserverAndroidTest.java
@@ -10,6 +10,7 @@ import org.chromium.content.browser.test.util.CallbackHelper; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.content_shell_apk.ContentShellActivity; import org.chromium.content_shell_apk.ContentShellTestBase;
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 67d2df7c..96c076a 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -230,8 +230,8 @@ int bridge_id, const GURL& requesting_frame, bool user_gesture, - const base::Callback<void(bool)>& result_callback) { - result_callback.Run(true); + const base::Callback<void(PermissionStatus)>& callback) { + callback.Run(PERMISSION_STATUS_DENIED); } PermissionStatus ContentBrowserClient::GetPermissionStatus(
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index c4ab6f3..c5c3942 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -434,7 +434,7 @@ int bridge_id, const GURL& requesting_frame, bool user_gesture, - const base::Callback<void(bool)>& result_callback); + const base::Callback<void(PermissionStatus)>& callback); virtual void CancelPermissionRequest(PermissionType permission, WebContents* web_contents,
diff --git a/content/public/browser/invalidate_type.h b/content/public/browser/invalidate_type.h index 975bb304..f85ec3d 100644 --- a/content/public/browser/invalidate_type.h +++ b/content/public/browser/invalidate_type.h
@@ -9,6 +9,11 @@ // Flags passed to the WebContentsDelegate.NavigationStateChanged to tell it // what has changed. Combine them to update more than one thing. +// +// A Java counterpart will be generated for this enum. +// GENERATED_JAVA_ENUM_PACKAGE: ( +// org.chromium.content_public.browser) +// GENERATED_JAVA_PREFIX_TO_STRIP: INVALIDATE_TYPE_ enum InvalidateTypes { INVALIDATE_TYPE_URL = 1 << 0, // The URL has changed. INVALIDATE_TYPE_TAB = 1 << 1, // The favicon, app icon, or crashed
diff --git a/content/public/browser/navigator_connect_service_factory.h b/content/public/browser/navigator_connect_service_factory.h index f66b2de..4a71f27 100644 --- a/content/public/browser/navigator_connect_service_factory.h +++ b/content/public/browser/navigator_connect_service_factory.h
@@ -24,7 +24,11 @@ // remains with the factory. It is assumed that for the passed // MessagePortDelegate implementation the route_id and message_port_id of a // connection are the same. - using ConnectCallback = base::Callback<void(MessagePortDelegate*)>; + // Pass true to |data_as_values| if the delegate expects to receive messages + // from the client encoded as base::Value instead of the normal serialization + // format. + using ConnectCallback = + base::Callback<void(MessagePortDelegate*, bool data_as_values)>; virtual ~NavigatorConnectServiceFactory() {}
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h index df89031..e0b9760e 100644 --- a/content/public/common/common_param_traits_macros.h +++ b/content/public/common/common_param_traits_macros.h
@@ -113,6 +113,7 @@ IPC_STRUCT_TRAITS_MEMBER(minimum_font_size) IPC_STRUCT_TRAITS_MEMBER(minimum_logical_font_size) IPC_STRUCT_TRAITS_MEMBER(default_encoding) + IPC_STRUCT_TRAITS_MEMBER(context_menu_on_mouse_up) IPC_STRUCT_TRAITS_MEMBER(javascript_enabled) IPC_STRUCT_TRAITS_MEMBER(web_security_enabled) IPC_STRUCT_TRAITS_MEMBER(javascript_can_open_windows_automatically)
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index 3b7d13b58..8d9bd67 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc
@@ -844,6 +844,9 @@ // Use the new surfaces system to handle compositor delegation. const char kUseSurfaces[] = "use-surfaces"; +// Disable the use of the new surfaces system to handle compositor delegation. +const char kDisableSurfaces[] = "disable-surfaces"; + // The contents of this flag are prepended to the utility process command line. // Useful values might be "valgrind" or "xterm -e gdb --args". const char kUtilityCmdPrefix[] = "utility-cmd-prefix";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index f792770d..a248681 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -231,6 +231,7 @@ CONTENT_EXPORT extern const char kUseMobileUserAgent[]; CONTENT_EXPORT extern const char kUseNormalPriorityForTileTaskWorkerThreads[]; extern const char kUseSurfaces[]; +CONTENT_EXPORT extern const char kDisableSurfaces[]; extern const char kUtilityCmdPrefix[]; CONTENT_EXPORT extern const char kUtilityProcess[]; extern const char kUtilityProcessAllowedDir[];
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc index 97b464e..1a4c116be 100644 --- a/content/public/common/web_preferences.cc +++ b/content/public/common/web_preferences.cc
@@ -86,6 +86,11 @@ minimum_font_size(0), minimum_logical_font_size(6), default_encoding("ISO-8859-1"), +#if defined(OS_WIN) + context_menu_on_mouse_up(true), +#else + context_menu_on_mouse_up(false), +#endif javascript_enabled(true), web_security_enabled(true), javascript_can_open_windows_automatically(true),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h index 250b546d..bb47acb 100644 --- a/content/public/common/web_preferences.h +++ b/content/public/common/web_preferences.h
@@ -83,6 +83,7 @@ int minimum_font_size; int minimum_logical_font_size; std::string default_encoding; + bool context_menu_on_mouse_up; bool javascript_enabled; bool web_security_enabled; bool javascript_can_open_windows_automatically;
diff --git a/content/public/renderer/BUILD.gn b/content/public/renderer/BUILD.gn index 5de959b..0ab2d33 100644 --- a/content/public/renderer/BUILD.gn +++ b/content/public/renderer/BUILD.gn
@@ -49,6 +49,7 @@ rebase_path(content_renderer_gypi_values.public_renderer_webrtc_sources, ".", "//content") + deps += [ "//third_party/webrtc" ] } if (enable_plugins) {
diff --git a/content/public/renderer/DEPS b/content/public/renderer/DEPS index f78d4a39..b80961c 100644 --- a/content/public/renderer/DEPS +++ b/content/public/renderer/DEPS
@@ -1,7 +1,7 @@ include_rules = [ "+content/public/child", "+media/base", - "+media/filters", + "+media/renderers", "+media/video", "+v8/include/v8.h", ]
diff --git a/content/public/renderer/document_state.h b/content/public/renderer/document_state.h index d388a8a9..d3d8c540 100644 --- a/content/public/renderer/document_state.h +++ b/content/public/renderer/document_state.h
@@ -161,8 +161,8 @@ was_fetched_via_proxy_ = value; } - net::HostPortPair proxy_server() const { return proxy_server_; } - void set_proxy_server(net::HostPortPair proxy_server) { + const net::HostPortPair& proxy_server() const { return proxy_server_; } + void set_proxy_server(const net::HostPortPair& proxy_server) { proxy_server_ = proxy_server; }
diff --git a/content/public/renderer/media_stream_api.cc b/content/public/renderer/media_stream_api.cc new file mode 100644 index 0000000..f8fd76d3 --- /dev/null +++ b/content/public/renderer/media_stream_api.cc
@@ -0,0 +1,125 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/renderer/media_stream_api.h" + +#include "base/base64.h" +#include "base/callback.h" +#include "base/rand_util.h" +#include "base/strings/utf_string_conversions.h" +#include "content/renderer/media/media_stream_audio_source.h" +#include "content/renderer/media/media_stream_video_capturer_source.h" +#include "content/renderer/media/media_stream_video_track.h" +#include "media/base/audio_capturer_source.h" +#include "media/base/video_capturer_source.h" +#include "third_party/WebKit/public/platform/WebMediaDeviceInfo.h" +#include "third_party/WebKit/public/platform/WebMediaStream.h" +#include "third_party/WebKit/public/platform/WebMediaStreamSource.h" +#include "third_party/WebKit/public/platform/WebURL.h" +#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" +#include "url/gurl.h" + +namespace content { + +namespace { + +blink::WebString MakeTrackId() { + std::string track_id; + base::Base64Encode(base::RandBytesAsString(64), &track_id); + return base::UTF8ToUTF16(track_id); +} + +} // namespace + +bool AddVideoTrackToMediaStream( + scoped_ptr<media::VideoCapturerSource> source, + bool is_remote, + bool is_readonly, + const std::string& media_stream_url) { + blink::WebMediaStream stream = + blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor( + GURL(media_stream_url)); + + if (stream.isNull()) { + LOG(ERROR) << "Stream not found"; + return false; + } + blink::WebString track_id = MakeTrackId(); + blink::WebMediaStreamSource webkit_source; + scoped_ptr<MediaStreamVideoSource> media_stream_source( + new MediaStreamVideoCapturerSource( + MediaStreamSource::SourceStoppedCallback(), + source.Pass())); + webkit_source.initialize( + track_id, + blink::WebMediaStreamSource::TypeVideo, + track_id, + is_remote, + is_readonly); + webkit_source.setExtraData(media_stream_source.get()); + + blink::WebMediaConstraints constraints; + constraints.initialize(); + stream.addTrack(MediaStreamVideoTrack::CreateVideoTrack( + media_stream_source.release(), + constraints, + MediaStreamVideoSource::ConstraintsCallback(), + true)); + return true; +} + +bool AddAudioTrackToMediaStream( + scoped_refptr<media::AudioCapturerSource> source, + const media::AudioParameters& params, + bool is_remote, + bool is_readonly, + const std::string& media_stream_url) { + DCHECK(params.IsValid()) << params.AsHumanReadableString(); + blink::WebMediaStream stream = + blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor( + GURL(media_stream_url)); + + if (stream.isNull()) { + LOG(ERROR) << "Stream not found"; + return false; + } + blink::WebMediaStreamSource webkit_source; + blink::WebString track_id = MakeTrackId(); + webkit_source.initialize( + track_id, + blink::WebMediaStreamSource::TypeAudio, + track_id, + is_remote, + is_readonly); + + MediaStreamAudioSource* audio_source( + new MediaStreamAudioSource( + -1, + StreamDeviceInfo(), + MediaStreamSource::SourceStoppedCallback(), + RenderThreadImpl::current()->GetPeerConnectionDependencyFactory())); + + blink::WebMediaConstraints constraints; + constraints.initialize(); + scoped_refptr<WebRtcAudioCapturer> capturer( + WebRtcAudioCapturer::CreateCapturer( + -1, + StreamDeviceInfo(), + constraints, + nullptr, + audio_source)); + capturer->SetCapturerSource(source, params); + audio_source->SetAudioCapturer(capturer); + webkit_source.setExtraData(audio_source); + + blink::WebMediaStreamTrack web_media_audio_track; + web_media_audio_track.initialize(webkit_source); + RenderThreadImpl::current()->GetPeerConnectionDependencyFactory()-> + CreateLocalAudioTrack(web_media_audio_track); + + stream.addTrack(web_media_audio_track); + return true; +} + +} // namespace content
diff --git a/content/public/renderer/media_stream_api.h b/content/public/renderer/media_stream_api.h new file mode 100644 index 0000000..71ce675 --- /dev/null +++ b/content/public/renderer/media_stream_api.h
@@ -0,0 +1,41 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_RENDERER_MEDIA_STREAM_API_H_ +#define CONTENT_PUBLIC_RENDERER_MEDIA_STREAM_API_H_ + +#include "content/common/content_export.h" +#include "media/base/audio_capturer_source.h" +#include "media/base/video_capturer_source.h" + +namespace blink { +class WebMediaStreamSource; +} + +namespace Media { +class AudioParameters; +} + +namespace content { + +// These two methods will initialize a WebMediaStreamSource object to take +// data from the provided audio or video capturer source. +// |is_remote| should be true if the source of the data is not a local device. +// |is_readonly| should be true if the format of the data cannot be changed by +// MediaTrackConstraints. +CONTENT_EXPORT bool AddVideoTrackToMediaStream( + scoped_ptr<media::VideoCapturerSource> source, + bool is_remote, + bool is_readonly, + const std::string& media_stream_url); +CONTENT_EXPORT bool AddAudioTrackToMediaStream( + scoped_refptr<media::AudioCapturerSource> source, + const media::AudioParameters& params, + bool is_remote, + bool is_readonly, + const std::string& media_stream_url); + +} // namespace content + +#endif // CONTENT_PUBLIC_RENDERER_MEDIA_STREAM_API_H_
diff --git a/content/public/renderer/video_encode_accelerator.cc b/content/public/renderer/video_encode_accelerator.cc index a8ad12b..b1ac143 100644 --- a/content/public/renderer/video_encode_accelerator.cc +++ b/content/public/renderer/video_encode_accelerator.cc
@@ -7,7 +7,7 @@ #include "base/task_runner_util.h" #include "content/common/gpu/client/gpu_video_encode_accelerator_host.h" #include "content/renderer/render_thread_impl.h" -#include "media/filters/gpu_video_accelerator_factories.h" +#include "media/renderers/gpu_video_accelerator_factories.h" namespace content {
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestWebContentsObserver.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestWebContentsObserver.java index 1862e30..f2e0262 100644 --- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestWebContentsObserver.java +++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestWebContentsObserver.java
@@ -4,11 +4,11 @@ package org.chromium.content.browser.test.util; -import org.chromium.content.browser.WebContentsObserver; import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper; import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageStartedHelper; import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; /** * The default WebContentsObserver used by ContentView tests. The below callbacks can be
diff --git a/content/public/test/test_web_contents_factory.h b/content/public/test/test_web_contents_factory.h new file mode 100644 index 0000000..8b48f9ef --- /dev/null +++ b/content/public/test/test_web_contents_factory.h
@@ -0,0 +1,52 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_TEST_TEST_WEB_CONTENTS_FACTORY_H_ +#define CONTENT_PUBLIC_TEST_TEST_WEB_CONTENTS_FACTORY_H_ + +#include "base/macros.h" +#include "base/memory/scoped_vector.h" + +namespace content { +class BrowserContext; +class RenderViewHostTestEnabler; +class WebContents; + +// 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? ;) +// TODO(devlin): The API is currently a bit sparse; there may need to be methods +// to, e.g., delete/close a web contents, access existing web contents, etc. +// These can be added as-needed. +class TestWebContentsFactory { + public: + TestWebContentsFactory(); + ~TestWebContentsFactory(); + + // Creates a new WebContents with the given |context|, and returns it. + // Ownership remains with the TestWebContentsFactory. + WebContents* CreateWebContents(BrowserContext* context); + + private: + // The test factory (and friends) for creating test web contents. + scoped_ptr<RenderViewHostTestEnabler> rvh_enabler_; + + // The vector of web contents that this class created. + ScopedVector<WebContents> web_contents_; + + // True if the factory initialized aura (and should thus tear it down). + bool tear_down_aura_; + + DISALLOW_COPY_AND_ASSIGN(TestWebContentsFactory); +}; + +} // namespace content + +#endif // CONTENT_PUBLIC_TEST_TEST_WEB_CONTENTS_FACTORY_H_
diff --git a/content/public/test/web_contents_observer_sanity_checker.cc b/content/public/test/web_contents_observer_sanity_checker.cc index e59998b..9b0fdcc 100644 --- a/content/public/test/web_contents_observer_sanity_checker.cc +++ b/content/public/test/web_contents_observer_sanity_checker.cc
@@ -4,7 +4,6 @@ #include "content/public/test/web_contents_observer_sanity_checker.h" -#include "base/debug/stack_trace.h" #include "base/strings/stringprintf.h" #include "content/common/frame_messages.h" #include "content/public/browser/render_frame_host.h" @@ -80,8 +79,27 @@ CHECK(new_host); CHECK_NE(new_host, old_host); - // TODO(nasko): Implement consistency checking for RenderFrameHostChanged - // in follow up CL. + if (old_host) { + std::pair<int, int> routing_pair = + std::make_pair(old_host->GetProcess()->GetID(), + old_host->GetRoutingID()); + bool old_did_exist = !!current_hosts_.erase(routing_pair); + if (!old_did_exist) { + CHECK(false) + << "RenderFrameHostChanged called with old host that did not exist:" + << Format(old_host); + } + } + + std::pair<int, int> routing_pair = + std::make_pair(new_host->GetProcess()->GetID(), + new_host->GetRoutingID()); + bool host_exists = !current_hosts_.insert(routing_pair).second; + if (host_exists) { + CHECK(false) + << "RenderFrameHostChanged called more than once for routing pair:" + << Format(new_host); + } } void WebContentsObserverSanityChecker::FrameDeleted(
diff --git a/content/public/test/web_contents_observer_sanity_checker.h b/content/public/test/web_contents_observer_sanity_checker.h index b8c3b61..2fab3ab 100644 --- a/content/public/test/web_contents_observer_sanity_checker.h +++ b/content/public/test/web_contents_observer_sanity_checker.h
@@ -87,6 +87,7 @@ void AssertRenderFrameExists(RenderFrameHost* render_frame_host); void AssertMainFrameExists(); + std::set<std::pair<int, int>> current_hosts_; std::set<std::pair<int, int>> live_routes_; std::set<std::pair<int, int>> deleted_routes_;
diff --git a/content/renderer/gpu/frame_swap_message_queue.cc b/content/renderer/gpu/frame_swap_message_queue.cc index bf91dd8..5a31382 100644 --- a/content/renderer/gpu/frame_swap_message_queue.cc +++ b/content/renderer/gpu/frame_swap_message_queue.cc
@@ -161,10 +161,14 @@ case cc::SwapPromise::SWAP_FAILS: case cc::SwapPromise::COMMIT_NO_UPDATE: swap_queue_->DrainMessages(source_frame_number, messages); - // fallthrough - case cc::SwapPromise::COMMIT_FAILS: visual_state_queue_->DrainMessages(source_frame_number, messages); break; + case cc::SwapPromise::COMMIT_FAILS: + // Do not queue any responses here. + // If COMMIT_FAILS the renderer is shutting down, which will + // result in the RenderFrameHostImpl destructor firing the + // remaining response callbacks itself. + break; default: NOTREACHED(); }
diff --git a/content/renderer/gpu/frame_swap_message_queue_unittest.cc b/content/renderer/gpu/frame_swap_message_queue_unittest.cc index 0b0ba8d..dc802c0 100644 --- a/content/renderer/gpu/frame_swap_message_queue_unittest.cc +++ b/content/renderer/gpu/frame_swap_message_queue_unittest.cc
@@ -237,13 +237,11 @@ QueueVisualStateMessage(3, CloneMessage(third_message_)); queue_->DidNotSwap(2, cc::SwapPromise::COMMIT_FAILS, &messages); - ASSERT_EQ(1u, messages.size()); - ASSERT_TRUE(HasMessageForId(messages, second_message_.routing_id())); + ASSERT_EQ(0u, messages.size()); messages.clear(); queue_->DidNotSwap(3, cc::SwapPromise::COMMIT_FAILS, &messages); - ASSERT_EQ(1u, messages.size()); - ASSERT_TRUE(HasMessageForId(messages, third_message_.routing_id())); + ASSERT_EQ(0u, messages.size()); messages.clear(); DrainMessages(1, &messages);
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.cc b/content/renderer/gpu/gpu_benchmarking_extension.cc index 68221886..1f2369d 100644 --- a/content/renderer/gpu/gpu_benchmarking_extension.cc +++ b/content/renderer/gpu/gpu_benchmarking_extension.cc
@@ -14,6 +14,7 @@ #include "cc/layers/layer.h" #include "content/common/input/synthetic_gesture_params.h" #include "content/common/input/synthetic_pinch_gesture_params.h" +#include "content/common/input/synthetic_smooth_drag_gesture_params.h" #include "content/common/input/synthetic_smooth_scroll_gesture_params.h" #include "content/common/input/synthetic_tap_gesture_params.h" #include "content/public/child/v8_value_converter.h" @@ -381,6 +382,48 @@ return true; } +bool BeginSmoothDrag(v8::Isolate* isolate, + float start_x, + float start_y, + float end_x, + float end_y, + v8::Handle<v8::Function> callback, + int gesture_source_type, + int speed_in_pixels_s) { + GpuBenchmarkingContext context; + if (!context.Init(false)) + return false; + scoped_refptr<CallbackAndContext> callback_and_context = + new CallbackAndContext(isolate, callback, + context.web_frame()->mainWorldScriptContext()); + + scoped_ptr<SyntheticSmoothDragGestureParams> gesture_params( + new SyntheticSmoothDragGestureParams); + + // Convert coordinates from CSS pixels to density independent pixels (DIPs). + float page_scale_factor = context.web_view()->pageScaleFactor(); + + gesture_params->start_point.SetPoint(start_x * page_scale_factor, + start_y * page_scale_factor); + gfx::PointF end_point(end_x * page_scale_factor, + end_y * page_scale_factor); + gfx::Vector2dF distance = gesture_params->start_point - end_point; + gesture_params->distances.push_back(distance); + gesture_params->speed_in_pixels_s = speed_in_pixels_s * page_scale_factor; + gesture_params->gesture_source_type = + static_cast<SyntheticGestureParams::GestureSourceType>( + gesture_source_type); + + // TODO(nduca): If the render_view_impl is destroyed while the gesture is in + // progress, we will leak the callback and context. This needs to be fixed, + // somehow. + context.render_view_impl()->QueueSyntheticGesture( + gesture_params.Pass(), + base::Bind(&OnSyntheticGestureCompleted, callback_and_context)); + + return true; +} + } // namespace gin::WrapperInfo GpuBenchmarking::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -425,6 +468,7 @@ .SetMethod("gestureSourceTypeSupported", &GpuBenchmarking::GestureSourceTypeSupported) .SetMethod("smoothScrollBy", &GpuBenchmarking::SmoothScrollBy) + .SetMethod("smoothDrag", &GpuBenchmarking::SmoothDrag) .SetMethod("swipe", &GpuBenchmarking::Swipe) .SetMethod("scrollBounce", &GpuBenchmarking::ScrollBounce) // TODO(dominikg): Remove once JS interface changes have rolled into @@ -529,6 +573,39 @@ start_y); } +bool GpuBenchmarking::SmoothDrag(gin::Arguments* args) { + GpuBenchmarkingContext context; + if (!context.Init(true)) + return false; + + float start_x; + float start_y; + float end_x; + float end_y; + v8::Handle<v8::Function> callback; + int gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT; + int speed_in_pixels_s = 800; + + if (!GetArg(args, &start_x) || + !GetArg(args, &start_y) || + !GetArg(args, &end_x) || + !GetArg(args, &end_y) || + !GetOptionalArg(args, &callback) || + !GetOptionalArg(args, &gesture_source_type) || + !GetOptionalArg(args, &speed_in_pixels_s)) { + return false; + } + + return BeginSmoothDrag(args->isolate(), + start_x, + start_y, + end_x, + end_y, + callback, + gesture_source_type, + speed_in_pixels_s); +} + bool GpuBenchmarking::Swipe(gin::Arguments* args) { GpuBenchmarkingContext context; if (!context.Init(true))
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.h b/content/renderer/gpu/gpu_benchmarking_extension.h index 33e10ea..bbfb015b 100644 --- a/content/renderer/gpu/gpu_benchmarking_extension.h +++ b/content/renderer/gpu/gpu_benchmarking_extension.h
@@ -45,6 +45,7 @@ void PrintToSkPicture(v8::Isolate* isolate, const std::string& dirname); bool GestureSourceTypeSupported(int gesture_source_type); bool SmoothScrollBy(gin::Arguments* args); + bool SmoothDrag(gin::Arguments* args); bool Swipe(gin::Arguments* args); bool ScrollBounce(gin::Arguments* args); bool PinchBy(gin::Arguments* args);
diff --git a/content/renderer/gpu/queue_message_swap_promise_unittest.cc b/content/renderer/gpu/queue_message_swap_promise_unittest.cc index c79a6df..7590490f 100644 --- a/content/renderer/gpu/queue_message_swap_promise_unittest.cc +++ b/content/renderer/gpu/queue_message_swap_promise_unittest.cc
@@ -294,8 +294,34 @@ } TEST_F(QueueMessageSwapPromiseTest, - VisalStateSwapPromiseDidNotSwapCommitFails) { - VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::COMMIT_FAILS); + VisualStateSwapPromiseDidNotSwapCommitFails) { + // COMMIT_FAILS is treated differently: + // If we fail to swap with COMMIT_FAILS, then the renderer is + // shutting down, which implies that the RenderFrameHostImpl + // destructor will eventually be called, firing the remaining + // response callbacks (with swap_success = false) itself. + QueueMessageData data[] = { + /* { policy, source_frame_number } */ + {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1}, + {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1}, + {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 2}, + }; + QueueMessages(data, arraysize(data)); + + promises_[0]->DidNotSwap(cc::SwapPromise::COMMIT_FAILS); + ASSERT_FALSE(promises_[1]); + EXPECT_TRUE(NextSwapMessages().empty()); + EXPECT_EQ(0u, DirectSendMessages().size()); + EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[0])); + EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[1])); + EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[2])); + + promises_[2]->DidNotSwap(cc::SwapPromise::COMMIT_FAILS); + EXPECT_TRUE(NextSwapMessages().empty()); + EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[2])); + + EXPECT_TRUE(NextSwapMessages().empty()); + EXPECT_FALSE(frame_swap_message_queue_->Empty()); } TEST_F(QueueMessageSwapPromiseTest, VisalStateSwapPromiseDidNotSwapSwapFails) {
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc index f844d31..c01231e 100644 --- a/content/renderer/gpu/render_widget_compositor.cc +++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -772,10 +772,6 @@ layer_tree_host_->SetTopControlsHeight(height, shrink); } -void RenderWidgetCompositor::setTopControlsContentOffset(float offset) { - setTopControlsShownRatio(offset); -} - void RenderWidgetCompositor::setTopControlsShownRatio(float ratio) { layer_tree_host_->SetTopControlsShownRatio(ratio); }
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h index 239362c..240a043 100644 --- a/content/renderer/gpu/render_widget_compositor.h +++ b/content/renderer/gpu/render_widget_compositor.h
@@ -131,8 +131,6 @@ bool animate); virtual void setTopControlsHeight(float height, bool shrink); virtual void setTopControlsShownRatio(float); - // TODO(aelias): Delete after Blink roll - virtual void setTopControlsContentOffset(float); // cc::LayerTreeHostClient implementation. void WillBeginMainFrame() override;
diff --git a/content/renderer/java/gin_java_bridge_object.cc b/content/renderer/java/gin_java_bridge_object.cc index 7c43276a..8786cff 100644 --- a/content/renderer/java/gin_java_bridge_object.cc +++ b/content/renderer/java/gin_java_bridge_object.cc
@@ -66,7 +66,8 @@ : gin::NamedPropertyInterceptor(isolate, this), dispatcher_(dispatcher), object_id_(object_id), - converter_(new GinJavaBridgeValueConverter()) { + converter_(new GinJavaBridgeValueConverter()), + template_cache_(isolate) { } GinJavaBridgeObject::~GinJavaBridgeObject() { @@ -91,15 +92,10 @@ } known_methods_[property] = dispatcher_->HasJavaMethod(object_id_, property); } - if (known_methods_[property]) { - return gin::CreateFunctionTemplate( - isolate, - base::Bind(&GinJavaBridgeObject::InvokeMethod, - base::Unretained(this), - property))->GetFunction(); - } else { + if (known_methods_[property]) + return GetFunctionTemplate(isolate, property)->GetFunction(); + else return v8::Local<v8::Value>(); - } } std::vector<std::string> GinJavaBridgeObject::EnumerateNamedProperties( @@ -110,6 +106,19 @@ return std::vector<std::string> (method_names.begin(), method_names.end()); } +v8::Local<v8::FunctionTemplate> GinJavaBridgeObject::GetFunctionTemplate( + v8::Isolate* isolate, + const std::string& name) { + v8::Local<v8::FunctionTemplate> function_template = template_cache_.Get(name); + if (!function_template.IsEmpty()) + return function_template; + function_template = gin::CreateFunctionTemplate( + isolate, base::Bind(&GinJavaBridgeObject::InvokeMethod, + base::Unretained(this), name)); + template_cache_.Set(name, function_template); + return function_template; +} + v8::Handle<v8::Value> GinJavaBridgeObject::InvokeMethod( const std::string& name, gin::Arguments* args) {
diff --git a/content/renderer/java/gin_java_bridge_object.h b/content/renderer/java/gin_java_bridge_object.h index 5c729b8..e119c88 100644 --- a/content/renderer/java/gin_java_bridge_object.h +++ b/content/renderer/java/gin_java_bridge_object.h
@@ -14,6 +14,7 @@ #include "gin/interceptor.h" #include "gin/object_template_builder.h" #include "gin/wrappable.h" +#include "v8/include/v8-util.h" namespace blink { class WebFrame; @@ -55,6 +56,8 @@ GinJavaBridgeDispatcher::ObjectID object_id); ~GinJavaBridgeObject() override; + v8::Local<v8::FunctionTemplate> GetFunctionTemplate(v8::Isolate* isolate, + const std::string& name); v8::Handle<v8::Value> InvokeMethod(const std::string& name, gin::Arguments* args); @@ -62,6 +65,7 @@ GinJavaBridgeDispatcher::ObjectID object_id_; scoped_ptr<GinJavaBridgeValueConverter> converter_; std::map<std::string, bool> known_methods_; + v8::StdPersistentValueMap<std::string, v8::FunctionTemplate> template_cache_; DISALLOW_COPY_AND_ASSIGN(GinJavaBridgeObject); };
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc index a5bf0b61..25813a179 100644 --- a/content/renderer/media/android/media_source_delegate.cc +++ b/content/renderer/media/android/media_source_delegate.cc
@@ -152,7 +152,8 @@ encrypted_media_init_data_cb, const media::SetDecryptorReadyCB& set_decryptor_ready_cb, const UpdateNetworkStateCB& update_network_state_cb, - const DurationChangeCB& duration_change_cb) { + const DurationChangeCB& duration_change_cb, + const base::Closure& waiting_for_decryption_key_cb) { DCHECK(main_task_runner_->BelongsToCurrentThread()); DCHECK(!media_source_opened_cb.is_null()); media_source_opened_cb_ = media_source_opened_cb; @@ -160,6 +161,7 @@ set_decryptor_ready_cb_ = media::BindToCurrentLoop(set_decryptor_ready_cb); update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb); duration_change_cb_ = duration_change_cb; + waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; access_unit_size_ = kAccessUnitSizeForMediaSource; chunk_demuxer_.reset(new media::ChunkDemuxer( @@ -521,7 +523,8 @@ DCHECK(!set_decryptor_ready_cb_.is_null()); audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( - media_task_runner_, set_decryptor_ready_cb_)); + media_task_runner_, set_decryptor_ready_cb_, + waiting_for_decryption_key_cb_)); audio_decrypting_demuxer_stream_->Initialize( audio_stream_, base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone, @@ -534,7 +537,8 @@ DCHECK(!set_decryptor_ready_cb_.is_null()); video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( - media_task_runner_, set_decryptor_ready_cb_)); + media_task_runner_, set_decryptor_ready_cb_, + waiting_for_decryption_key_cb_)); video_decrypting_demuxer_stream_->Initialize( video_stream_, base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone,
diff --git a/content/renderer/media/android/media_source_delegate.h b/content/renderer/media/android/media_source_delegate.h index c8eaade..666b380 100644 --- a/content/renderer/media/android/media_source_delegate.h +++ b/content/renderer/media/android/media_source_delegate.h
@@ -62,7 +62,8 @@ encrypted_media_init_data_cb, const media::SetDecryptorReadyCB& set_decryptor_ready_cb, const UpdateNetworkStateCB& update_network_state_cb, - const DurationChangeCB& duration_change_cb); + const DurationChangeCB& duration_change_cb, + const base::Closure& waiting_for_decryption_key_cb); blink::WebTimeRanges Buffered() const; size_t DecodedFrameCount() const; @@ -198,6 +199,7 @@ MediaSourceOpenedCB media_source_opened_cb_; media::Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb_; + base::Closure waiting_for_decryption_key_cb_; // Temporary for EME v0.1. In the future the init data type should be passed // through GenerateKeyRequest() directly from WebKit.
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc index fe32f058..d3b0dcb 100644 --- a/content/renderer/media/android/webmediaplayer_android.cc +++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -313,6 +313,8 @@ base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState, weak_factory_.GetWeakPtr()), base::Bind(&WebMediaPlayerAndroid::OnDurationChanged, + weak_factory_.GetWeakPtr()), + base::Bind(&WebMediaPlayerAndroid::OnWaitingForDecryptionKey, weak_factory_.GetWeakPtr())); InitializePlayer(url_, frame_->document().firstPartyForCookies(), true, demuxer_client_id); @@ -1759,6 +1761,15 @@ vector_as_array(&init_data), init_data.size()); } +void WebMediaPlayerAndroid::OnWaitingForDecryptionKey() { + client_->didBlockPlaybackWaitingForKey(); + + // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called + // when a key has been successfully added (e.g. OnSessionKeysChange() with + // |has_additional_usable_key| = true). http://crbug.com/461903 + client_->didResumePlaybackBlockedForKey(); +} + void WebMediaPlayerAndroid::SetCdmInternal( const media::CdmAttachedCB& cdm_attached_cb) { DCHECK(cdm_context_ && is_player_initialized_);
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h index 314d7ee..8d18a26 100644 --- a/content/renderer/media/android/webmediaplayer_android.h +++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -258,6 +258,10 @@ void OnEncryptedMediaInitData(const std::string& init_data_type, const std::vector<uint8>& init_data); + // Called when a decoder detects that the key needed to decrypt the stream + // is not available. + void OnWaitingForDecryptionKey(); + protected: // Helper method to update the playing state. void UpdatePlayingState(bool is_playing_);
diff --git a/content/renderer/media/media_stream_video_capture_source_unittest.cc b/content/renderer/media/media_stream_video_capture_source_unittest.cc index b6f4833c..f01f42f 100644 --- a/content/renderer/media/media_stream_video_capture_source_unittest.cc +++ b/content/renderer/media/media_stream_video_capture_source_unittest.cc
@@ -172,24 +172,30 @@ class FakeMediaStreamVideoSink : public MediaStreamVideoSink { public: FakeMediaStreamVideoSink(base::TimeTicks* capture_time, + media::VideoFrameMetadata* metadata, base::Closure got_frame_cb) : capture_time_(capture_time), + metadata_(metadata), got_frame_cb_(got_frame_cb) { } void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& capture_time) { *capture_time_ = capture_time; + metadata_->Clear(); + base::DictionaryValue tmp; + frame->metadata()->MergeInternalValuesInto(&tmp); + metadata_->MergeInternalValuesFrom(tmp); base::ResetAndReturn(&got_frame_cb_).Run(); } private: - base::TimeTicks* capture_time_; + base::TimeTicks* const capture_time_; + media::VideoFrameMetadata* const metadata_; base::Closure got_frame_cb_; }; -TEST_F(MediaStreamVideoCapturerSourceTest, CaptureTime) { +TEST_F(MediaStreamVideoCapturerSourceTest, CaptureTimeAndMetadataPlumbing) { StreamDeviceInfo device_info; device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE; InitWithDeviceInfo(device_info); @@ -213,23 +219,28 @@ base::TimeTicks reference_capture_time = base::TimeTicks::FromInternalValue(60013); base::TimeTicks capture_time; + media::VideoFrameMetadata metadata; FakeMediaStreamVideoSink fake_sink( &capture_time, + &metadata, media::BindToCurrentLoop(run_loop.QuitClosure())); FakeMediaStreamVideoSink::AddToVideoTrack( &fake_sink, base::Bind(&FakeMediaStreamVideoSink::OnVideoFrame, base::Unretained(&fake_sink)), track); + const scoped_refptr<media::VideoFrame> frame = + media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2)); + frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, 30.0); child_process_->io_message_loop()->PostTask( - FROM_HERE, - base::Bind(deliver_frame_cb, - media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2)), - media::VideoCaptureFormat(), - reference_capture_time)); + FROM_HERE, base::Bind(deliver_frame_cb, frame, reference_capture_time)); run_loop.Run(); FakeMediaStreamVideoSink::RemoveFromVideoTrack(&fake_sink, track); EXPECT_EQ(reference_capture_time, capture_time); + double metadata_value; + EXPECT_TRUE(metadata.GetDouble(media::VideoFrameMetadata::FRAME_RATE, + &metadata_value)); + EXPECT_EQ(30.0, metadata_value); } } // namespace content
diff --git a/content/renderer/media/media_stream_video_source.cc b/content/renderer/media/media_stream_video_source.cc index e2379451..6e501215 100644 --- a/content/renderer/media/media_stream_video_source.cc +++ b/content/renderer/media/media_stream_video_source.cc
@@ -39,11 +39,6 @@ MediaStreamVideoSource::kMinFrameRate, }; -const int MediaStreamVideoSource::kDefaultWidth = 640; -const int MediaStreamVideoSource::kDefaultHeight = 480; -const int MediaStreamVideoSource::kDefaultFrameRate = 30; -const int MediaStreamVideoSource::kUnknownFrameRate = 0; - namespace { // Google-specific key prefix. Constraints with this prefix are ignored if they @@ -209,11 +204,10 @@ while (format_it != formats->end()) { // Modify the format_it to fulfill the constraint if possible. // Delete it otherwise. - if (!UpdateFormatForConstraint(constraint, mandatory, &(*format_it))) { + if (!UpdateFormatForConstraint(constraint, mandatory, &(*format_it))) format_it = formats->erase(format_it); - } else { + else ++format_it; - } } } @@ -222,9 +216,8 @@ const blink::WebMediaConstraints& constraints, const media::VideoCaptureFormats& supported_formats, blink::WebString* unsatisfied_constraint) { - if (constraints.isNull()) { + if (constraints.isNull()) return supported_formats; - } double max_aspect_ratio; double min_aspect_ratio; @@ -291,9 +284,8 @@ for (size_t i = 0; i < optional.size(); ++i) { media::VideoCaptureFormats current_candidates = candidates; FilterFormatsByConstraint(optional[i], false, ¤t_candidates); - if (!current_candidates.empty()) { + if (!current_candidates.empty()) candidates = current_candidates; - } } // We have done as good as we can to filter the supported resolutions. @@ -307,7 +299,7 @@ media::VideoCaptureFormats::const_iterator best_it = formats.begin(); int best_diff = std::numeric_limits<int>::max(); for (; it != formats.end(); ++it) { - int diff = abs(area - it->frame_size.width() * it->frame_size.height()); + const int diff = abs(area - it->frame_size.GetArea()); if (diff < best_diff) { best_diff = diff; best_it = it; @@ -334,8 +326,10 @@ *capture_format = GetBestFormatBasedOnArea( formats, - std::min(max_width, MediaStreamVideoSource::kDefaultWidth) * - std::min(max_height, MediaStreamVideoSource::kDefaultHeight)); + std::min(max_width, + static_cast<int>(MediaStreamVideoSource::kDefaultWidth)) * + std::min(max_height, + static_cast<int>(MediaStreamVideoSource::kDefaultHeight))); } } // anonymous namespace @@ -348,8 +342,8 @@ // static bool MediaStreamVideoSource::IsConstraintSupported(const std::string& name) { - for (size_t i = 0; i < arraysize(kSupportedConstraints); ++i) { - if (kSupportedConstraints[i] == name) + for (const char* constraint : kSupportedConstraints) { + if (constraint == name) return true; } return false; @@ -492,11 +486,9 @@ media::VideoCaptureFormat* best_format) { DCHECK(CalledOnValidThread()); // Find the first constraints that we can fulfill. - for (std::vector<RequestedConstraints>::iterator request_it = - requested_constraints_.begin(); - request_it != requested_constraints_.end(); ++request_it) { + for (const auto& request : requested_constraints_) { const blink::WebMediaConstraints& requested_constraints = - request_it->constraints; + request.constraints; // If the source doesn't support capability enumeration it is still ok if // no mandatory constraints have been specified. That just means that @@ -548,15 +540,15 @@ std::vector<RequestedConstraints> callbacks; callbacks.swap(requested_constraints_); - for (std::vector<RequestedConstraints>::iterator it = callbacks.begin(); - it != callbacks.end(); ++it) { + for (const auto& request : callbacks) { MediaStreamRequestResult result = MEDIA_DEVICE_OK; blink::WebString unsatisfied_constraint; - if (HasMandatoryConstraints(it->constraints) && - FilterFormats(it->constraints, formats, - &unsatisfied_constraint).empty()) + if (HasMandatoryConstraints(request.constraints) && + FilterFormats(request.constraints, formats, + &unsatisfied_constraint).empty()) { result = MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED; + } if (state_ != STARTED && result == MEDIA_DEVICE_OK) result = MEDIA_DEVICE_TRACK_START_FAILURE; @@ -564,17 +556,17 @@ if (result == MEDIA_DEVICE_OK) { int max_width; int max_height; - GetDesiredMaxWidthAndHeight(it->constraints, &max_width, &max_height); + GetDesiredMaxWidthAndHeight(request.constraints, &max_width, &max_height); double max_aspect_ratio; double min_aspect_ratio; - GetDesiredMinAndMaxAspectRatio(it->constraints, + GetDesiredMinAndMaxAspectRatio(request.constraints, &min_aspect_ratio, &max_aspect_ratio); double max_frame_rate = 0.0f; - GetConstraintValueAsDouble(it->constraints, + GetConstraintValueAsDouble(request.constraints, kMaxFrameRate, &max_frame_rate); - track_adapter_->AddTrack(it->track, it->frame_callback, + track_adapter_->AddTrack(request.track, request.frame_callback, max_width, max_height, min_aspect_ratio, max_aspect_ratio, max_frame_rate); @@ -582,8 +574,8 @@ DVLOG(3) << "FinalizeAddTrack() result " << result; - if (!it->callback.is_null()) { - it->callback.Run(this, result, unsatisfied_constraint); + if (!request.callback.is_null()) { + request.callback.Run(this, result, unsatisfied_constraint); } } } @@ -594,10 +586,8 @@ DCHECK(CalledOnValidThread()); if (!owner().isNull()) owner().setReadyState(state); - for (std::vector<MediaStreamVideoTrack*>::iterator it = tracks_.begin(); - it != tracks_.end(); ++it) { - (*it)->OnReadyStateChanged(state); - } + for (const auto& track : tracks_) + track->OnReadyStateChanged(state); } void MediaStreamVideoSource::SetMutedState(bool muted_state) {
diff --git a/content/renderer/media/media_stream_video_source.h b/content/renderer/media/media_stream_video_source.h index ba66e43..4d0dba1 100644 --- a/content/renderer/media/media_stream_video_source.h +++ b/content/renderer/media/media_stream_video_source.h
@@ -76,12 +76,15 @@ static const char kMaxFrameRate[]; // maxFrameRate static const char kMinFrameRate[]; // minFrameRate - // Default resolution. If no constraints are specified and the delegate - // support it, this is the resolution that will be used. - static const int kDefaultWidth; - static const int kDefaultHeight; - static const int kDefaultFrameRate; - static const int kUnknownFrameRate; + enum { + // Default resolution. If no constraints are specified and the delegate + // support it, this is the resolution that will be used. + kDefaultWidth = 640, + kDefaultHeight = 480, + + kDefaultFrameRate = 30, + kUnknownFrameRate = 0, + }; protected: void DoStopSource() override;
diff --git a/content/renderer/media/media_stream_video_track.cc b/content/renderer/media/media_stream_video_track.cc index 04d8817..8a049a6 100644 --- a/content/renderer/media/media_stream_video_track.cc +++ b/content/renderer/media/media_stream_video_track.cc
@@ -45,7 +45,6 @@ // Triggers all registered callbacks with |frame|, |format| and // |estimated_capture_time| as parameters. Must be called on the IO-thread. void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time); private: @@ -145,16 +144,12 @@ void MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO( const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time) { DCHECK(io_message_loop_->BelongsToCurrentThread()); const scoped_refptr<media::VideoFrame>& video_frame = enabled_ ? frame : GetBlackFrame(frame); - - for (std::vector<VideoIdCallbackPair>::iterator it = callbacks_.begin(); - it != callbacks_.end(); ++it) { - it->second.Run(video_frame, format, estimated_capture_time); - } + for (const auto& entry : callbacks_) + entry.second.Run(video_frame, estimated_capture_time); } const scoped_refptr<media::VideoFrame>&
diff --git a/content/renderer/media/media_stream_video_track_unittest.cc b/content/renderer/media/media_stream_video_track_unittest.cc index eed4fa29..2fe85039 100644 --- a/content/renderer/media/media_stream_video_track_unittest.cc +++ b/content/renderer/media/media_stream_video_track_unittest.cc
@@ -139,7 +139,6 @@ void CheckThreadVideoFrameReceiver( CheckThreadHelper* helper, const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time) { // Do nothing. }
diff --git a/content/renderer/media/mock_media_stream_video_sink.cc b/content/renderer/media/mock_media_stream_video_sink.cc index 7a054ab3..2ded48a 100644 --- a/content/renderer/media/mock_media_stream_video_sink.cc +++ b/content/renderer/media/mock_media_stream_video_sink.cc
@@ -29,7 +29,6 @@ void MockMediaStreamVideoSink::DeliverVideoFrame( const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time) { last_frame_ = frame; ++number_of_frames_;
diff --git a/content/renderer/media/mock_media_stream_video_sink.h b/content/renderer/media/mock_media_stream_video_sink.h index 2f59fcf..e82020b5 100644 --- a/content/renderer/media/mock_media_stream_video_sink.h +++ b/content/renderer/media/mock_media_stream_video_sink.h
@@ -38,10 +38,8 @@ blink::WebMediaStreamSource::ReadyState state() const { return state_; } private: - void DeliverVideoFrame( - const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, - const base::TimeTicks& estimated_capture_time); + void DeliverVideoFrame(const scoped_refptr<media::VideoFrame>& frame, + const base::TimeTicks& estimated_capture_time); int number_of_frames_; bool enabled_;
diff --git a/content/renderer/media/mock_media_stream_video_source.cc b/content/renderer/media/mock_media_stream_video_source.cc index 19f7b6f..b99e4c3 100644 --- a/content/renderer/media/mock_media_stream_video_source.cc +++ b/content/renderer/media/mock_media_stream_video_source.cc
@@ -78,17 +78,7 @@ DCHECK(!frame_callback_.is_null()); io_message_loop()->PostTask( FROM_HERE, - base::Bind(&MockMediaStreamVideoSource::DeliverVideoFrameOnIO, - base::Unretained(this), frame, format_, - base::TimeTicks(), frame_callback_)); -} - -void MockMediaStreamVideoSource::DeliverVideoFrameOnIO( - const scoped_refptr<media::VideoFrame>& frame, - media::VideoCaptureFormat format, - const base::TimeTicks& estimated_capture_time, - const VideoCaptureDeliverFrameCB& frame_callback) { - frame_callback.Run(frame, format, estimated_capture_time); + base::Bind(frame_callback_, frame, base::TimeTicks())); } } // namespace content
diff --git a/content/renderer/media/mock_media_stream_video_source.h b/content/renderer/media/mock_media_stream_video_source.h index 9602b2f..0ae7507 100644 --- a/content/renderer/media/mock_media_stream_video_source.h +++ b/content/renderer/media/mock_media_stream_video_source.h
@@ -50,11 +50,6 @@ } protected: - void DeliverVideoFrameOnIO(const scoped_refptr<media::VideoFrame>& frame, - media::VideoCaptureFormat format, - const base::TimeTicks& estimated_capture_time, - const VideoCaptureDeliverFrameCB& frame_callback); - // Implements MediaStreamVideoSource. virtual void GetCurrentSupportedFormats( int max_requested_height,
diff --git a/content/renderer/media/mock_peer_connection_impl.cc b/content/renderer/media/mock_peer_connection_impl.cc index fa1796d..08a58b7 100644 --- a/content/renderer/media/mock_peer_connection_impl.cc +++ b/content/renderer/media/mock_peer_connection_impl.cc
@@ -186,8 +186,8 @@ webrtc::StatsReport report2(webrtc::StatsReport::NewTypedId( webrtc::StatsReport::kStatsReportTypeSession, "nontrack").Pass()); report1.set_timestamp(42); - report1.AddValue(webrtc::StatsReport::kStatsValueNameFingerprint, - "trackvalue"); + report1.AddString(webrtc::StatsReport::kStatsValueNameFingerprint, + "trackvalue"); webrtc::StatsReports reports; reports.push_back(&report1); @@ -196,8 +196,8 @@ // If selector is not given, we pass back two. if (!track) { report2.set_timestamp(44); - report2.AddValue(webrtc::StatsReport::kStatsValueNameFingerprintAlgorithm, - "somevalue"); + report2.AddString(webrtc::StatsReport::kStatsValueNameFingerprintAlgorithm, + "somevalue"); reports.push_back(&report2); }
diff --git a/content/renderer/media/peer_connection_tracker.cc b/content/renderer/media/peer_connection_tracker.cc index 2075cdd0..12574df 100644 --- a/content/renderer/media/peer_connection_tracker.cc +++ b/content/renderer/media/peer_connection_tracker.cc
@@ -216,8 +216,8 @@ dict->Set("values", values); for (const auto& v : report.values()) { - values->AppendString(v->display_name()); - values->AppendString(v->value); + values->AppendString(v.second->display_name()); + values->AppendString(v.second->ToString()); } return dict;
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.h b/content/renderer/media/renderer_gpu_video_accelerator_factories.h index 26ebf6dd..6398ad6 100644 --- a/content/renderer/media/renderer_gpu_video_accelerator_factories.h +++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.h
@@ -13,7 +13,7 @@ #include "base/synchronization/waitable_event.h" #include "content/child/thread_safe_sender.h" #include "content/common/content_export.h" -#include "media/filters/gpu_video_accelerator_factories.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "ui/gfx/geometry/size.h" namespace base {
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc index da93384f..9363fec 100644 --- a/content/renderer/media/rtc_peer_connection_handler.cc +++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -408,8 +408,8 @@ report.timestamp); for (const auto& value : report.values) { response->addStatistic(idx, - blink::WebString::fromUTF8(value->display_name()), - blink::WebString::fromUTF8(value->value)); + blink::WebString::fromUTF8(value.second->display_name()), + blink::WebString::fromUTF8(value.second->ToString())); } }
diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc index 300832b..a2a8cea 100644 --- a/content/renderer/media/rtc_video_decoder.cc +++ b/content/renderer/media/rtc_video_decoder.cc
@@ -16,7 +16,7 @@ #include "content/renderer/media/native_handle_impl.h" #include "gpu/command_buffer/common/mailbox_holder.h" #include "media/base/bind_to_current_loop.h" -#include "media/filters/gpu_video_accelerator_factories.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/webrtc/common_video/interface/texture_video_frame.h" #include "third_party/webrtc/system_wrappers/interface/ref_count.h"
diff --git a/content/renderer/media/rtc_video_decoder_factory.cc b/content/renderer/media/rtc_video_decoder_factory.cc index f59a38f..52e80a8 100644 --- a/content/renderer/media/rtc_video_decoder_factory.cc +++ b/content/renderer/media/rtc_video_decoder_factory.cc
@@ -7,7 +7,7 @@ #include "base/location.h" #include "base/memory/scoped_ptr.h" #include "content/renderer/media/rtc_video_decoder.h" -#include "media/filters/gpu_video_accelerator_factories.h" +#include "media/renderers/gpu_video_accelerator_factories.h" namespace content {
diff --git a/content/renderer/media/rtc_video_decoder_unittest.cc b/content/renderer/media/rtc_video_decoder_unittest.cc index dcb9c4f..2b4c9c6 100644 --- a/content/renderer/media/rtc_video_decoder_unittest.cc +++ b/content/renderer/media/rtc_video_decoder_unittest.cc
@@ -8,7 +8,7 @@ #include "base/threading/thread.h" #include "content/renderer/media/rtc_video_decoder.h" #include "media/base/gmock_callback_support.h" -#include "media/filters/mock_gpu_video_accelerator_factories.h" +#include "media/renderers/mock_gpu_video_accelerator_factories.h" #include "media/video/mock_video_decode_accelerator.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/renderer/media/rtc_video_encoder.cc b/content/renderer/media/rtc_video_encoder.cc index 85da0c0..44c9107 100644 --- a/content/renderer/media/rtc_video_encoder.cc +++ b/content/renderer/media/rtc_video_encoder.cc
@@ -15,8 +15,8 @@ #include "media/base/bitstream_buffer.h" #include "media/base/video_frame.h" #include "media/base/video_util.h" -#include "media/filters/gpu_video_accelerator_factories.h" #include "media/filters/h264_parser.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "media/video/video_encode_accelerator.h" #include "third_party/webrtc/system_wrappers/interface/tick_util.h"
diff --git a/content/renderer/media/rtc_video_encoder_factory.cc b/content/renderer/media/rtc_video_encoder_factory.cc index 8518512..147ce36 100644 --- a/content/renderer/media/rtc_video_encoder_factory.cc +++ b/content/renderer/media/rtc_video_encoder_factory.cc
@@ -8,7 +8,7 @@ #include "content/common/gpu/client/gpu_video_encode_accelerator_host.h" #include "content/public/common/content_switches.h" #include "content/renderer/media/rtc_video_encoder.h" -#include "media/filters/gpu_video_accelerator_factories.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "media/video/video_encode_accelerator.h" namespace content {
diff --git a/content/renderer/media/rtc_video_renderer.cc b/content/renderer/media/rtc_video_renderer.cc index 66190cb..0f32598 100644 --- a/content/renderer/media/rtc_video_renderer.cc +++ b/content/renderer/media/rtc_video_renderer.cc
@@ -83,7 +83,6 @@ void RTCVideoRenderer::OnVideoFrame( const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time) { DCHECK(message_loop_proxy_->BelongsToCurrentThread()); if (state_ != STARTED) { @@ -109,7 +108,7 @@ // originates from a video camera. scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateBlackFrame(frame_size_); - OnVideoFrame(video_frame, media::VideoCaptureFormat(), base::TimeTicks()); + OnVideoFrame(video_frame, base::TimeTicks()); } } // namespace content
diff --git a/content/renderer/media/rtc_video_renderer.h b/content/renderer/media/rtc_video_renderer.h index 924b0030..19550e1 100644 --- a/content/renderer/media/rtc_video_renderer.h +++ b/content/renderer/media/rtc_video_renderer.h
@@ -55,7 +55,6 @@ }; void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time); // VideoTrackSink implementation. Called on the main thread.
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc index 7f395cd..39a0abc2 100644 --- a/content/renderer/media/video_capture_impl.cc +++ b/content/renderer/media/video_capture_impl.cc
@@ -198,7 +198,7 @@ void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) { DCHECK(thread_checker_.CalledOnValidThread()); - ClientBufferMap::iterator iter = client_buffers_.find(buffer_id); + const ClientBufferMap::iterator iter = client_buffers_.find(buffer_id); if (iter == client_buffers_.end()) return; @@ -208,20 +208,17 @@ } void VideoCaptureImpl::OnBufferReceived(int buffer_id, - const media::VideoCaptureFormat& format, + const gfx::Size& coded_size, const gfx::Rect& visible_rect, - base::TimeTicks timestamp) { + base::TimeTicks timestamp, + const base::DictionaryValue& metadata) { DCHECK(thread_checker_.CalledOnValidThread()); - // The capture pipeline supports only I420 for now. - DCHECK_EQ(format.pixel_format, media::PIXEL_FORMAT_I420); - if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0)); return; } - last_frame_format_ = format; if (first_frame_timestamp_.is_null()) first_frame_timestamp_ = timestamp; @@ -232,13 +229,13 @@ "timestamp", timestamp.ToInternalValue(), "time_delta", (timestamp - first_frame_timestamp_).ToInternalValue()); - ClientBufferMap::iterator iter = client_buffers_.find(buffer_id); + const ClientBufferMap::const_iterator iter = client_buffers_.find(buffer_id); DCHECK(iter != client_buffers_.end()); scoped_refptr<ClientBuffer> buffer = iter->second; scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalPackedMemory( media::VideoFrame::I420, - last_frame_format_.frame_size, + coded_size, visible_rect, gfx::Size(visible_rect.width(), visible_rect.height()), reinterpret_cast<uint8*>(buffer->buffer->memory()), @@ -252,18 +249,18 @@ buffer_id, buffer, 0))); + frame->metadata()->MergeInternalValuesFrom(metadata); - for (ClientInfoMap::iterator it = clients_.begin(); it != clients_.end(); - ++it) { - it->second.deliver_frame_cb.Run(frame, format, timestamp); - } + for (const auto& client : clients_) + client.second.deliver_frame_cb.Run(frame, timestamp); } void VideoCaptureImpl::OnMailboxBufferReceived( int buffer_id, const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp) { + const gfx::Size& packed_frame_size, + base::TimeTicks timestamp, + const base::DictionaryValue& metadata) { DCHECK(thread_checker_.CalledOnValidThread()); if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { @@ -271,7 +268,6 @@ return; } - last_frame_format_ = format; if (first_frame_timestamp_.is_null()) first_frame_timestamp_ = timestamp; @@ -280,13 +276,12 @@ media::BindToCurrentLoop(base::Bind( &VideoCaptureImpl::OnClientBufferFinished, weak_factory_.GetWeakPtr(), buffer_id, scoped_refptr<ClientBuffer>())), - last_frame_format_.frame_size, gfx::Rect(last_frame_format_.frame_size), - last_frame_format_.frame_size, timestamp - first_frame_timestamp_, false); + packed_frame_size, gfx::Rect(packed_frame_size), packed_frame_size, + timestamp - first_frame_timestamp_, false); + frame->metadata()->MergeInternalValuesFrom(metadata); - for (ClientInfoMap::iterator it = clients_.begin(); it != clients_.end(); - ++it) { - it->second.deliver_frame_cb.Run(frame, format, timestamp); - } + for (const auto& client : clients_) + client.second.deliver_frame_cb.Run(frame, timestamp); } void VideoCaptureImpl::OnClientBufferFinished( @@ -315,26 +310,21 @@ RestartCapture(); break; case VIDEO_CAPTURE_STATE_PAUSED: - for (ClientInfoMap::iterator it = clients_.begin(); - it != clients_.end(); ++it) { - it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_PAUSED); - } + for (const auto& client : clients_) + client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_PAUSED); break; case VIDEO_CAPTURE_STATE_ERROR: DVLOG(1) << "OnStateChanged: error!, device_id = " << device_id_; - for (ClientInfoMap::iterator it = clients_.begin(); - it != clients_.end(); ++it) { - it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_ERROR); - } + for (const auto& client : clients_) + client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_ERROR); clients_.clear(); state_ = VIDEO_CAPTURE_STATE_ERROR; break; case VIDEO_CAPTURE_STATE_ENDED: DVLOG(1) << "OnStateChanged: ended!, device_id = " << device_id_; - for (ClientInfoMap::iterator it = clients_.begin(); - it != clients_.end(); ++it) { + for (const auto& client : clients_) { // We'll only notify the client that the stream has stopped. - it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED); + client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED); } clients_.clear(); state_ = VIDEO_CAPTURE_STATE_ENDED; @@ -365,17 +355,13 @@ DVLOG(1) << "OnDelegateAdded: device_id " << device_id; device_id_ = device_id; - for (ClientInfoMap::iterator it = clients_pending_on_filter_.begin(); - it != clients_pending_on_filter_.end(); ) { - int client_id = it->first; - VideoCaptureStateUpdateCB state_update_cb = - it->second.state_update_cb; - VideoCaptureDeliverFrameCB deliver_frame_cb = - it->second.deliver_frame_cb; - const media::VideoCaptureParams params = it->second.params; + ClientInfoMap::iterator it = clients_pending_on_filter_.begin(); + while (it != clients_pending_on_filter_.end()) { + const int client_id = it->first; + const ClientInfo client_info = it->second; clients_pending_on_filter_.erase(it++); - StartCapture(client_id, params, state_update_cb, - deliver_frame_cb); + StartCapture(client_id, client_info.params, client_info.state_update_cb, + client_info.deliver_frame_cb); } } @@ -398,12 +384,11 @@ clients_.insert(clients_pending_on_restart_.begin(), clients_pending_on_restart_.end()); clients_pending_on_restart_.clear(); - for (ClientInfoMap::iterator it = clients_.begin(); - it != clients_.end(); ++it) { + for (const auto& client : clients_) { width = std::max(width, - it->second.params.requested_format.frame_size.width()); - height = std::max(height, - it->second.params.requested_format.frame_size.height()); + client.second.params.requested_format.frame_size.width()); + height = std::max( + height, client.second.params.requested_format.frame_size.height()); } params_.requested_format.frame_size.SetSize(width, height); DVLOG(1) << "RestartCapture, " @@ -428,7 +413,7 @@ DCHECK(thread_checker_.CalledOnValidThread()); bool found = false; - ClientInfoMap::iterator it = clients->find(client_id); + const ClientInfoMap::iterator it = clients->find(client_id); if (it != clients->end()) { it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED); clients->erase(it);
diff --git a/content/renderer/media/video_capture_impl.h b/content/renderer/media/video_capture_impl.h index 86b1e4b..d7d6eb07 100644 --- a/content/renderer/media/video_capture_impl.h +++ b/content/renderer/media/video_capture_impl.h
@@ -113,13 +113,15 @@ int buffer_id) override; void OnBufferDestroyed(int buffer_id) override; void OnBufferReceived(int buffer_id, - const media::VideoCaptureFormat& format, + const gfx::Size& coded_size, const gfx::Rect& visible_rect, - base::TimeTicks) override; + base::TimeTicks timestamp, + const base::DictionaryValue& metadata) override; void OnMailboxBufferReceived(int buffer_id, const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp) override; + const gfx::Size& packed_frame_size, + base::TimeTicks timestamp, + const base::DictionaryValue& metadata) override; void OnStateChanged(VideoCaptureState state) override; void OnDeviceSupportedFormatsEnumerated( const media::VideoCaptureFormats& supported_formats) override; @@ -165,9 +167,6 @@ // client to this class via StartCapture(). media::VideoCaptureParams params_; - // The device's video capture format sent from browser process side. - media::VideoCaptureFormat last_frame_format_; - // The device's first captured frame timestamp sent from browser process side. base::TimeTicks first_frame_timestamp_;
diff --git a/content/renderer/media/video_capture_impl_manager_unittest.cc b/content/renderer/media/video_capture_impl_manager_unittest.cc index a688c12..1258c76 100644 --- a/content/renderer/media/video_capture_impl_manager_unittest.cc +++ b/content/renderer/media/video_capture_impl_manager_unittest.cc
@@ -91,9 +91,8 @@ } protected: - MOCK_METHOD3(OnFrameReady, + MOCK_METHOD2(OnFrameReady, void(const scoped_refptr<media::VideoFrame>&, - const media::VideoCaptureFormat&, const base::TimeTicks& estimated_capture_time)); MOCK_METHOD0(OnStarted, void()); MOCK_METHOD0(OnStopped, void());
diff --git a/content/renderer/media/video_capture_impl_unittest.cc b/content/renderer/media/video_capture_impl_unittest.cc index 8c75e47..282cc3e3 100644 --- a/content/renderer/media/video_capture_impl_unittest.cc +++ b/content/renderer/media/video_capture_impl_unittest.cc
@@ -129,9 +129,8 @@ } protected: - MOCK_METHOD3(OnFrameReady, + MOCK_METHOD2(OnFrameReady, void(const scoped_refptr<media::VideoFrame>&, - const media::VideoCaptureFormat&, const base::TimeTicks&)); MOCK_METHOD1(OnStateUpdate, void(VideoCaptureState)); MOCK_METHOD1(OnDeviceFormatsInUse,
diff --git a/content/renderer/media/video_capture_message_filter.cc b/content/renderer/media/video_capture_message_filter.cc index 7157407..80fd570 100644 --- a/content/renderer/media/video_capture_message_filter.cc +++ b/content/renderer/media/video_capture_message_filter.cc
@@ -77,10 +77,9 @@ DVLOG(1) << "VideoCaptureMessageFilter::OnFilterAdded()"; sender_ = sender; - for (Delegates::iterator it = pending_delegates_.begin(); - it != pending_delegates_.end(); it++) { - it->second->OnDelegateAdded(it->first); - delegates_[it->first] = it->second; + for (const auto& pending_delegate : pending_delegates_) { + pending_delegate.second->OnDelegateAdded(pending_delegate.first); + delegates_[pending_delegate.first] = pending_delegate.second; } pending_delegates_.clear(); } @@ -122,32 +121,29 @@ } void VideoCaptureMessageFilter::OnBufferReceived( - int device_id, - int buffer_id, - const media::VideoCaptureFormat& format, - const gfx::Rect& visible_rect, - base::TimeTicks timestamp) { - Delegate* delegate = find_delegate(device_id); + const VideoCaptureMsg_BufferReady_Params& params) { + Delegate* delegate = find_delegate(params.device_id); if (!delegate) { DLOG(WARNING) << "OnBufferReceived: Got video SHM buffer for a " "non-existent or removed video capture."; // Send the buffer back to Host in case it's waiting for all buffers // to be returned. - Send(new VideoCaptureHostMsg_BufferReady(device_id, buffer_id, 0)); + Send(new VideoCaptureHostMsg_BufferReady( + params.device_id, params.buffer_id, 0)); return; } - delegate->OnBufferReceived(buffer_id, format, visible_rect, timestamp); + delegate->OnBufferReceived(params.buffer_id, + params.coded_size, + params.visible_rect, + params.timestamp, + params.metadata); } void VideoCaptureMessageFilter::OnMailboxBufferReceived( - int device_id, - int buffer_id, - const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp) { - Delegate* delegate = find_delegate(device_id); + const VideoCaptureMsg_MailboxBufferReady_Params& params) { + Delegate* delegate = find_delegate(params.device_id); if (!delegate) { DLOG(WARNING) << "OnMailboxBufferReceived: Got video mailbox buffer for a " @@ -155,12 +151,17 @@ // Send the buffer back to Host in case it's waiting for all buffers // to be returned. - Send(new VideoCaptureHostMsg_BufferReady(device_id, buffer_id, 0)); + Send(new VideoCaptureHostMsg_BufferReady( + params.device_id, params.buffer_id, 0)); return; } delegate->OnMailboxBufferReceived( - buffer_id, mailbox_holder, format, timestamp); + params.buffer_id, + params.mailbox_holder, + params.packed_frame_size, + params.timestamp, + params.metadata); } void VideoCaptureMessageFilter::OnBufferDestroyed(
diff --git a/content/renderer/media/video_capture_message_filter.h b/content/renderer/media/video_capture_message_filter.h index 311bcbad..31712373 100644 --- a/content/renderer/media/video_capture_message_filter.h +++ b/content/renderer/media/video_capture_message_filter.h
@@ -13,11 +13,15 @@ #include <map> #include "base/memory/shared_memory.h" +#include "base/values.h" #include "content/common/content_export.h" #include "content/common/media/video_capture.h" #include "ipc/message_filter.h" #include "media/base/video_capture_types.h" +struct VideoCaptureMsg_BufferReady_Params; +struct VideoCaptureMsg_MailboxBufferReady_Params; + namespace gpu { struct MailboxHolder; } // namespace gpu @@ -36,17 +40,20 @@ virtual void OnBufferDestroyed(int buffer_id) = 0; // Called when a video frame buffer is received from the browser process. - virtual void OnBufferReceived(int buffer_id, - const media::VideoCaptureFormat& format, - const gfx::Rect& visible_rect, - base::TimeTicks timestamp) = 0; + virtual void OnBufferReceived( + int buffer_id, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + base::TimeTicks timestamp, + const base::DictionaryValue& metadata) = 0; // Called when a video mailbox buffer is received from the browser process. virtual void OnMailboxBufferReceived( int buffer_id, const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp) = 0; + const gfx::Size& packed_frame_size, + base::TimeTicks timestamp, + const base::DictionaryValue& metadata) = 0; // Called when state of a video capture device has changed in the browser // process. @@ -102,18 +109,11 @@ int buffer_id); // Receive a filled buffer from browser process. - void OnBufferReceived(int device_id, - int buffer_id, - const media::VideoCaptureFormat& format, - const gfx::Rect& visible_rect, - base::TimeTicks timestamp); + void OnBufferReceived(const VideoCaptureMsg_BufferReady_Params& params); // Receive a filled texture mailbox buffer from browser process. - void OnMailboxBufferReceived(int device_id, - int buffer_id, - const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp); + void OnMailboxBufferReceived( + const VideoCaptureMsg_MailboxBufferReady_Params& params); // State of browser process' video capture device has changed. void OnDeviceStateChanged(int device_id, VideoCaptureState state);
diff --git a/content/renderer/media/video_capture_message_filter_unittest.cc b/content/renderer/media/video_capture_message_filter_unittest.cc index 1298e11c..72fd235 100644 --- a/content/renderer/media/video_capture_message_filter_unittest.cc +++ b/content/renderer/media/video_capture_message_filter_unittest.cc
@@ -12,10 +12,13 @@ using ::testing::_; using ::testing::AnyNumber; +using ::testing::DoAll; +using ::testing::Invoke; using ::testing::Mock; using ::testing::Return; using ::testing::SaveArg; using ::testing::StrictMock; +using ::testing::WithArg; namespace content { namespace { @@ -29,16 +32,18 @@ int length, int buffer_id)); MOCK_METHOD1(OnBufferDestroyed, void(int buffer_id)); - MOCK_METHOD4(OnBufferReceived, + MOCK_METHOD5(OnBufferReceived, void(int buffer_id, - const media::VideoCaptureFormat& format, + const gfx::Size& coded_size, const gfx::Rect& visible_rect, - base::TimeTicks timestamp)); - MOCK_METHOD4(OnMailboxBufferReceived, + base::TimeTicks timestamp, + const base::DictionaryValue& metadata)); + MOCK_METHOD5(OnMailboxBufferReceived, void(int buffer_id, const gpu::MailboxHolder& mailbox_holder, - const media::VideoCaptureFormat& format, - base::TimeTicks timestamp)); + const gfx::Size& packed_frame_size, + base::TimeTicks timestamp, + const base::DictionaryValue& metadata)); MOCK_METHOD1(OnStateChanged, void(VideoCaptureState state)); MOCK_METHOD1(OnDeviceSupportedFormatsEnumerated, void(const media::VideoCaptureFormats& formats)); @@ -57,6 +62,16 @@ int device_id_; }; +void ExpectMetadataContainsFooBarBaz(const base::DictionaryValue& metadata) { + std::string value; + if (metadata.GetString("foo", &value)) + EXPECT_EQ(std::string("bar"), value); + else if (metadata.GetString("bar", &value)) + EXPECT_EQ(std::string("baz"), value); + else + FAIL() << "Missing key 'foo' or key 'bar'."; +} + } // namespace TEST(VideoCaptureMessageFilterTest, Basic) { @@ -89,56 +104,55 @@ Mock::VerifyAndClearExpectations(&delegate); // VideoCaptureMsg_BufferReady - int buffer_id = 22; - base::TimeTicks timestamp = base::TimeTicks::FromInternalValue(1); + VideoCaptureMsg_BufferReady_Params params; + params.device_id = delegate.device_id(); + params.buffer_id = 22; + params.coded_size = gfx::Size(234, 512); + params.visible_rect = gfx::Rect(100, 200, 300, 400); + params.timestamp = base::TimeTicks::FromInternalValue(1); + params.metadata.SetString("foo", "bar"); - const media::VideoCaptureFormat shm_format( - gfx::Size(234, 512), 30, media::PIXEL_FORMAT_I420); - media::VideoCaptureFormat saved_format; - EXPECT_CALL(delegate, OnBufferReceived(buffer_id, _, _, timestamp)) - .WillRepeatedly(SaveArg<1>(&saved_format)); - filter->OnMessageReceived(VideoCaptureMsg_BufferReady( - delegate.device_id(), buffer_id, shm_format, gfx::Rect(234, 512), - timestamp)); + EXPECT_CALL(delegate, OnBufferReceived(params.buffer_id, + params.coded_size, + params.visible_rect, + params.timestamp, + _)) + .WillRepeatedly(WithArg<4>(Invoke(&ExpectMetadataContainsFooBarBaz))); + filter->OnMessageReceived(VideoCaptureMsg_BufferReady(params)); Mock::VerifyAndClearExpectations(&delegate); - EXPECT_EQ(shm_format.frame_size, saved_format.frame_size); - EXPECT_EQ(shm_format.frame_rate, saved_format.frame_rate); - EXPECT_EQ(shm_format.pixel_format, saved_format.pixel_format); // VideoCaptureMsg_MailboxBufferReady - buffer_id = 33; - timestamp = base::TimeTicks::FromInternalValue(2); - - const media::VideoCaptureFormat mailbox_format( - gfx::Size(234, 512), 30, media::PIXEL_FORMAT_TEXTURE); + VideoCaptureMsg_MailboxBufferReady_Params params_m; + params_m.device_id = delegate.device_id(); + params_m.buffer_id = 33; gpu::Mailbox mailbox; const int8 mailbox_name[arraysize(mailbox.name)] = "TEST MAILBOX"; mailbox.SetName(mailbox_name); - unsigned int syncpoint = 44; + params_m.mailbox_holder = gpu::MailboxHolder(mailbox, 0, 44); + params_m.packed_frame_size = gfx::Size(345, 256); + params_m.timestamp = base::TimeTicks::FromInternalValue(2); + params_m.metadata.SetString("bar", "baz"); + gpu::MailboxHolder saved_mailbox_holder; - EXPECT_CALL(delegate, OnMailboxBufferReceived(buffer_id, _, _, timestamp)) - .WillRepeatedly( - DoAll(SaveArg<1>(&saved_mailbox_holder), SaveArg<2>(&saved_format))); - gpu::MailboxHolder mailbox_holder(mailbox, 0, syncpoint); - filter->OnMessageReceived( - VideoCaptureMsg_MailboxBufferReady(delegate.device_id(), - buffer_id, - mailbox_holder, - mailbox_format, - timestamp)); + EXPECT_CALL(delegate, OnMailboxBufferReceived(params_m.buffer_id, + _, + params_m.packed_frame_size, + params_m.timestamp, + _)) + .WillRepeatedly(DoAll( + SaveArg<1>(&saved_mailbox_holder), + WithArg<4>(Invoke(&ExpectMetadataContainsFooBarBaz)))); + filter->OnMessageReceived(VideoCaptureMsg_MailboxBufferReady(params_m)); Mock::VerifyAndClearExpectations(&delegate); - EXPECT_EQ(mailbox_format.frame_size, saved_format.frame_size); - EXPECT_EQ(mailbox_format.frame_rate, saved_format.frame_rate); - EXPECT_EQ(mailbox_format.pixel_format, saved_format.pixel_format); EXPECT_EQ(memcmp(mailbox.name, saved_mailbox_holder.mailbox.name, sizeof(mailbox.name)), 0); // VideoCaptureMsg_FreeBuffer - EXPECT_CALL(delegate, OnBufferDestroyed(buffer_id)); + EXPECT_CALL(delegate, OnBufferDestroyed(params_m.buffer_id)); filter->OnMessageReceived(VideoCaptureMsg_FreeBuffer( - delegate.device_id(), buffer_id)); + delegate.device_id(), params_m.buffer_id)); Mock::VerifyAndClearExpectations(&delegate); }
diff --git a/content/renderer/media/video_source_handler.cc b/content/renderer/media/video_source_handler.cc index b48f8e2..13af886 100644 --- a/content/renderer/media/video_source_handler.cc +++ b/content/renderer/media/video_source_handler.cc
@@ -53,10 +53,8 @@ reader_ = reader; } - void OnVideoFrame( - const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, - const base::TimeTicks& estimated_capture_time) { + void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame, + const base::TimeTicks& estimated_capture_time) { TRACE_EVENT0("video", "PpFrameReceiver::OnVideoFrame"); if (reader_) { reader_->GotFrame(frame); @@ -141,8 +139,7 @@ return; } PpFrameReceiver* receiver = it->second->receiver_.get(); - receiver->OnVideoFrame(frame, media::VideoCaptureFormat(), - base::TimeTicks()); + receiver->OnVideoFrame(frame, base::TimeTicks()); } VideoSourceHandler::SourceInfo::SourceInfo(
diff --git a/content/renderer/media/video_track_adapter.cc b/content/renderer/media/video_track_adapter.cc index 855cf767..746602a 100644 --- a/content/renderer/media/video_track_adapter.cc +++ b/content/renderer/media/video_track_adapter.cc
@@ -49,10 +49,9 @@ } // anonymous namespace -// VideoFrameResolutionAdapter is created on and lives on -// on the IO-thread. It does the resolution adaptation and delivers frames to -// all registered tracks on the IO-thread. -// All method calls must be on the IO-thread. +// VideoFrameResolutionAdapter is created on and lives on the IO-thread. It does +// the resolution adaptation and delivers frames to all registered tracks on the +// IO-thread. All method calls must be on the IO-thread. class VideoTrackAdapter::VideoFrameResolutionAdapter : public base::RefCountedThreadSafe<VideoFrameResolutionAdapter> { public: @@ -76,7 +75,6 @@ void RemoveCallback(const MediaStreamVideoTrack* track); void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time); // Returns true if all arguments match with the output of this adapter. @@ -91,10 +89,8 @@ virtual ~VideoFrameResolutionAdapter(); friend class base::RefCountedThreadSafe<VideoFrameResolutionAdapter>; - virtual void DoDeliverFrame( - const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, - const base::TimeTicks& estimated_capture_time); + void DoDeliverFrame(const scoped_refptr<media::VideoFrame>& frame, + const base::TimeTicks& estimated_capture_time); // Returns |true| if the input frame rate is higher that the requested max // frame rate and |frame| should be dropped. @@ -174,17 +170,21 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame( const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time) { DCHECK(io_thread_checker_.CalledOnValidThread()); - if (MaybeDropFrame(frame, format.frame_rate)) + double frame_rate; + if (!frame->metadata()->GetDouble(media::VideoFrameMetadata::FRAME_RATE, + &frame_rate)) { + frame_rate = MediaStreamVideoSource::kUnknownFrameRate; + } + if (MaybeDropFrame(frame, frame_rate)) return; // TODO(perkj): Allow cropping / scaling of textures once // http://crbug/362521 is fixed. if (frame->format() == media::VideoFrame::NATIVE_TEXTURE) { - DoDeliverFrame(frame, format, estimated_capture_time); + DoDeliverFrame(frame, estimated_capture_time); return; } scoped_refptr<media::VideoFrame> video_frame(frame); @@ -246,7 +246,7 @@ << " output visible rect " << video_frame->visible_rect().ToString(); } - DoDeliverFrame(video_frame, format, estimated_capture_time); + DoDeliverFrame(video_frame, estimated_capture_time); } bool VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeDropFrame( @@ -257,8 +257,7 @@ // Do not drop frames if max frame rate hasn't been specified or the source // frame rate is known and is lower than max. if (max_frame_rate_ == 0.0f || - (source_frame_rate > 0 && - source_frame_rate <= max_frame_rate_)) { + (source_frame_rate > 0 && source_frame_rate <= max_frame_rate_)) { return false; } @@ -308,16 +307,12 @@ return true; } -void VideoTrackAdapter:: -VideoFrameResolutionAdapter::DoDeliverFrame( +void VideoTrackAdapter::VideoFrameResolutionAdapter::DoDeliverFrame( const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time) { DCHECK(io_thread_checker_.CalledOnValidThread()); - for (std::vector<VideoIdCallbackPair>::const_iterator it = callbacks_.begin(); - it != callbacks_.end(); ++it) { - it->second.Run(frame, format, estimated_capture_time); - } + for (const auto& callback : callbacks_) + callback.second.Run(frame, estimated_capture_time); } void VideoTrackAdapter::VideoFrameResolutionAdapter::AddCallback( @@ -380,14 +375,13 @@ DCHECK(adapters_.empty()); } -void VideoTrackAdapter::AddTrack( - const MediaStreamVideoTrack* track, - VideoCaptureDeliverFrameCB frame_callback, - int max_width, - int max_height, - double min_aspect_ratio, - double max_aspect_ratio, - double max_frame_rate) { +void VideoTrackAdapter::AddTrack(const MediaStreamVideoTrack* track, + VideoCaptureDeliverFrameCB frame_callback, + int max_width, + int max_height, + double min_aspect_ratio, + double max_aspect_ratio, + double max_frame_rate) { DCHECK(thread_checker_.CalledOnValidThread()); io_message_loop_->PostTask( @@ -397,20 +391,18 @@ min_aspect_ratio, max_aspect_ratio, max_frame_rate)); } -void VideoTrackAdapter::AddTrackOnIO( - const MediaStreamVideoTrack* track, - VideoCaptureDeliverFrameCB frame_callback, - const gfx::Size& max_frame_size, - double min_aspect_ratio, - double max_aspect_ratio, - double max_frame_rate) { +void VideoTrackAdapter::AddTrackOnIO(const MediaStreamVideoTrack* track, + VideoCaptureDeliverFrameCB frame_callback, + const gfx::Size& max_frame_size, + double min_aspect_ratio, + double max_aspect_ratio, + double max_frame_rate) { DCHECK(io_message_loop_->BelongsToCurrentThread()); scoped_refptr<VideoFrameResolutionAdapter> adapter; - for (FrameAdapters::const_iterator it = adapters_.begin(); - it != adapters_.end(); ++it) { - if ((*it)->ConstraintsMatch(max_frame_size, min_aspect_ratio, - max_aspect_ratio, max_frame_rate)) { - adapter = it->get(); + for (const auto& frame_adapter : adapters_) { + if (frame_adapter->ConstraintsMatch(max_frame_size, min_aspect_ratio, + max_aspect_ratio, max_frame_rate)) { + adapter = frame_adapter.get(); break; } } @@ -494,15 +486,12 @@ void VideoTrackAdapter::DeliverFrameOnIO( const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time) { DCHECK(io_message_loop_->BelongsToCurrentThread()); TRACE_EVENT0("video", "VideoTrackAdapter::DeliverFrameOnIO"); ++frame_counter_; - for (FrameAdapters::iterator it = adapters_.begin(); - it != adapters_.end(); ++it) { - (*it)->DeliverFrame(frame, format, estimated_capture_time); - } + for (const auto& adapter : adapters_) + adapter->DeliverFrame(frame, estimated_capture_time); } void VideoTrackAdapter::CheckFramesReceivedOnIO(
diff --git a/content/renderer/media/video_track_adapter.h b/content/renderer/media/video_track_adapter.h index 1a616126..a2f441c 100644 --- a/content/renderer/media/video_track_adapter.h +++ b/content/renderer/media/video_track_adapter.h
@@ -50,7 +50,6 @@ // Must be called on the IO-thread. void DeliverFrameOnIO( const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time); const scoped_refptr<base::MessageLoopProxy>& io_message_loop() {
diff --git a/content/renderer/media/webrtc/media_stream_remote_video_source.cc b/content/renderer/media/webrtc/media_stream_remote_video_source.cc index b752721..786ed84 100644 --- a/content/renderer/media/webrtc/media_stream_remote_video_source.cc +++ b/content/renderer/media/webrtc/media_stream_remote_video_source.cc
@@ -40,8 +40,9 @@ void SetSize(int width, int height) override; void RenderFrame(const cricket::VideoFrame* frame) override; - void DoRenderFrameOnIOThread(scoped_refptr<media::VideoFrame> video_frame, - const media::VideoCaptureFormat& format); + void DoRenderFrameOnIOThread( + const scoped_refptr<media::VideoFrame>& video_frame); + private: // Bound to the render thread. base::ThreadChecker thread_checker_; @@ -103,30 +104,19 @@ frame->GetVPlane(), frame->GetVPitch(), uv_rows, video_frame.get()); } - media::VideoPixelFormat pixel_format = - (video_frame->format() == media::VideoFrame::YV12) ? - media::PIXEL_FORMAT_YV12 : media::PIXEL_FORMAT_TEXTURE; - - media::VideoCaptureFormat format( - gfx::Size(video_frame->natural_size().width(), - video_frame->natural_size().height()), - MediaStreamVideoSource::kUnknownFrameRate, - pixel_format); - io_message_loop_->PostTask( FROM_HERE, base::Bind(&RemoteVideoSourceDelegate::DoRenderFrameOnIOThread, - this, video_frame, format)); + this, video_frame)); } void MediaStreamRemoteVideoSource:: RemoteVideoSourceDelegate::DoRenderFrameOnIOThread( - scoped_refptr<media::VideoFrame> video_frame, - const media::VideoCaptureFormat& format) { + const scoped_refptr<media::VideoFrame>& video_frame) { DCHECK(io_message_loop_->BelongsToCurrentThread()); TRACE_EVENT0("webrtc", "RemoteVideoSourceDelegate::DoRenderFrameOnIOThread"); // TODO(hclam): Give the estimated capture time. - frame_callback_.Run(video_frame, format, base::TimeTicks()); + frame_callback_.Run(video_frame, base::TimeTicks()); } MediaStreamRemoteVideoSource::MediaStreamRemoteVideoSource(
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc index d9f485b..d37e2d9 100644 --- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc +++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -36,7 +36,7 @@ #include "content/renderer/render_thread_impl.h" #include "content/renderer/render_view_impl.h" #include "jingle/glue/thread_wrapper.h" -#include "media/filters/gpu_video_accelerator_factories.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "third_party/WebKit/public/platform/WebMediaConstraints.h" #include "third_party/WebKit/public/platform/WebMediaStream.h" #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
diff --git a/content/renderer/media/webrtc/video_destination_handler.cc b/content/renderer/media/webrtc/video_destination_handler.cc index 45579f0..0684aa65 100644 --- a/content/renderer/media/webrtc/video_destination_handler.cc +++ b/content/renderer/media/webrtc/video_destination_handler.cc
@@ -32,14 +32,12 @@ const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy, const VideoCaptureDeliverFrameCB& new_frame_callback); - void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format); + void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame); private: friend class base::RefCountedThreadSafe<FrameWriterDelegate>; virtual ~FrameWriterDelegate(); - void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format); + void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame); scoped_refptr<base::MessageLoopProxy> io_message_loop_; VideoCaptureDeliverFrameCB new_frame_callback_; @@ -56,21 +54,18 @@ } void PpFrameWriter::FrameWriterDelegate::DeliverFrame( - const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format) { + const scoped_refptr<media::VideoFrame>& frame) { io_message_loop_->PostTask( FROM_HERE, - base::Bind(&FrameWriterDelegate::DeliverFrameOnIO, - this, frame, format)); + base::Bind(&FrameWriterDelegate::DeliverFrameOnIO, this, frame)); } void PpFrameWriter::FrameWriterDelegate::DeliverFrameOnIO( - const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format) { + const scoped_refptr<media::VideoFrame>& frame) { DCHECK(io_message_loop_->BelongsToCurrentThread()); // The local time when this frame is generated is unknown so give a null // value to |estimated_capture_time|. - new_frame_callback_.Run(frame, format, base::TimeTicks()); + new_frame_callback_.Run(frame, base::TimeTicks()); } PpFrameWriter::PpFrameWriter() { @@ -152,10 +147,6 @@ scoped_refptr<media::VideoFrame> new_frame = frame_pool_.CreateFrame(media::VideoFrame::YV12, frame_size, gfx::Rect(frame_size), frame_size, timestamp); - media::VideoCaptureFormat format( - frame_size, - MediaStreamVideoSource::kUnknownFrameRate, - media::PIXEL_FORMAT_YV12); // TODO(magjed): Chrome OS is not ready for switching from BGRA to ARGB. // Remove this once http://crbug/434007 is fixed. We have a corresponding @@ -176,7 +167,7 @@ width, height); - delegate_->DeliverFrame(new_frame, format); + delegate_->DeliverFrame(new_frame); } // PpFrameWriterProxy is a helper class to make sure the user won't use
diff --git a/content/renderer/media/webrtc/webrtc_video_track_adapter.cc b/content/renderer/media/webrtc/webrtc_video_track_adapter.cc index 6a9c2f4d..d3c2036 100644 --- a/content/renderer/media/webrtc/webrtc_video_track_adapter.cc +++ b/content/renderer/media/webrtc/webrtc_video_track_adapter.cc
@@ -44,14 +44,11 @@ void ReleaseSourceOnMainThread(); void OnVideoFrameOnIO(const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time); private: void OnVideoFrameOnWorkerThread( - const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, - const base::TimeTicks& estimated_capture_time); + const scoped_refptr<media::VideoFrame>& frame); friend class base::RefCountedThreadSafe<WebRtcVideoSourceAdapter>; virtual ~WebRtcVideoSourceAdapter(); @@ -113,20 +110,18 @@ void WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::OnVideoFrameOnIO( const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time) { DCHECK(io_thread_checker_.CalledOnValidThread()); libjingle_worker_thread_->PostTask( FROM_HERE, base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread, - this, frame, format, estimated_capture_time)); + this, + frame)); } void WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread( - const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, - const base::TimeTicks& estimated_capture_time) { + const scoped_refptr<media::VideoFrame>& frame) { DCHECK(libjingle_worker_thread_->BelongsToCurrentThread()); base::AutoLock auto_lock(capture_adapter_stop_lock_); if (capture_adapter_)
diff --git a/content/renderer/pepper/pepper_media_stream_video_track_host.cc b/content/renderer/pepper/pepper_media_stream_video_track_host.cc index 096820b..258ee564 100644 --- a/content/renderer/pepper/pepper_media_stream_video_track_host.cc +++ b/content/renderer/pepper/pepper_media_stream_video_track_host.cc
@@ -97,24 +97,24 @@ uint8_t* dst) { CHECK(src->format() == VideoFrame::YV12 || src->format() == VideoFrame::I420); if (dst_format == PP_VIDEOFRAME_FORMAT_BGRA) { - if (src->coded_size() == dst_size) { - libyuv::I420ToARGB(src->data(VideoFrame::kYPlane), + if (src->visible_rect().size() == dst_size) { + libyuv::I420ToARGB(src->visible_data(VideoFrame::kYPlane), src->stride(VideoFrame::kYPlane), - src->data(VideoFrame::kUPlane), + src->visible_data(VideoFrame::kUPlane), src->stride(VideoFrame::kUPlane), - src->data(VideoFrame::kVPlane), + src->visible_data(VideoFrame::kVPlane), src->stride(VideoFrame::kVPlane), dst, dst_size.width() * 4, dst_size.width(), dst_size.height()); } else { - media::ScaleYUVToRGB32(src->data(VideoFrame::kYPlane), - src->data(VideoFrame::kUPlane), - src->data(VideoFrame::kVPlane), + media::ScaleYUVToRGB32(src->visible_data(VideoFrame::kYPlane), + src->visible_data(VideoFrame::kUPlane), + src->visible_data(VideoFrame::kVPlane), dst, - src->coded_size().width(), - src->coded_size().height(), + src->visible_rect().width(), + src->visible_rect().height(), dst_size.width(), dst_size.height(), src->stride(VideoFrame::kYPlane), @@ -135,21 +135,21 @@ const int plane_order = (dst_format == PP_VIDEOFRAME_FORMAT_YV12) ? 0 : 1; int dst_width = dst_size.width(); int dst_height = dst_size.height(); - libyuv::ScalePlane(src->data(kPlanesOrder[plane_order][0]), + libyuv::ScalePlane(src->visible_data(kPlanesOrder[plane_order][0]), src->stride(kPlanesOrder[plane_order][0]), - src->coded_size().width(), - src->coded_size().height(), + src->visible_rect().width(), + src->visible_rect().height(), dst, dst_width, dst_width, dst_height, kFilterMode); dst += dst_width * dst_height; - const int src_halfwidth = (src->coded_size().width() + 1) >> 1; - const int src_halfheight = (src->coded_size().height() + 1) >> 1; + const int src_halfwidth = (src->visible_rect().width() + 1) >> 1; + const int src_halfheight = (src->visible_rect().height() + 1) >> 1; const int dst_halfwidth = (dst_width + 1) >> 1; const int dst_halfheight = (dst_height + 1) >> 1; - libyuv::ScalePlane(src->data(kPlanesOrder[plane_order][1]), + libyuv::ScalePlane(src->visible_data(kPlanesOrder[plane_order][1]), src->stride(kPlanesOrder[plane_order][1]), src_halfwidth, src_halfheight, @@ -159,7 +159,7 @@ dst_halfheight, kFilterMode); dst += dst_halfwidth * dst_halfheight; - libyuv::ScalePlane(src->data(kPlanesOrder[plane_order][2]), + libyuv::ScalePlane(src->visible_data(kPlanesOrder[plane_order][2]), src->stride(kPlanesOrder[plane_order][2]), src_halfwidth, src_halfheight, @@ -186,15 +186,13 @@ const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy, const VideoCaptureDeliverFrameCB& new_frame_callback); - void DeliverVideoFrame(const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format); + void DeliverVideoFrame(const scoped_refptr<media::VideoFrame>& frame); private: friend class base::RefCountedThreadSafe<FrameDeliverer>; virtual ~FrameDeliverer(); - void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format); + void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame); scoped_refptr<base::MessageLoopProxy> io_message_loop_; VideoCaptureDeliverFrameCB new_frame_callback_; @@ -213,21 +211,18 @@ } void PepperMediaStreamVideoTrackHost::FrameDeliverer::DeliverVideoFrame( - const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format) { + const scoped_refptr<media::VideoFrame>& frame) { io_message_loop_->PostTask( FROM_HERE, - base::Bind(&FrameDeliverer::DeliverFrameOnIO, - this, frame, format)); + base::Bind(&FrameDeliverer::DeliverFrameOnIO, this, frame)); } void PepperMediaStreamVideoTrackHost::FrameDeliverer::DeliverFrameOnIO( - const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format) { + const scoped_refptr<media::VideoFrame>& frame) { DCHECK(io_message_loop_->BelongsToCurrentThread()); // The time when this frame is generated is unknown so give a null value to // |estimated_capture_time|. - new_frame_callback_.Run(frame, format, base::TimeTicks()); + new_frame_callback_.Run(frame, base::TimeTicks()); } PepperMediaStreamVideoTrackHost::PepperMediaStreamVideoTrackHost( @@ -369,11 +364,7 @@ base::TimeDelta::FromMilliseconds(ts_ms), base::Closure()); - frame_deliverer_->DeliverVideoFrame( - frame, - media::VideoCaptureFormat(plugin_frame_size_, - kDefaultOutputFrameRate, - ToPixelFormat(plugin_frame_format_))); + frame_deliverer_->DeliverVideoFrame(frame); } // Makes the frame available again for plugin. @@ -383,7 +374,6 @@ void PepperMediaStreamVideoTrackHost::OnVideoFrame( const scoped_refptr<VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time) { DCHECK(frame.get()); // TODO(penghuang): Check |frame->end_of_stream()| and close the track. @@ -392,7 +382,7 @@ return; if (source_frame_size_.IsEmpty()) { - source_frame_size_ = frame->coded_size(); + source_frame_size_ = frame->visible_rect().size(); source_frame_format_ = ppformat; InitBuffers(); }
diff --git a/content/renderer/pepper/pepper_media_stream_video_track_host.h b/content/renderer/pepper/pepper_media_stream_video_track_host.h index e9a562b6..74455ee2 100644 --- a/content/renderer/pepper/pepper_media_stream_video_track_host.h +++ b/content/renderer/pepper/pepper_media_stream_video_track_host.h
@@ -56,7 +56,6 @@ int32_t SendFrameToTrack(int32_t index); void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time); // MediaStreamVideoSource overrides:
diff --git a/content/renderer/pepper/pepper_platform_video_capture.cc b/content/renderer/pepper/pepper_platform_video_capture.cc index 0d011f3..68ef4800 100644 --- a/content/renderer/pepper/pepper_platform_video_capture.cc +++ b/content/renderer/pepper/pepper_platform_video_capture.cc
@@ -142,10 +142,9 @@ void PepperPlatformVideoCapture::OnFrameReady( const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time) { if (handler_ && !stop_capture_cb_.is_null()) - handler_->OnFrameReady(frame, format); + handler_->OnFrameReady(frame); } PepperMediaDeviceManager* PepperPlatformVideoCapture::GetMediaDeviceManager() {
diff --git a/content/renderer/pepper/pepper_platform_video_capture.h b/content/renderer/pepper/pepper_platform_video_capture.h index 601c4f16d6..dd6ed78 100644 --- a/content/renderer/pepper/pepper_platform_video_capture.h +++ b/content/renderer/pepper/pepper_platform_video_capture.h
@@ -42,7 +42,6 @@ void OnDeviceOpened(int request_id, bool succeeded, const std::string& label); void OnStateUpdate(VideoCaptureState state); void OnFrameReady(const scoped_refptr<media::VideoFrame>& frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time); // Can return NULL if the RenderFrame referenced by |render_frame_id_| has
diff --git a/content/renderer/pepper/pepper_video_capture_host.cc b/content/renderer/pepper/pepper_video_capture_host.cc index ed76dc3..820dd12 100644 --- a/content/renderer/pepper/pepper_video_capture_host.cc +++ b/content/renderer/pepper/pepper_video_capture_host.cc
@@ -4,6 +4,7 @@ #include "content/renderer/pepper/pepper_video_capture_host.h" +#include "content/renderer/media/media_stream_video_source.h" #include "content/renderer/pepper/host_globals.h" #include "content/renderer/pepper/pepper_media_device_manager.h" #include "content/renderer/pepper/pepper_platform_video_capture.h" @@ -120,21 +121,26 @@ } void PepperVideoCaptureHost::OnFrameReady( - const scoped_refptr<media::VideoFrame>& frame, - media::VideoCaptureFormat format) { + const scoped_refptr<media::VideoFrame>& frame) { DCHECK(frame.get()); - if (alloc_size_ != frame->coded_size() || buffers_.empty()) { - AllocBuffers(frame->coded_size(), format.frame_rate); - alloc_size_ = frame->coded_size(); + if (alloc_size_ != frame->visible_rect().size() || buffers_.empty()) { + alloc_size_ = frame->visible_rect().size(); + double frame_rate; + int rounded_frame_rate; + if (frame->metadata()->GetDouble(media::VideoFrameMetadata::FRAME_RATE, + &frame_rate)) + rounded_frame_rate = static_cast<int>(frame_rate + 0.5 /* round */); + else + rounded_frame_rate = MediaStreamVideoSource::kUnknownFrameRate; + AllocBuffers(alloc_size_, rounded_frame_rate); } for (uint32_t i = 0; i < buffers_.size(); ++i) { if (!buffers_[i].in_use) { DCHECK_EQ(frame->format(), media::VideoFrame::I420); if (buffers_[i].buffer->size() < - media::VideoFrame::AllocationSize(frame->format(), - frame->coded_size())) { + media::VideoFrame::AllocationSize(frame->format(), alloc_size_)) { // TODO(ihf): handle size mismatches gracefully here. return; } @@ -144,7 +150,7 @@ static_assert(media::VideoFrame::kVPlane == 2, "v plane should be 2"); for (size_t j = 0; j < media::VideoFrame::NumPlanes(frame->format()); ++j) { - const uint8* src = frame->data(j); + const uint8* src = frame->visible_data(j); const size_t row_bytes = frame->row_bytes(j); const size_t src_stride = frame->stride(j); for (int k = 0; k < frame->rows(j); ++k) {
diff --git a/content/renderer/pepper/pepper_video_capture_host.h b/content/renderer/pepper/pepper_video_capture_host.h index cfa11ec..24061b5e7 100644 --- a/content/renderer/pepper/pepper_video_capture_host.h +++ b/content/renderer/pepper/pepper_video_capture_host.h
@@ -59,8 +59,7 @@ void OnError(); // Called when a video frame is ready. - void OnFrameReady(const scoped_refptr<media::VideoFrame>& frame, - media::VideoCaptureFormat format); + void OnFrameReady(const scoped_refptr<media::VideoFrame>& frame); private: int32_t OnOpen(ppapi::host::HostMessageContext* context,
diff --git a/content/renderer/pepper/pepper_video_encoder_host.cc b/content/renderer/pepper/pepper_video_encoder_host.cc index bacbfe0..e476cb6 100644 --- a/content/renderer/pepper/pepper_video_encoder_host.cc +++ b/content/renderer/pepper/pepper_video_encoder_host.cc
@@ -14,7 +14,7 @@ #include "content/renderer/render_thread_impl.h" #include "media/base/bind_to_current_loop.h" #include "media/base/video_frame.h" -#include "media/filters/gpu_video_accelerator_factories.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "media/video/video_encode_accelerator.h" #include "ppapi/c/pp_codecs.h" #include "ppapi/c/pp_errors.h"
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 47e05b5b..bceb2b5 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -19,6 +19,7 @@ #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" +#include "cc/base/switches.h" #include "content/child/appcache/appcache_dispatcher.h" #include "content/child/plugin_messages.h" #include "content/child/quota_dispatcher.h" @@ -65,6 +66,7 @@ #include "content/renderer/dom_utils.h" #include "content/renderer/external_popup_menu.h" #include "content/renderer/geolocation_dispatcher.h" +#include "content/renderer/gpu/gpu_benchmarking_extension.h" #include "content/renderer/history_controller.h" #include "content/renderer/history_serialization.h" #include "content/renderer/image_loading_helper.h" @@ -80,6 +82,7 @@ #include "content/renderer/media/render_media_log.h" #include "content/renderer/media/user_media_client_impl.h" #include "content/renderer/media/webmediaplayer_ms.h" +#include "content/renderer/memory_benchmarking_extension.h" #include "content/renderer/mojo/service_registry_js_wrapper.h" #include "content/renderer/notification_permission_dispatcher.h" #include "content/renderer/npapi/plugin_channel_host.h" @@ -95,6 +98,9 @@ #include "content/renderer/renderer_webcolorchooser_impl.h" #include "content/renderer/screen_orientation/screen_orientation_dispatcher.h" #include "content/renderer/shared_worker_repository.h" +#include "content/renderer/skia_benchmarking_extension.h" +#include "content/renderer/stats_collection_controller.h" +#include "content/renderer/web_ui_extension.h" #include "content/renderer/websharedworker_proxy.h" #include "gin/modules/module_registry.h" #include "media/base/audio_renderer_mixer_input.h" @@ -102,7 +108,7 @@ #include "media/blink/webencryptedmediaclient_impl.h" #include "media/blink/webmediaplayer_impl.h" #include "media/blink/webmediaplayer_params.h" -#include "media/filters/gpu_video_accelerator_factories.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "net/base/data_url.h" #include "net/base/net_errors.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" @@ -1093,22 +1099,8 @@ CHECK(entry->root().urlString() != WebString::fromUTF8(kSwappedOutURL)); render_view_->history_controller()->GoToEntry(entry.Pass(), cache_policy); } - } else if (!params.base_url_for_data_url.is_empty()) { - // A loadData request with a specified base URL. - std::string mime_type, charset, data; - if (net::DataURL::Parse( - params.common_params.url, &mime_type, &charset, &data)) { - frame->loadData( - WebData(data.c_str(), data.length()), - WebString::fromUTF8(mime_type), - WebString::fromUTF8(charset), - params.base_url_for_data_url, - params.history_url_for_data_url, - false); - } else { - CHECK(false) << "Invalid URL passed: " - << params.common_params.url.possibly_invalid_spec(); - } + } else if (!params.common_params.base_url_for_data_url.is_empty()) { + LoadDataURL(params.common_params, frame); } else { // Navigate to the given URL. WebURLRequest request = @@ -2571,16 +2563,32 @@ void RenderFrameImpl::didClearWindowObject(blink::WebLocalFrame* frame) { DCHECK(!frame_ || frame_ == frame); - // TODO(nasko): Move implementation here. Needed state: - // * enabled_bindings_ - // * dom_automation_controller_ - // * stats_collection_controller_ - render_view_->didClearWindowObject(frame); + int enabled_bindings = render_view_->GetEnabledBindings(); - if (render_view_->GetEnabledBindings() & BINDINGS_POLICY_DOM_AUTOMATION) + if (enabled_bindings & BINDINGS_POLICY_WEB_UI) + WebUIExtension::Install(frame); + + if (enabled_bindings & BINDINGS_POLICY_DOM_AUTOMATION) DomAutomationController::Install(this, frame); + if (enabled_bindings & BINDINGS_POLICY_STATS_COLLECTION) + StatsCollectionController::Install(frame); + + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + + if (command_line.HasSwitch(cc::switches::kEnableGpuBenchmarking)) + GpuBenchmarking::Install(frame); + + if (command_line.HasSwitch(switches::kEnableMemoryBenchmarking)) + MemoryBenchmarkingExtension::Install(frame); + + if (command_line.HasSwitch(switches::kEnableSkiaBenchmarking)) + SkiaBenchmarking::Install(frame); + + FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(), + DidClearWindowObject(frame)); FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidClearWindowObject()); } @@ -3629,8 +3637,8 @@ // VisibilityState remain a page-level concept or move to frames? // The semantics of 'Show' might have to change here. if (render_widget_) { - render_view()->webview()->setVisibilityState( - blink::WebPageVisibilityStateVisible, false); + static_cast<blink::WebFrameWidget*>(render_widget_->webwidget())-> + setVisibilityState(blink::WebPageVisibilityStateVisible, false); } FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WasShown()); } @@ -3884,6 +3892,12 @@ GetContentClient()->SetActiveURL(common_params.url); + if (!common_params.base_url_for_data_url.is_empty() || + common_params.url.SchemeIs(url::kDataScheme)) { + LoadDataURL(common_params, frame_); + return; + } + // Create a WebURLRequest that blink can use to get access to the body of the // response through a stream in the browser. Blink will then commit the // navigation. @@ -4379,6 +4393,26 @@ GetRequestBodyForWebURLRequest(*request))); } +void RenderFrameImpl::LoadDataURL(const CommonNavigationParams& params, + WebFrame* frame) { + // A loadData request with a specified base URL. + std::string mime_type, charset, data; + if (net::DataURL::Parse(params.url, &mime_type, &charset, &data)) { + const GURL base_url = params.base_url_for_data_url.is_empty() ? + params.url : params.base_url_for_data_url; + frame->loadData( + WebData(data.c_str(), data.length()), + WebString::fromUTF8(mime_type), + WebString::fromUTF8(charset), + base_url, + params.history_url_for_data_url, + false); + } else { + CHECK(false) << "Invalid URL passed: " + << params.url.possibly_invalid_spec(); + } +} + GURL RenderFrameImpl::GetLoadingUrl() const { WebDataSource* ds = frame_->dataSource(); if (ds->hasUnreachableURL())
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 9512149..327d850 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -710,6 +710,10 @@ // of the WebURLRequest. void BeginNavigation(blink::WebURLRequest* request); + // Loads a data url. + void LoadDataURL(const CommonNavigationParams& params, + blink::WebFrame* frame); + // Returns the URL being loaded by the |frame_|'s request. GURL GetLoadingUrl() const;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index a5d7e58f..0291a86 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -116,7 +116,7 @@ #include "ipc/mojo/ipc_channel_mojo.h" #include "media/base/audio_hardware_config.h" #include "media/base/media.h" -#include "media/filters/gpu_video_accelerator_factories.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "mojo/common/common_type_converters.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" @@ -433,18 +433,29 @@ // When we run plugins in process, we actually run them on the render thread, // which means that we need to make the render thread pump UI events. RenderThreadImpl::RenderThreadImpl() - : ChildThreadImpl(Options(ShouldUseMojoChannel())) { + : ChildThreadImpl(Options::Builder() + .InBrowserProcess(true) + .UseMojoChannel(ShouldUseMojoChannel()) + .Build()) { Init(); } RenderThreadImpl::RenderThreadImpl(const std::string& channel_name) - : ChildThreadImpl(Options(channel_name, ShouldUseMojoChannel())) { + : ChildThreadImpl(Options::Builder() + .InBrowserProcess(true) + .UseMojoChannel(ShouldUseMojoChannel()) + .WithChannelName(channel_name) + .Build()) { Init(); } RenderThreadImpl::RenderThreadImpl( scoped_ptr<base::MessageLoop> main_message_loop) - : ChildThreadImpl(Options(ShouldUseMojoChannel())), + : ChildThreadImpl(Options::Builder() + // TODO(skyostil): This should be set to false. + .InBrowserProcess(true) + .UseMojoChannel(ShouldUseMojoChannel()) + .Build()), main_message_loop_(main_message_loop.Pass()) { Init(); } @@ -661,7 +672,12 @@ // threads in GPU raster mode. if (is_threaded_gpu_rasterization_enabled_) num_raster_threads = 1; - cc::TileTaskWorkerPool::SetNumWorkerThreads(num_raster_threads); + + // In single process, browser compositor already initialized and set up + // worker threads, can't change the number later for the renderer compistor + // in the same process. + if (!command_line.HasSwitch(switches::kSingleProcess)) + cc::TileTaskWorkerPool::SetNumWorkerThreads(num_raster_threads); #if defined(OS_ANDROID) || defined(OS_LINUX) if (!command_line.HasSwitch(
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 6519f37..22d4ce6 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -31,7 +31,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" -#include "cc/base/switches.h" #include "content/child/appcache/appcache_dispatcher.h" #include "content/child/appcache/web_application_cache_host_impl.h" #include "content/child/child_shared_bitmap_manager.h" @@ -76,7 +75,6 @@ #include "content/renderer/disambiguation_popup_helper.h" #include "content/renderer/dom_storage/webstoragenamespace_impl.h" #include "content/renderer/drop_data_builder.h" -#include "content/renderer/gpu/gpu_benchmarking_extension.h" #include "content/renderer/gpu/render_widget_compositor.h" #include "content/renderer/history_controller.h" #include "content/renderer/history_serialization.h" @@ -86,7 +84,6 @@ #include "content/renderer/internal_document_state_data.h" #include "content/renderer/media/audio_device_factory.h" #include "content/renderer/media/video_capture_impl_manager.h" -#include "content/renderer/memory_benchmarking_extension.h" #include "content/renderer/mhtml_generator.h" #include "content/renderer/net_info_helper.h" #include "content/renderer/render_frame_impl.h" @@ -98,19 +95,15 @@ #include "content/renderer/renderer_webapplicationcachehost_impl.h" #include "content/renderer/resizing_mode_selector.h" #include "content/renderer/savable_resources.h" -#include "content/renderer/skia_benchmarking_extension.h" #include "content/renderer/speech_recognition_dispatcher.h" -#include "content/renderer/stats_collection_controller.h" -#include "content/renderer/stats_collection_observer.h" #include "content/renderer/text_input_client_observer.h" -#include "content/renderer/web_ui_extension.h" #include "content/renderer/web_ui_extension_data.h" #include "content/renderer/web_ui_mojo.h" #include "content/renderer/websharedworker_proxy.h" #include "media/audio/audio_output_device.h" #include "media/base/media_switches.h" -#include "media/filters/gpu_video_accelerator_factories.h" #include "media/renderers/audio_renderer_impl.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "net/base/data_url.h" #include "net/base/escape.h" #include "net/base/net_errors.h" @@ -1131,9 +1124,7 @@ prefs.rubber_banding_on_compositor_thread); settings->setUseSolidColorScrollbars(prefs.use_solid_color_scrollbars); -#if defined(OS_WIN) - settings->setShowContextMenuOnMouseUp(true); -#endif + settings->setShowContextMenuOnMouseUp(prefs.context_menu_on_mouse_up); #if defined(OS_MACOSX) settings->setDoubleTapToZoomEnabled(true); @@ -2294,29 +2285,6 @@ return navigation_state; } -void RenderViewImpl::didClearWindowObject(WebLocalFrame* frame) { - FOR_EACH_OBSERVER( - RenderViewObserver, observers_, DidClearWindowObject(frame)); - - if (enabled_bindings_& BINDINGS_POLICY_WEB_UI) - WebUIExtension::Install(frame); - - if (enabled_bindings_ & BINDINGS_POLICY_STATS_COLLECTION) - StatsCollectionController::Install(frame); - - const base::CommandLine& command_line = - *base::CommandLine::ForCurrentProcess(); - - if (command_line.HasSwitch(switches::kEnableSkiaBenchmarking)) - SkiaBenchmarking::Install(frame); - - if (command_line.HasSwitch(cc::switches::kEnableGpuBenchmarking)) - GpuBenchmarking::Install(frame); - - if (command_line.HasSwitch(switches::kEnableMemoryBenchmarking)) - MemoryBenchmarkingExtension::Install(frame); -} - void RenderViewImpl::didChangeIcon(WebLocalFrame* frame, WebIconURL::Type icon_type) { if (frame->parent())
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 506a0ba4..b5bbee0c 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h
@@ -583,7 +583,6 @@ void didCreateDataSource(blink::WebLocalFrame* frame, blink::WebDataSource* datasource); - void didClearWindowObject(blink::WebLocalFrame* frame); void didChangeIcon(blink::WebLocalFrame*, blink::WebIconURL::Type); void didUpdateCurrentHistoryItem(blink::WebLocalFrame* frame); void didChangeScrollOffset(blink::WebLocalFrame* frame);
diff --git a/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc b/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc index f2f6a569..4a97a045 100644 --- a/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc +++ b/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
@@ -338,9 +338,9 @@ base::TimeTicks deadline_in_task; int run_count = 0; - default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); idle_task_runner_->PostIdleTaskAfterWakeup( FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); RunUntilIdle(); EnableIdleTasks(); // Must start a new idle period before idle task runs.
diff --git a/content/renderer/scheduler/task_queue_manager.cc b/content/renderer/scheduler/task_queue_manager.cc index f4f8fc5f..0b88d5a 100644 --- a/content/renderer/scheduler/task_queue_manager.cc +++ b/content/renderer/scheduler/task_queue_manager.cc
@@ -43,7 +43,7 @@ void PumpQueue(); bool UpdateWorkQueue(base::TimeTicks* next_pending_delayed_task, - TaskQueueManager::WorkQueueUpdateEventType event_type); + const base::PendingTask* previous_task); base::PendingTask TakeTaskFromWorkQueue(); void WillDeleteTaskQueueManager(); @@ -73,8 +73,8 @@ void EnqueueTask(const base::PendingTask& pending_task); void PumpQueueLocked(); - bool ShouldAutoPumpQueueLocked( - TaskQueueManager::WorkQueueUpdateEventType event_type); + bool TaskIsOlderThanQueuedTasks(const base::PendingTask* task); + bool ShouldAutoPumpQueueLocked(const base::PendingTask* previous_task); void EnqueueTaskLocked(const base::PendingTask& pending_task); void TraceQueueSize(bool is_locked) const; @@ -153,13 +153,35 @@ } } +bool TaskQueue::TaskIsOlderThanQueuedTasks(const base::PendingTask* task) { + lock_.AssertAcquired(); + // A null task is passed when UpdateQueue is called before any task is run. + // In this case we don't want to pump an after_wakeup queue, so return true + // here. + if (!task) + return true; + + // Return false if there are no task in the incoming queue. + if (incoming_queue_.empty()) + return false; + + base::PendingTask oldest_queued_task = incoming_queue_.front(); + DCHECK(oldest_queued_task.delayed_run_time.is_null()); + DCHECK(task->delayed_run_time.is_null()); + + // Note: the comparison is correct due to the fact that the PendingTask + // operator inverts its comparison operation in order to work well in a heap + // based priority queue. + return oldest_queued_task < *task; +} + bool TaskQueue::ShouldAutoPumpQueueLocked( - TaskQueueManager::WorkQueueUpdateEventType event_type) { + const base::PendingTask* previous_task) { lock_.AssertAcquired(); if (pump_policy_ == TaskQueueManager::PumpPolicy::MANUAL) return false; if (pump_policy_ == TaskQueueManager::PumpPolicy::AFTER_WAKEUP && - event_type != TaskQueueManager::WorkQueueUpdateEventType::AFTER_WAKEUP) + TaskIsOlderThanQueuedTasks(previous_task)) return false; if (incoming_queue_.empty()) return false; @@ -168,7 +190,7 @@ bool TaskQueue::UpdateWorkQueue( base::TimeTicks* next_pending_delayed_task, - TaskQueueManager::WorkQueueUpdateEventType event_type) { + const base::PendingTask* previous_task) { if (!work_queue_.empty()) return true; @@ -178,7 +200,7 @@ *next_pending_delayed_task = std::min(*next_pending_delayed_task, delayed_task_run_times_.top()); } - if (!ShouldAutoPumpQueueLocked(event_type)) + if (!ShouldAutoPumpQueueLocked(previous_task)) return false; work_queue_.Swap(&incoming_queue_); TraceQueueSize(true); @@ -383,14 +405,15 @@ bool TaskQueueManager::UpdateWorkQueues( base::TimeTicks* next_pending_delayed_task, - WorkQueueUpdateEventType event_type) { + const base::PendingTask* previous_task) { // TODO(skyostil): This is not efficient when the number of queues grows very // large due to the number of locks taken. Consider optimizing when we get // there. DCHECK(main_thread_checker_.CalledOnValidThread()); bool has_work = false; for (auto& queue : queues_) { - has_work |= queue->UpdateWorkQueue(next_pending_delayed_task, event_type); + has_work |= queue->UpdateWorkQueue(next_pending_delayed_task, + previous_task); if (!queue->work_queue().empty()) { // Currently we should not be getting tasks with delayed run times in any // of the work queues. @@ -426,8 +449,9 @@ base::TimeTicks next_pending_delayed_task( base::TimeTicks::FromInternalValue(kMaxTimeTicks)); - if (!UpdateWorkQueues(&next_pending_delayed_task, - WorkQueueUpdateEventType::BEFORE_WAKEUP)) + // Pass nullptr to UpdateWorkQueues here to prevent waking up an + // pump-after-wakeup queue. + if (!UpdateWorkQueues(&next_pending_delayed_task, nullptr)) return; base::PendingTask previous_task((tracked_objects::Location()), @@ -446,8 +470,7 @@ MaybePostDoWorkOnMainRunner(); ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task); - if (!UpdateWorkQueues(&next_pending_delayed_task, - WorkQueueUpdateEventType::AFTER_WAKEUP)) + if (!UpdateWorkQueues(&next_pending_delayed_task, &previous_task)) return; } }
diff --git a/content/renderer/scheduler/task_queue_manager.h b/content/renderer/scheduler/task_queue_manager.h index 79df04d..8f32b93a 100644 --- a/content/renderer/scheduler/task_queue_manager.h +++ b/content/renderer/scheduler/task_queue_manager.h
@@ -116,8 +116,6 @@ private: friend class internal::TaskQueue; - enum class WorkQueueUpdateEventType { BEFORE_WAKEUP, AFTER_WAKEUP }; - // Called by the task queue to register a new pending task and allocate a // sequence number for it. void DidQueueTask(base::PendingTask* pending_task); @@ -131,12 +129,13 @@ void DoWork(bool posted_from_main_thread); // Reloads any empty work queues which have automatic pumping enabled and - // which are eligible to be auto pumped at the given |event_type|. - // Returns true if any work queue has tasks after doing this. + // which are eligible to be auto pumped based on the |previous_task| which was + // run. Call with an empty |previous_task| if no task was just run. Returns + // true if any work queue has tasks after doing this. // |next_pending_delayed_task| should be the time of the next known delayed // task. It is updated if any task is found which should run earlier. bool UpdateWorkQueues(base::TimeTicks* next_pending_delayed_task, - WorkQueueUpdateEventType event_type); + const base::PendingTask* previous_task); // Chooses the next work queue to service. Returns true if |out_queue_index| // indicates the queue from which the next task should be run, false to
diff --git a/content/renderer/scheduler/task_queue_manager_unittest.cc b/content/renderer/scheduler/task_queue_manager_unittest.cc index 5c4e4eb8..0a1a2a7 100644 --- a/content/renderer/scheduler/task_queue_manager_unittest.cc +++ b/content/renderer/scheduler/task_queue_manager_unittest.cc
@@ -58,6 +58,7 @@ selector_ = make_scoped_ptr(new SelectorForTest); manager_ = make_scoped_ptr( new TaskQueueManager(num_queues, test_task_runner_, selector_.get())); + EXPECT_EQ(num_queues, selector_->work_queues().size()); } void InitializeWithRealMessageLoop(size_t num_queues) { @@ -65,6 +66,7 @@ selector_ = make_scoped_ptr(new SelectorForTest); manager_ = make_scoped_ptr(new TaskQueueManager( num_queues, message_loop_->task_runner(), selector_.get())); + EXPECT_EQ(num_queues, selector_->work_queues().size()); } scoped_refptr<base::TestSimpleTaskRunner> test_task_runner_; @@ -93,7 +95,6 @@ TEST_F(TaskQueueManagerTest, SingleQueuePosting) { Initialize(1u); - EXPECT_EQ(1u, selector_->work_queues().size()); std::vector<int> run_order; scoped_refptr<base::SingleThreadTaskRunner> runner = @@ -113,7 +114,6 @@ TEST_F(TaskQueueManagerTest, MultiQueuePosting) { Initialize(3u); - EXPECT_EQ(3u, selector_->work_queues().size()); std::vector<int> run_order; scoped_refptr<base::SingleThreadTaskRunner> runners[3] = { @@ -141,7 +141,6 @@ TEST_F(TaskQueueManagerTest, NonNestableTaskPosting) { InitializeWithRealMessageLoop(1u); - EXPECT_EQ(1u, selector_->work_queues().size()); std::vector<int> run_order; scoped_refptr<base::SingleThreadTaskRunner> runner = @@ -157,7 +156,6 @@ TEST_F(TaskQueueManagerTest, NonNestableTaskExecutesInExpectedOrder) { InitializeWithRealMessageLoop(1u); - EXPECT_EQ(1u, selector_->work_queues().size()); std::vector<int> run_order; scoped_refptr<base::SingleThreadTaskRunner> runner = @@ -181,7 +179,6 @@ TEST_F(TaskQueueManagerTest, NonNestableTaskDoesntExecuteInNestedLoop) { InitializeWithRealMessageLoop(1u); - EXPECT_EQ(1u, selector_->work_queues().size()); std::vector<int> run_order; scoped_refptr<base::SingleThreadTaskRunner> runner = @@ -402,7 +399,6 @@ TEST_F(TaskQueueManagerTest, ReentrantPosting) { Initialize(1u); - EXPECT_EQ(1u, selector_->work_queues().size()); std::vector<int> run_order; scoped_refptr<base::SingleThreadTaskRunner> runner = @@ -457,18 +453,22 @@ EXPECT_THAT(run_order, ElementsAre(1)); } -void RePostingTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner) { +void RePostingTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner, + int* run_count) { + (*run_count)++; runner->PostTask( - FROM_HERE, Bind(&RePostingTestTask, base::Unretained(runner.get()))); + FROM_HERE, + Bind(&RePostingTestTask, base::Unretained(runner.get()), run_count)); } TEST_F(TaskQueueManagerTest, DoWorkCantPostItselfMultipleTimes) { Initialize(1u); - scoped_refptr<base::SingleThreadTaskRunner> runner = manager_->TaskRunnerForQueue(0); - runner->PostTask(FROM_HERE, base::Bind(&RePostingTestTask, runner)); + int run_count = 0; + runner->PostTask(FROM_HERE, + base::Bind(&RePostingTestTask, runner, &run_count)); selector_->AppendQueueToService(0); selector_->AppendQueueToService(0); @@ -478,6 +478,7 @@ // NOTE without the executing_task_ check in MaybePostDoWorkOnMainRunner there // will be two tasks here. EXPECT_EQ(1u, test_task_runner_->GetPendingTasks().size()); + EXPECT_EQ(1, run_count); } TEST_F(TaskQueueManagerTest, PostFromNestedRunloop) { @@ -583,9 +584,8 @@ EXPECT_THAT(run_order, ElementsAre(2, 3, 1)); } -TEST_F(TaskQueueManagerTest, AutoPumpOnWakeup) { +TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeup) { Initialize(2u); - EXPECT_EQ(2u, selector_->work_queues().size()); manager_->SetPumpPolicy(0, TaskQueueManager::PumpPolicy::AFTER_WAKEUP); std::vector<int> run_order; @@ -610,9 +610,8 @@ EXPECT_THAT(run_order, ElementsAre(3, 1, 2)); } -TEST_F(TaskQueueManagerTest, AutoPumpOnWakeupWhenAlreadyAwake) { +TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupWhenAlreadyAwake) { Initialize(2u); - EXPECT_EQ(2u, selector_->work_queues().size()); manager_->SetPumpPolicy(0, TaskQueueManager::PumpPolicy::AFTER_WAKEUP); std::vector<int> run_order; @@ -622,15 +621,15 @@ selector_->AppendQueueToService(1); selector_->AppendQueueToService(0); - runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + runners[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1, 2)); // TQM was already awake. + EXPECT_THAT(run_order, ElementsAre(2, 1)); // TQM was already awake. } -TEST_F(TaskQueueManagerTest, AutoPumpOnWakeupTriggeredByManuallyPumpedQueue) { +TEST_F(TaskQueueManagerTest, + AutoPumpAfterWakeupTriggeredByManuallyPumpedQueue) { Initialize(2u); - EXPECT_EQ(2u, selector_->work_queues().size()); manager_->SetPumpPolicy(0, TaskQueueManager::PumpPolicy::AFTER_WAKEUP); manager_->SetPumpPolicy(1, TaskQueueManager::PumpPolicy::MANUAL); @@ -656,6 +655,104 @@ EXPECT_THAT(run_order, ElementsAre(2, 1)); } +void TestPostingTask(scoped_refptr<base::SingleThreadTaskRunner> task_runner, + base::Closure task) { + task_runner->PostTask(FROM_HERE, task); +} + +TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupFromTask) { + Initialize(2u); + manager_->SetPumpPolicy(0, TaskQueueManager::PumpPolicy::AFTER_WAKEUP); + + std::vector<int> run_order; + scoped_refptr<base::SingleThreadTaskRunner> runners[2] = { + manager_->TaskRunnerForQueue(0), manager_->TaskRunnerForQueue(1)}; + + selector_->AppendQueueToService(1); + selector_->AppendQueueToService(1); + selector_->AppendQueueToService(0); + + // Check that a task which posts a task to an auto pump after wakeup queue + // doesn't cause the queue to wake up. + base::Closure after_wakeup_task = base::Bind(&TestTask, 1, &run_order); + runners[1]->PostTask( + FROM_HERE, + base::Bind(&TestPostingTask, runners[0], after_wakeup_task)); + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + // Wake up the queue. + runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(2, 1)); +} + +TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupFromMultipleTasks) { + Initialize(2u); + manager_->SetPumpPolicy(0, TaskQueueManager::PumpPolicy::AFTER_WAKEUP); + + std::vector<int> run_order; + scoped_refptr<base::SingleThreadTaskRunner> runners[2] = { + manager_->TaskRunnerForQueue(0), manager_->TaskRunnerForQueue(1)}; + + selector_->AppendQueueToService(1); + selector_->AppendQueueToService(1); + selector_->AppendQueueToService(1); + selector_->AppendQueueToService(0); + selector_->AppendQueueToService(0); + + // Check that a task which posts a task to an auto pump after wakeup queue + // doesn't cause the queue to wake up. + base::Closure after_wakeup_task_1 = base::Bind(&TestTask, 1, &run_order); + base::Closure after_wakeup_task_2 = base::Bind(&TestTask, 2, &run_order); + runners[1]->PostTask( + FROM_HERE, + base::Bind(&TestPostingTask, runners[0], after_wakeup_task_1)); + runners[1]->PostTask( + FROM_HERE, + base::Bind(&TestPostingTask, runners[0], after_wakeup_task_2)); + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + // Wake up the queue. + runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(3, 1, 2)); +} + +void NullTestTask() { +} + +TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupBecomesQuiescent) { + Initialize(2u); + manager_->SetPumpPolicy(0, TaskQueueManager::PumpPolicy::AFTER_WAKEUP); + + int run_count = 0; + scoped_refptr<base::SingleThreadTaskRunner> runners[2] = { + manager_->TaskRunnerForQueue(0), manager_->TaskRunnerForQueue(1)}; + + selector_->AppendQueueToService(1); + selector_->AppendQueueToService(0); + selector_->AppendQueueToService(0); + // Append extra service queue '0' entries to the selector otherwise test will + // finish even if the RePostingTestTask woke each other up. + selector_->AppendQueueToService(0); + selector_->AppendQueueToService(0); + + // Check that if multiple tasks reposts themselves onto a pump-after-wakeup + // queue they don't wake each other and will eventually stop when no other + // tasks execute. + runners[0]->PostTask(FROM_HERE, + base::Bind(&RePostingTestTask, runners[0], &run_count)); + runners[0]->PostTask(FROM_HERE, + base::Bind(&RePostingTestTask, runners[0], &run_count)); + runners[1]->PostTask(FROM_HERE, base::Bind(&NullTestTask)); + test_task_runner_->RunUntilIdle(); + // The reposting tasks posted to the after wakeup queue shouldn't have woken + // each other up. + EXPECT_EQ(2, run_count); +} + class MockTaskObserver : public base::MessageLoop::TaskObserver { public: MOCK_METHOD1(DidProcessTask, void(const base::PendingTask& task));
diff --git a/content/renderer/service_worker/service_worker_cache_storage_dispatcher.cc b/content/renderer/service_worker/service_worker_cache_storage_dispatcher.cc index 7398e13..29170b1 100644 --- a/content/renderer/service_worker/service_worker_cache_storage_dispatcher.cc +++ b/content/renderer/service_worker/service_worker_cache_storage_dispatcher.cc
@@ -88,7 +88,6 @@ query_params.ignore_search = web_query_params.ignoreSearch; query_params.ignore_method = web_query_params.ignoreMethod; query_params.ignore_vary = web_query_params.ignoreVary; - query_params.prefix_match = web_query_params.prefixMatch; query_params.cache_name = web_query_params.cacheName; return query_params; }
diff --git a/content/renderer/service_worker/service_worker_script_context.cc b/content/renderer/service_worker/service_worker_script_context.cc index 14661847..b94323e6 100644 --- a/content/renderer/service_worker/service_worker_script_context.cc +++ b/content/renderer/service_worker/service_worker_script_context.cc
@@ -314,8 +314,7 @@ proxy_->dispatchActivateEvent(request_id); } -void ServiceWorkerScriptContext::OnInstallEvent(int request_id, - int active_version_id) { +void ServiceWorkerScriptContext::OnInstallEvent(int request_id) { TRACE_EVENT0("ServiceWorker", "ServiceWorkerScriptContext::OnInstallEvent"); install_start_timings_[request_id] = base::TimeTicks::Now();
diff --git a/content/renderer/service_worker/service_worker_script_context.h b/content/renderer/service_worker/service_worker_script_context.h index 1517e0fd..656efd0 100644 --- a/content/renderer/service_worker/service_worker_script_context.h +++ b/content/renderer/service_worker/service_worker_script_context.h
@@ -113,7 +113,7 @@ SkipWaitingCallbacksMap; void OnActivateEvent(int request_id); - void OnInstallEvent(int request_id, int active_version_id); + void OnInstallEvent(int request_id); void OnFetchEvent(int request_id, const ServiceWorkerFetchRequest& request); void OnSyncEvent(int request_id); void OnNotificationClickEvent(
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index 2bbac9b..96cee7c0 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn
@@ -59,6 +59,8 @@ "browser/layout_test/layout_test_javascript_dialog_manager.h", "browser/layout_test/layout_test_message_filter.cc", "browser/layout_test/layout_test_message_filter.h", + "browser/layout_test/layout_test_navigator_connect_service_factory.cc", + "browser/layout_test/layout_test_navigator_connect_service_factory.h", "browser/layout_test/layout_test_notification_manager.cc", "browser/layout_test/layout_test_notification_manager.h", "browser/layout_test/layout_test_push_messaging_service.cc", @@ -482,7 +484,7 @@ # TODO(GYP): Figure out what this should be on android # and make linking this work on the Mac. -if (!is_android && !is_mac && (!is_win || link_chrome_on_windows)) { +if (!is_android && !is_mac) { executable("content_shell") { testonly = true
diff --git a/content/shell/browser/layout_test/layout_test_content_browser_client.cc b/content/shell/browser/layout_test/layout_test_content_browser_client.cc index e881c1c..624a3a7 100644 --- a/content/shell/browser/layout_test/layout_test_content_browser_client.cc +++ b/content/shell/browser/layout_test/layout_test_content_browser_client.cc
@@ -6,10 +6,12 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/navigator_connect_context.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/storage_partition.h" #include "content/shell/browser/layout_test/layout_test_browser_context.h" #include "content/shell/browser/layout_test/layout_test_message_filter.h" +#include "content/shell/browser/layout_test/layout_test_navigator_connect_service_factory.h" #include "content/shell/browser/layout_test/layout_test_notification_manager.h" #include "content/shell/browser/shell_browser_context.h" #include "content/shell/common/shell_messages.h" @@ -22,7 +24,7 @@ void RequestDesktopNotificationPermissionOnIO( const GURL& source_origin, - const base::Callback<void(bool)>& callback) { + const base::Callback<void(PermissionStatus)>& callback) { LayoutTestNotificationManager* manager = LayoutTestContentBrowserClient::Get()->GetLayoutTestNotificationManager(); bool allowed = manager ? manager->RequestPermission(source_origin) @@ -32,7 +34,8 @@ BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, - base::Bind(callback, allowed)); + base::Bind(callback, + allowed ? PERMISSION_STATUS_GRANTED : PERMISSION_STATUS_ASK)); } } // namespace @@ -84,7 +87,7 @@ int bridge_id, const GURL& requesting_frame, bool user_gesture, - const base::Callback<void(bool)>& result_callback) { + const base::Callback<void(PermissionStatus)>& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (permission == content::PERMISSION_NOTIFICATIONS) { BrowserThread::PostTask( @@ -92,7 +95,7 @@ FROM_HERE, base::Bind(&RequestDesktopNotificationPermissionOnIO, requesting_frame, - result_callback)); + callback)); return; } ShellContentBrowserClient::RequestPermission(permission, @@ -100,7 +103,7 @@ bridge_id, requesting_frame, user_gesture, - result_callback); + callback); } PlatformNotificationService* @@ -108,4 +111,10 @@ return layout_test_notification_manager_.get(); } +void LayoutTestContentBrowserClient::GetAdditionalNavigatorConnectServices( + const scoped_refptr<NavigatorConnectContext>& context) { + context->AddFactory( + make_scoped_ptr(new LayoutTestNavigatorConnectServiceFactory)); +} + } // namespace content
diff --git a/content/shell/browser/layout_test/layout_test_content_browser_client.h b/content/shell/browser/layout_test/layout_test_content_browser_client.h index b0f0643..d834318 100644 --- a/content/shell/browser/layout_test/layout_test_content_browser_client.h +++ b/content/shell/browser/layout_test/layout_test_content_browser_client.h
@@ -34,8 +34,10 @@ int bridge_id, const GURL& requesting_frame, bool user_gesture, - const base::Callback<void(bool)>& result_callback) override; + const base::Callback<void(PermissionStatus)>& callback) override; PlatformNotificationService* GetPlatformNotificationService() override; + void GetAdditionalNavigatorConnectServices( + const scoped_refptr<NavigatorConnectContext>& context) override; private: scoped_ptr<LayoutTestNotificationManager> layout_test_notification_manager_;
diff --git a/content/shell/browser/layout_test/layout_test_navigator_connect_service_factory.cc b/content/shell/browser/layout_test/layout_test_navigator_connect_service_factory.cc new file mode 100644 index 0000000..087ffce --- /dev/null +++ b/content/shell/browser/layout_test/layout_test_navigator_connect_service_factory.cc
@@ -0,0 +1,121 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/shell/browser/layout_test/layout_test_navigator_connect_service_factory.h" + +#include "base/values.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/message_port_delegate.h" +#include "content/public/browser/message_port_provider.h" +#include "content/public/common/message_port_types.h" +#include "content/public/common/navigator_connect_client.h" +#include "url/gurl.h" + +namespace content { + +namespace { +const char* kTestScheme = "chrome-layout-test"; +const char* kEchoService = "echo"; +const char* kAnnotateService = "annotate"; +const char* kAsValue = "as-value"; +} + +class LayoutTestNavigatorConnectServiceFactory::Service + : public MessagePortDelegate { + public: + Service(); + ~Service() override; + + void RegisterConnection(int message_port_id, const std::string& service); + + // MessagePortDelegate implementation. + void SendMessage( + int message_port_id, + const MessagePortMessage& message, + const std::vector<TransferredMessagePort>& sent_message_ports) override; + void SendMessagesAreQueued(int message_port_id) override; + + private: + std::map<int, std::string> connections_; +}; + +LayoutTestNavigatorConnectServiceFactory::Service::Service() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); +} + +LayoutTestNavigatorConnectServiceFactory::Service::~Service() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + MessagePortProvider::OnMessagePortDelegateClosing(this); +} + +void LayoutTestNavigatorConnectServiceFactory::Service::RegisterConnection( + int message_port_id, + const std::string& service) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + connections_[message_port_id] = service; +} + +void LayoutTestNavigatorConnectServiceFactory::Service::SendMessage( + int message_port_id, + const MessagePortMessage& message, + const std::vector<TransferredMessagePort>& sent_message_ports) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(connections_.find(message_port_id) != connections_.end()); + if (connections_[message_port_id] == kAnnotateService) { + scoped_ptr<base::DictionaryValue> reply(new base::DictionaryValue); + reply->SetString("message_as_string", message.message_as_string); + reply->Set("message_as_value", message.message_as_value.DeepCopy()); + MessagePortProvider::PostMessageToPort( + message_port_id, MessagePortMessage(reply.Pass()), sent_message_ports); + } else { + MessagePortProvider::PostMessageToPort(message_port_id, message, + sent_message_ports); + } +} + +void LayoutTestNavigatorConnectServiceFactory::Service::SendMessagesAreQueued( + int message_port_id) { + NOTREACHED() << "This method should never be called."; +} + +LayoutTestNavigatorConnectServiceFactory:: + LayoutTestNavigatorConnectServiceFactory() + : service_(nullptr) { +} + +LayoutTestNavigatorConnectServiceFactory:: + ~LayoutTestNavigatorConnectServiceFactory() { + if (service_) + BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, service_); +} + +bool LayoutTestNavigatorConnectServiceFactory::HandlesUrl( + const GURL& target_url) { + return target_url.SchemeIs(kTestScheme); +} + +void LayoutTestNavigatorConnectServiceFactory::Connect( + const NavigatorConnectClient& client, + const ConnectCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + std::string service = client.target_url.path(); + if (service != kEchoService && service != kAnnotateService) { + callback.Run(nullptr, false); + return; + } + if (!service_) + service_ = new Service; + service_->RegisterConnection(client.message_port_id, service); + callback.Run(service_, client.target_url.query() == kAsValue); + + if (service == kAnnotateService) { + scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue); + value->SetString("origin", client.origin.spec()); + MessagePortProvider::PostMessageToPort( + client.message_port_id, MessagePortMessage(value.Pass()), + std::vector<TransferredMessagePort>()); + } +} + +} // namespace content
diff --git a/content/shell/browser/layout_test/layout_test_navigator_connect_service_factory.h b/content/shell/browser/layout_test/layout_test_navigator_connect_service_factory.h new file mode 100644 index 0000000..e153922b --- /dev/null +++ b/content/shell/browser/layout_test/layout_test_navigator_connect_service_factory.h
@@ -0,0 +1,40 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_SHELL_BROWSER_LAYOUT_TEST_LAYOUT_TEST_NAVIGATOR_CONNECT_SERVICE_FACTORY_H_ +#define CONTENT_SHELL_BROWSER_LAYOUT_TEST_LAYOUT_TEST_NAVIGATOR_CONNECT_SERVICE_FACTORY_H_ + +#include <map> +#include <string> + +#include "content/public/browser/navigator_connect_service_factory.h" + +namespace content { + +// Implementation of NavigatorConnectServiceFactory that provides services +// layout tests can connect to under the chrome-layout-test: schema. +// In particular this implements an 'echo' service, that just sends back any +// message sends to it, and an 'annotate' service, which sends back some extra +// metadata in addition to the message it received. +class LayoutTestNavigatorConnectServiceFactory + : public NavigatorConnectServiceFactory { + public: + LayoutTestNavigatorConnectServiceFactory(); + ~LayoutTestNavigatorConnectServiceFactory() override; + + // NavigatorConnectServiceFactory implementation. + bool HandlesUrl(const GURL& target_url) override; + void Connect(const NavigatorConnectClient& client, + const ConnectCallback& callback) override; + + private: + // |service_| is created and destroyed on the IO thread, while + // LayoutTestNavigatorConnectServiceFactory can be destroyed on any thread. + class Service; + Service* service_; +}; + +} // namespace content + +#endif // CONTENT_SHELL_BROWSER_LAYOUT_TEST_LAYOUT_TEST_NAVIGATOR_CONNECT_SERVICE_FACTORY_H_
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc index a73fc9e..927fdd7c 100644 --- a/content/shell/browser/shell_content_browser_client.cc +++ b/content/shell/browser/shell_content_browser_client.cc
@@ -287,6 +287,25 @@ return new ShellQuotaPermissionContext(); } +void ShellContentBrowserClient::RequestPermission( + PermissionType permission, + WebContents* web_contents, + int bridge_id, + const GURL& requesting_frame, + bool user_gesture, + const base::Callback<void(PermissionStatus)>& callback) { + // Some Geolocation tests on Android are still expecting to have the + // permission granted. See https://crbug.com/463514. + if (permission == PERMISSION_GEOLOCATION) { + callback.Run(PERMISSION_STATUS_GRANTED); + return; + } + + ContentBrowserClient::RequestPermission( + permission, web_contents, bridge_id, + requesting_frame, user_gesture, callback); +} + SpeechRecognitionManagerDelegate* ShellContentBrowserClient::CreateSpeechRecognitionManagerDelegate() { return new ShellSpeechRecognitionManagerDelegate();
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h index 33369a1..e78062f 100644 --- a/content/shell/browser/shell_content_browser_client.h +++ b/content/shell/browser/shell_content_browser_client.h
@@ -54,6 +54,14 @@ WebContentsViewDelegate* GetWebContentsViewDelegate( WebContents* web_contents) override; QuotaPermissionContext* CreateQuotaPermissionContext() override; + void RequestPermission( + PermissionType permission, + WebContents* web_contents, + int bridge_id, + const GURL& requesting_frame, + bool user_gesture, + const base::Callback<void(PermissionStatus)>& callback) override; + SpeechRecognitionManagerDelegate* CreateSpeechRecognitionManagerDelegate() override; net::NetLog* GetNetLog() override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index ec6efd3..18048efa9 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -247,7 +247,7 @@ } # !is_ios # TODO(GYP) enable content_browsertests on Mac when it links. -if (!is_mac && (!is_win || link_chrome_on_windows)) { +if (!is_mac) { test("content_browsertests") { sources = rebase_path(content_tests_gypi_values.content_browsertests_sources, @@ -439,7 +439,7 @@ } } -if (!is_mac && (!is_win || link_chrome_on_windows)) { # TODO(GYP) enable on Mac once it links. +if (!is_mac) { # TODO(GYP) enable on Mac once it links. test("content_unittests") { sources = rebase_path(content_tests_gypi_values.content_unittests_sources, ".", @@ -631,7 +631,7 @@ } } -if (!is_mac && (!is_win || link_chrome_on_windows)) { # TODO(GYP) enable on Mac once it links. +if (!is_mac) { # TODO(GYP) enable on Mac once it links. test("content_perftests") { sources = [ "../browser/net/sqlite_persistent_cookie_store_perftest.cc",
diff --git a/content/test/data/media/peerconnection-call.html b/content/test/data/media/peerconnection-call.html index 1e6ff4b8..345d0ea 100644 --- a/content/test/data/media/peerconnection-call.html +++ b/content/test/data/media/peerconnection-call.html
@@ -533,48 +533,48 @@ setAllEventsOccuredHandler(function() { // Add an audio track to the local stream and remove the video track and // then renegotiate. But first - setup the expectations. - local_stream = gFirstConnection.getLocalStreams()[0]; + var localStream = gFirstConnection.getLocalStreams()[0]; + var remoteStream1 = gFirstConnection.getRemoteStreams()[0]; - remote_stream_1 = gFirstConnection.getRemoteStreams()[0]; // Add an expected event that onaddtrack will be called on the remote // mediastream received on gFirstConnection when the audio track is // received. addExpectedEvent(); - remote_stream_1.onaddtrack = function(){ - assertEquals(remote_stream_1.getAudioTracks()[0].id, - local_stream.getAudioTracks()[0].id); + remoteStream1.onaddtrack = function(){ + assertEquals(remoteStream1.getAudioTracks()[0].id, + localStream.getAudioTracks()[0].id); eventOccured(); } // Add an expectation that the received video track is removed from // gFirstConnection. addExpectedEvent(); - remote_stream_1.onremovetrack = function() { + remoteStream1.onremovetrack = function() { eventOccured(); } // Add an expected event that onaddtrack will be called on the remote // mediastream received on gSecondConnection when the audio track is // received. - remote_stream_2 = gSecondConnection.getRemoteStreams()[0]; + remoteStream2 = gSecondConnection.getRemoteStreams()[0]; addExpectedEvent(); - remote_stream_2.onaddtrack = function() { - assertEquals(remote_stream_2.getAudioTracks()[0].id, - local_stream.getAudioTracks()[0].id); + remoteStream2.onaddtrack = function() { + assertEquals(remoteStream2.getAudioTracks()[0].id, + localStream.getAudioTracks()[0].id); eventOccured(); } // Add an expectation that the received video track is removed from // gSecondConnection. addExpectedEvent(); - remote_stream_2.onremovetrack = function() { + remoteStream2.onremovetrack = function() { eventOccured(); } // When all the above events have occurred- the test pass. setAllEventsOccuredHandler(reportTestSuccess); - local_stream.addTrack(gLocalStream.getAudioTracks()[0]); - local_stream.removeTrack(local_stream.getVideoTracks()[0]); + localStream.addTrack(gLocalStream.getAudioTracks()[0]); + localStream.removeTrack(localStream.getVideoTracks()[0]); negotiate(); }); } @@ -681,7 +681,7 @@ function addTwoMediaStreamsToOneConnection() { createConnections(null); navigator.webkitGetUserMedia({audio: true, video: true}, - CloneStreamAndAddTwoStreamstoOneConnection, printGetUserMediaError); + cloneStreamAndAddTwoStreamsToOneConnection, printGetUserMediaError); } function onToneChange(tone) { @@ -743,7 +743,7 @@ // Called if getUserMedia succeeds, then clone the stream, send two streams // from one peer connection. - function CloneStreamAndAddTwoStreamstoOneConnection(localStream) { + function cloneStreamAndAddTwoStreamsToOneConnection(localStream) { displayAndRemember(localStream); var clonedStream = null; @@ -780,15 +780,14 @@ negotiate(); } - // Called if getUserMedia succeeds when we want to send a modified - // MediaStream. A new MediaStream is created and the video track from - // |localStream| is added. + // A new MediaStream is created with video track from |localStream| and is + // added to both peer connections. function createNewVideoStreamAndAddToBothConnections(localStream) { displayAndRemember(localStream); - var new_stream = new webkitMediaStream(); - new_stream.addTrack(localStream.getVideoTracks()[0]); - gFirstConnection.addStream(new_stream); - gSecondConnection.addStream(new_stream); + var newStream = new webkitMediaStream(); + newStream.addTrack(localStream.getVideoTracks()[0]); + gFirstConnection.addStream(newStream); + gSecondConnection.addStream(newStream); negotiate(); }
diff --git a/content/test/data/web_ui_mojo.js b/content/test/data/web_ui_mojo.js index 38b0194..978d068 100644 --- a/content/test/data/web_ui_mojo.js +++ b/content/test/data/web_ui_mojo.js
@@ -3,17 +3,16 @@ // found in the LICENSE file. define('main', [ - 'mojo/public/js/connection', + 'mojo/public/js/router', 'content/test/data/web_ui_test_mojo_bindings.mojom', 'content/public/renderer/service_provider', -], function (connection, bindings, serviceProvider) { +], function (router, bindings, serviceProvider) { var browserTarget; return function() { - browserTarget = connection.bindProxyHandle( - serviceProvider.connectToService(bindings.BrowserTarget.name), - undefined, - bindings.BrowserTarget); + browserTarget = new bindings.BrowserTarget.proxyClass( + new router.Router( + serviceProvider.connectToService(bindings.BrowserTarget.name))); browserTarget.start().then(function() { browserTarget.stop();
diff --git a/content/test/render_thread_impl_browser_test_ipc_helper.cc b/content/test/render_thread_impl_browser_test_ipc_helper.cc index 59d09c2..3075f75 100644 --- a/content/test/render_thread_impl_browser_test_ipc_helper.cc +++ b/content/test/render_thread_impl_browser_test_ipc_helper.cc
@@ -4,6 +4,7 @@ #include "content/test/render_thread_impl_browser_test_ipc_helper.h" +#include "content/common/mojo/channel_init.h" #include "ipc/mojo/ipc_channel_mojo_host.h" #include "testing/gtest/include/gtest/gtest.h" @@ -40,13 +41,17 @@ base::Thread::Options options; options.message_loop_type = base::MessageLoop::TYPE_IO; ASSERT_TRUE(ipc_thread_->StartWithOptions(options)); + ChannelInit::SetSingleProcessIOTaskRunner(ipc_thread_->task_runner()); } void RenderThreadImplBrowserIPCTestHelper::SetupMojo() { InitializeMojo(); + ipc_support_.reset(new IPC::ScopedIPCSupport(ipc_thread_->task_runner())); mojo_host_.reset(new IPC::ChannelMojoHost(ipc_thread_->task_runner())); mojo_application_host_.reset(new MojoApplicationHost()); + mojo_application_host_->OverrideIOTaskRunnerForTest( + ipc_thread_->task_runner()); channel_ = IPC::ChannelProxy::Create( IPC::ChannelMojo::CreateServerFactory(mojo_host_->channel_delegate(),
diff --git a/content/test/render_thread_impl_browser_test_ipc_helper.h b/content/test/render_thread_impl_browser_test_ipc_helper.h index ce3b257d..b2eebd4 100644 --- a/content/test/render_thread_impl_browser_test_ipc_helper.h +++ b/content/test/render_thread_impl_browser_test_ipc_helper.h
@@ -10,6 +10,7 @@ #include "content/common/mojo/mojo_messages.h" #include "ipc/ipc_channel_proxy.h" #include "ipc/mojo/ipc_channel_mojo.h" +#include "ipc/mojo/scoped_ipc_support.h" namespace IPC { class ChannelMojoHost; @@ -42,6 +43,7 @@ scoped_ptr<base::Thread> ipc_thread_; scoped_ptr<base::MessageLoopForIO> message_loop_; scoped_ptr<DummyListener> dummy_listener_; + scoped_ptr<IPC::ScopedIPCSupport> ipc_support_; scoped_ptr<MojoApplicationHost> mojo_application_host_; scoped_ptr<IPC::ChannelMojoHost> mojo_host_; std::string channel_id_;
diff --git a/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc index 1bee8c05..81a0552 100644 --- a/content/test/test_blink_web_unit_test_support.cc +++ b/content/test/test_blink_web_unit_test_support.cc
@@ -13,6 +13,7 @@ #include "content/public/common/content_switches.h" #include "content/renderer/scheduler/renderer_scheduler.h" #include "content/renderer/scheduler/web_scheduler_impl.h" +#include "content/renderer/scheduler/webthread_impl_for_scheduler.h" #include "content/test/mock_webclipboard_impl.h" #include "content/test/web_gesture_curve_mock.h" #include "content/test/web_layer_tree_view_impl_for_testing.h" @@ -60,6 +61,7 @@ if (base::MessageLoopProxy::current()) { renderer_scheduler_ = RendererScheduler::Create(); web_scheduler_.reset(new WebSchedulerImpl(renderer_scheduler_.get())); + web_thread_.reset(new WebThreadImplForScheduler(renderer_scheduler_.get())); } blink::initialize(this); @@ -319,4 +321,10 @@ return web_scheduler_.get(); } +blink::WebThread* TestBlinkWebUnitTestSupport::currentThread() { + if (web_thread_ && web_thread_->isCurrentThread()) + return web_thread_.get(); + return BlinkPlatformImpl::currentThread(); +} + } // namespace content
diff --git a/content/test/test_blink_web_unit_test_support.h b/content/test/test_blink_web_unit_test_support.h index cbea4c5e..15712718 100644 --- a/content/test/test_blink_web_unit_test_support.h +++ b/content/test/test_blink_web_unit_test_support.h
@@ -86,6 +86,7 @@ virtual bool getBlobItems(const blink::WebString& uuid, blink::WebVector<blink::WebBlobData::Item*>* items); virtual blink::WebScheduler* scheduler(); + virtual blink::WebThread* currentThread(); private: MockWebBlobRegistryImpl blob_registry_; @@ -97,6 +98,7 @@ cc_blink::WebCompositorSupportImpl compositor_support_; scoped_ptr<RendererScheduler> renderer_scheduler_; scoped_ptr<WebSchedulerImpl> web_scheduler_; + scoped_ptr<blink::WebThread> web_thread_; #if defined(OS_WIN) || defined(OS_MACOSX) blink::WebThemeEngine* active_theme_engine_;
diff --git a/content/test/test_navigation_url_loader.cc b/content/test/test_navigation_url_loader.cc index 2d148878..6eea8b2d 100644 --- a/content/test/test_navigation_url_loader.cc +++ b/content/test/test_navigation_url_loader.cc
@@ -6,6 +6,8 @@ #include "content/browser/loader/navigation_url_loader_delegate.h" #include "content/public/browser/stream_handle.h" +#include "content/public/common/resource_response.h" +#include "net/url_request/redirect_info.h" namespace content { @@ -21,6 +23,16 @@ redirect_count_++; } +void TestNavigationURLLoader::SimulateServerRedirect(const GURL& redirect_url) { + net::RedirectInfo redirect_info; + redirect_info.status_code = 302; + redirect_info.new_method = "GET"; + redirect_info.new_url = redirect_url; + redirect_info.new_first_party_for_cookies = redirect_url; + scoped_refptr<ResourceResponse> response(new ResourceResponse); + CallOnRequestRedirected(redirect_info, response); +} + void TestNavigationURLLoader::CallOnRequestRedirected( const net::RedirectInfo& redirect_info, const scoped_refptr<ResourceResponse>& response) {
diff --git a/content/test/test_navigation_url_loader.h b/content/test/test_navigation_url_loader.h index b598464..f5eb288 100644 --- a/content/test/test_navigation_url_loader.h +++ b/content/test/test_navigation_url_loader.h
@@ -36,6 +36,8 @@ NavigationRequestInfo* request_info() const { return request_info_.get(); } + void SimulateServerRedirect(const GURL& redirect_url); + void CallOnRequestRedirected(const net::RedirectInfo& redirect_info, const scoped_refptr<ResourceResponse>& response); void CallOnResponseStarted(const scoped_refptr<ResourceResponse>& response,
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc index 988681c..6ef20c1 100644 --- a/content/test/test_render_frame_host.cc +++ b/content/test/test_render_frame_host.cc
@@ -200,58 +200,71 @@ OnDidCommitProvisionalLoad(msg); } -void TestRenderFrameHost::SendBeginNavigationWithURL(const GURL& url, - bool has_user_gesture) { - BeginNavigationParams begin_params("GET", std::string(), net::LOAD_NORMAL, - has_user_gesture); - CommonNavigationParams common_params; - common_params.url = url; - common_params.referrer = Referrer(GURL(), blink::WebReferrerPolicyDefault); - common_params.transition = ui::PAGE_TRANSITION_LINK; - OnBeginNavigation(common_params, begin_params, - scoped_refptr<ResourceRequestBody>()); +void TestRenderFrameHost::SendRendererInitiatedNavigationRequest( + const GURL& url, + bool has_user_gesture) { + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation)) { + BeginNavigationParams begin_params("GET", std::string(), net::LOAD_NORMAL, + has_user_gesture); + CommonNavigationParams common_params; + common_params.url = url; + common_params.referrer = Referrer(GURL(), blink::WebReferrerPolicyDefault); + common_params.transition = ui::PAGE_TRANSITION_LINK; + OnBeginNavigation(common_params, begin_params, + scoped_refptr<ResourceRequestBody>()); + } } void TestRenderFrameHost::DidDisownOpener() { OnDidDisownOpener(); } -void TestRenderFrameHost::PrepareForCommit(const GURL& url) { +void TestRenderFrameHost::PrepareForCommit() { + PrepareForCommitWithServerRedirect(GURL()); +} + +void TestRenderFrameHost::PrepareForCommitWithServerRedirect( + const GURL& redirect_url) { if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableBrowserSideNavigation)) { + // Non PlzNavigate SendBeforeUnloadACK(true); return; } // PlzNavigate - // Simulate the network stack commit without any redirects. NavigationRequest* request = static_cast<NavigatorImpl*>(frame_tree_node_->navigator()) ->GetNavigationRequestForNodeForTesting(frame_tree_node_); + CHECK(request); - // We are simulating a renderer-initiated user-initiated navigation. - if (!request) { - SendBeginNavigationWithURL(url, true); - request = static_cast<NavigatorImpl*>(frame_tree_node_->navigator()) - ->GetNavigationRequestForNodeForTesting(frame_tree_node_); - } - ASSERT_TRUE(request); - - // We may not have simulated the renderer response to the navigation request. - // Do that now. + // Simulate a beforeUnload ACK from the renderer if the browser is waiting for + // it. If it runs it will update the request state. if (request->state() == NavigationRequest::WAITING_FOR_RENDERER_RESPONSE) SendBeforeUnloadACK(true); - // We have already simulated the IO thread commit. Only the - // DidCommitProvisionalLoad from the renderer is missing. - if (request->state() == NavigationRequest::RESPONSE_STARTED) + // If a network request is not needed for this URL, just check the request is + // in the correct state and return. + if (!request->ShouldMakeNetworkRequest(request->common_params().url)) { + CHECK(request->state() == NavigationRequest::RESPONSE_STARTED); return; + } - ASSERT_TRUE(request->state() == NavigationRequest::STARTED); + CHECK(request->state() == NavigationRequest::STARTED); + TestNavigationURLLoader* url_loader = static_cast<TestNavigationURLLoader*>(request->loader_for_testing()); - ASSERT_TRUE(url_loader); + CHECK(url_loader); + + // If a non-empty |redirect_url| was provided, simulate a server redirect. + if (!redirect_url.is_empty()) + url_loader->SimulateServerRedirect(redirect_url); + + // Simulate the network stack commit. scoped_refptr<ResourceResponse> response(new ResourceResponse); + // TODO(carlosk): ideally with PlzNavigate it should be possible someday to + // fully commit the navigation at this call to CallOnResponseStarted. url_loader->CallOnResponseStarted(response, MakeEmptyStream()); }
diff --git a/content/test/test_render_frame_host.h b/content/test/test_render_frame_host.h index fcf4a74..333c2d7 100644 --- a/content/test/test_render_frame_host.h +++ b/content/test/test_render_frame_host.h
@@ -85,7 +85,11 @@ int response_code, const base::FilePath* file_path_for_history_item, const std::vector<GURL>& redirects); - void SendBeginNavigationWithURL(const GURL& url, bool has_user_gesture); + + // With the current navigation logic this method is a no-op. + // PlzNavigate: this method simulates receiving a BeginNavigation IPC. + void SendRendererInitiatedNavigationRequest(const GURL& url, + bool has_user_gesture); void DidDisownOpener(); @@ -102,7 +106,13 @@ // this simulates a BeforeUnload ACK from the renderer. // PlzNavigate: this simulates a BeforeUnload ACK from the renderer, and the // interaction with the IO thread up until the response is ready to commit. - void PrepareForCommit(const GURL& url); + void PrepareForCommit(); + + // This method does the same as PrepareForCommit. + // PlzNavigate: Beyond doing the same as PrepareForCommit, this method will + // also simulate a server redirect to |redirect_url|. If the URL is empty the + // redirect step is ignored. + void PrepareForCommitWithServerRedirect(const GURL& redirect_url); // Simulate receiving a FrameHostMsg_BeforeUnloadHandlersPresent. void SendBeforeUnloadHandlersPresent(bool present);
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc index d3a1c1d1..d3f47f6 100644 --- a/content/test/test_web_contents.cc +++ b/content/test/test_web_contents.cc
@@ -158,7 +158,7 @@ // replaced without a pending frame being created, and we don't get the right // values for the RFH to navigate: we try to use the old one that has been // deleted in the meantime. - GetMainFrame()->PrepareForCommit(entry->GetURL()); + GetMainFrame()->PrepareForCommit(); TestRenderFrameHost* old_rfh = GetMainFrame(); TestRenderFrameHost* rfh = GetPendingMainFrame();
diff --git a/content/test/test_web_contents_factory.cc b/content/test/test_web_contents_factory.cc new file mode 100644 index 0000000..0bf7a01 --- /dev/null +++ b/content/test/test_web_contents_factory.cc
@@ -0,0 +1,53 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/test/test_web_contents_factory.h" + +#include "base/run_loop.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/test_renderer_host.h" +#include "content/public/test/web_contents_tester.h" + +#if defined(USE_AURA) +#include "ui/aura/env.h" +#endif + +namespace content { + +TestWebContentsFactory::TestWebContentsFactory() + : rvh_enabler_(new content::RenderViewHostTestEnabler()), + tear_down_aura_(false) { +#if defined(USE_AURA) + if (aura::Env::GetInstanceDontCreate() == nullptr) { + aura::Env::CreateInstance(true); + tear_down_aura_ = true; + } +#endif +} + +TestWebContentsFactory::~TestWebContentsFactory() { + // We explicitly clear the vector to force destruction of any created web + // contents so that we can properly handle their cleanup (running posted + // tasks, etc). + 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) + if (tear_down_aura_) + aura::Env::DeleteInstance(); +#endif +} + +WebContents* TestWebContentsFactory::CreateWebContents( + BrowserContext* context) { + web_contents_.push_back( + WebContentsTester::CreateTestWebContents(context, nullptr)); + DCHECK(web_contents_.back()); + return web_contents_.back(); +} + +} // namespace content
diff --git a/content/utility/utility_thread_impl.cc b/content/utility/utility_thread_impl.cc index 26af2b1..d1b9bfa 100644 --- a/content/utility/utility_thread_impl.cc +++ b/content/utility/utility_thread_impl.cc
@@ -40,7 +40,10 @@ } UtilityThreadImpl::UtilityThreadImpl(const std::string& channel_name) - : ChildThreadImpl(Options(channel_name, false)), + : ChildThreadImpl(Options::Builder() + .InBrowserProcess(true) + .WithChannelName(channel_name) + .Build()), single_process_(true) { Init(); }
diff --git a/content/zygote/zygote_main_linux.cc b/content/zygote/zygote_main_linux.cc index efbfdb0..96fac21 100644 --- a/content/zygote/zygote_main_linux.cc +++ b/content/zygote/zygote_main_linux.cc
@@ -67,6 +67,7 @@ #if defined(SANITIZER_COVERAGE) #include <sanitizer/common_interface_defs.h> +#include <sanitizer/coverage_interface.h> #endif namespace content {
diff --git a/courgette/disassembler_elf_32.cc b/courgette/disassembler_elf_32.cc index ff2b9e03..02a31eb 100644 --- a/courgette/disassembler_elf_32.cc +++ b/courgette/disassembler_elf_32.cc
@@ -262,6 +262,9 @@ const Elf32_Shdr *section_header = SectionHeader(section_id); + if (section_header->sh_type == SHT_NOBITS) + continue; + if (!ParseSimpleRegion(file_offset, section_header->sh_offset, program)) @@ -282,8 +285,6 @@ return false; file_offset = section_header->sh_offset + section_header->sh_size; break; - case SHT_NOBITS: - // Fall through case SHT_INIT_ARRAY: // Fall through case SHT_FINI_ARRAY:
diff --git a/courgette/disassembler_elf_32_x86.cc b/courgette/disassembler_elf_32_x86.cc index 74496d3c..d2c1c86b44 100644 --- a/courgette/disassembler_elf_32_x86.cc +++ b/courgette/disassembler_elf_32_x86.cc
@@ -91,6 +91,9 @@ uint32 section_relocs_count = section_header->sh_size / section_header->sh_entsize; + if (abs32_locations_.empty()) + match = false; + if (abs32_locations_.size() > section_relocs_count) match = false;
diff --git a/courgette/encode_decode_unittest.cc b/courgette/encode_decode_unittest.cc index 0e121d6..a3161ce 100644 --- a/courgette/encode_decode_unittest.cc +++ b/courgette/encode_decode_unittest.cc
@@ -82,3 +82,8 @@ std::string file = FileContents("elf-32-1"); TestAssembleToStreamDisassemble(file, 135988); } + +TEST_F(EncodeDecodeTest, Elf_HighBSS) { + std::string file = FileContents("elf-32-high-bss"); + TestAssembleToStreamDisassemble(file, 7308); +}
diff --git a/courgette/testdata/elf-32-high-bss b/courgette/testdata/elf-32-high-bss new file mode 100755 index 0000000..b9445c8 --- /dev/null +++ b/courgette/testdata/elf-32-high-bss Binary files differ
diff --git a/crypto/crypto.gyp b/crypto/crypto.gyp index 632c498..c8fdbc5 100644 --- a/crypto/crypto.gyp +++ b/crypto/crypto.gyp
@@ -238,7 +238,7 @@ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64', ], 'sources': [ - '<@(hmac_win64_related_sources)', + '<@(nacl_win64_sources)', ], 'defines': [ 'CRYPTO_IMPLEMENTATION',
diff --git a/crypto/crypto.gypi b/crypto/crypto.gypi index 82b5da5..6fdbdf49 100644 --- a/crypto/crypto.gypi +++ b/crypto/crypto.gypi
@@ -23,7 +23,6 @@ 'wincrypt_shim.h', ], }, - 'hmac_win64_related_sources': [ '<@(hmac_win64_related_sources)' ], 'crypto_sources': [ # NOTE: all transitive dependencies of HMAC on windows need # to be placed in the source list above. @@ -100,6 +99,11 @@ 'third_party/nss/pk11akey.cc', 'third_party/nss/rsawrapr.c', 'third_party/nss/secsign.cc', - ] + ], + 'nacl_win64_sources': [ + '<@(hmac_win64_related_sources)', + 'random.cc', + 'random.h', + ], } }
diff --git a/crypto/hmac_openssl.cc b/crypto/hmac_openssl.cc index 92eea19d..ef20290 100644 --- a/crypto/hmac_openssl.cc +++ b/crypto/hmac_openssl.cc
@@ -20,45 +20,37 @@ std::vector<unsigned char> key; }; -HMAC::HMAC(HashAlgorithm hash_alg) - : hash_alg_(hash_alg), plat_(new HMACPlatformData()) { +HMAC::HMAC(HashAlgorithm hash_alg) : hash_alg_(hash_alg) { // Only SHA-1 and SHA-256 hash algorithms are supported now. DCHECK(hash_alg_ == SHA1 || hash_alg_ == SHA256); } bool HMAC::Init(const unsigned char* key, size_t key_length) { // Init must not be called more than once on the same HMAC object. - DCHECK(plat_->key.empty()); - + DCHECK(!plat_); + plat_.reset(new HMACPlatformData()); plat_->key.assign(key, key + key_length); - if (key_length == 0) { - // Special-case: if the key is empty, use a key with one zero - // byte. OpenSSL's HMAC function breaks when passed a NULL key. (It calls - // HMAC_Init_ex which treats a NULL key as having already been initialized - // with a key previously.) HMAC pads keys with zeros, so this key is - // equivalent. - plat_->key.push_back(0); - } return true; } HMAC::~HMAC() { - // Zero out key copy. - plat_->key.assign(plat_->key.size(), 0); - STLClearObject(&plat_->key); + if (plat_) { + // Zero out key copy. + plat_->key.assign(plat_->key.size(), 0); + STLClearObject(&plat_->key); + } } bool HMAC::Sign(const base::StringPiece& data, unsigned char* digest, size_t digest_length) const { - DCHECK(!plat_->key.empty()); // Init must be called before Sign. + DCHECK(plat_); // Init must be called before Sign. ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> result(digest, digest_length); return !!::HMAC(hash_alg_ == SHA1 ? EVP_sha1() : EVP_sha256(), - &plat_->key[0], plat_->key.size(), - reinterpret_cast<const unsigned char*>(data.data()), - data.size(), - result.safe_buffer(), NULL); + vector_as_array(&plat_->key), plat_->key.size(), + reinterpret_cast<const unsigned char*>(data.data()), + data.size(), result.safe_buffer(), NULL); } } // namespace crypto
diff --git a/device/battery/android/java/src/org/chromium/device/battery/BatteryStatusManager.java b/device/battery/android/java/src/org/chromium/device/battery/BatteryStatusManager.java index b94c7f0..87fd280 100644 --- a/device/battery/android/java/src/org/chromium/device/battery/BatteryStatusManager.java +++ b/device/battery/android/java/src/org/chromium/device/battery/BatteryStatusManager.java
@@ -4,6 +4,7 @@ package org.chromium.device.battery; +import android.annotation.TargetApi; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -133,35 +134,44 @@ double chargingTimeSeconds = (charging && batteryFull) ? 0 : Double.POSITIVE_INFINITY; double dischargingTimeSeconds = Double.POSITIVE_INFINITY; - if (mLollipopBatteryManager != null) { - // On Lollipop we can provide a better estimate for chargingTime and dischargingTime. - double remainingCapacityRatio = mLollipopBatteryManager.getIntProperty( - BatteryManager.BATTERY_PROPERTY_CAPACITY) / 100.0; - double batteryCapacityMicroAh = mLollipopBatteryManager.getIntProperty( - BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER); - double averageCurrentMicroA = mLollipopBatteryManager.getIntProperty( - BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE); - - if (charging) { - if (chargingTimeSeconds == Double.POSITIVE_INFINITY && averageCurrentMicroA > 0) { - double chargeFromEmptyHours = batteryCapacityMicroAh / averageCurrentMicroA; - chargingTimeSeconds = - Math.ceil((1 - remainingCapacityRatio) * chargeFromEmptyHours * 3600.0); - } - } else { - if (averageCurrentMicroA < 0) { - double dischargeFromFullHours = batteryCapacityMicroAh / -averageCurrentMicroA; - dischargingTimeSeconds = - Math.floor(remainingCapacityRatio * dischargeFromFullHours * 3600.0); - } - } - } - BatteryStatus batteryStatus = new BatteryStatus(); batteryStatus.charging = charging; batteryStatus.chargingTime = chargingTimeSeconds; batteryStatus.dischargingTime = dischargingTimeSeconds; batteryStatus.level = level; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + updateBatteryStatusForLollipop(batteryStatus); + } + mCallback.onBatteryStatusChanged(batteryStatus); } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private void updateBatteryStatusForLollipop(BatteryStatus batteryStatus) { + assert mLollipopBatteryManager != null; + + // On Lollipop we can provide a better estimate for chargingTime and dischargingTime. + double remainingCapacityRatio = mLollipopBatteryManager.getIntProperty( + BatteryManager.BATTERY_PROPERTY_CAPACITY) / 100.0; + double batteryCapacityMicroAh = mLollipopBatteryManager.getIntProperty( + BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER); + double averageCurrentMicroA = mLollipopBatteryManager.getIntProperty( + BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE); + + if (batteryStatus.charging) { + if (batteryStatus.chargingTime == Double.POSITIVE_INFINITY + && averageCurrentMicroA > 0) { + double chargeFromEmptyHours = batteryCapacityMicroAh / averageCurrentMicroA; + batteryStatus.chargingTime = + Math.ceil((1 - remainingCapacityRatio) * chargeFromEmptyHours * 3600.0); + } + } else { + if (averageCurrentMicroA < 0) { + double dischargeFromFullHours = batteryCapacityMicroAh / -averageCurrentMicroA; + batteryStatus.dischargingTime = + Math.floor(remainingCapacityRatio * dischargeFromFullHours * 3600.0); + } + } + } }
diff --git a/device/hid/BUILD.gn b/device/hid/BUILD.gn index b0375731..4a6a1b2 100644 --- a/device/hid/BUILD.gn +++ b/device/hid/BUILD.gn
@@ -6,6 +6,8 @@ sources = [ "device_monitor_linux.cc", "device_monitor_linux.h", + "fake_input_service_linux.cc", + "fake_input_service_linux.h", "hid_collection_info.cc", "hid_collection_info.h", "hid_connection.cc",
diff --git a/device/hid/fake_input_service_linux.cc b/device/hid/fake_input_service_linux.cc new file mode 100644 index 0000000..ae3f085 --- /dev/null +++ b/device/hid/fake_input_service_linux.cc
@@ -0,0 +1,30 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/hid/fake_input_service_linux.h" + +#include <string> +#include <vector> + +namespace device { + +FakeInputServiceLinux::FakeInputServiceLinux() { +} + +FakeInputServiceLinux::~FakeInputServiceLinux() { +} + +void FakeInputServiceLinux::AddDeviceForTesting(const InputDeviceInfo& info) { + AddDevice(info); +} + +void FakeInputServiceLinux::RemoveDeviceForTesting(const std::string& id) { + RemoveDevice(id); +} + +void FakeInputServiceLinux::ClearDeviceList() { + devices_.clear(); +} + +} // namespace device \ No newline at end of file
diff --git a/device/hid/fake_input_service_linux.h b/device/hid/fake_input_service_linux.h new file mode 100644 index 0000000..1b46d98 --- /dev/null +++ b/device/hid/fake_input_service_linux.h
@@ -0,0 +1,29 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_HID_FAKE_INPUT_SERVICE_LINUX_H_ +#define DEVICE_HID_FAKE_INPUT_SERVICE_LINUX_H_ + +#include <string> + +#include "device/hid/input_service_linux.h" + +namespace device { + +class FakeInputServiceLinux : public InputServiceLinux { + + public: + FakeInputServiceLinux(); + ~FakeInputServiceLinux() override; + + void AddDeviceForTesting(const InputDeviceInfo& info); + void RemoveDeviceForTesting(const std::string& id); + void ClearDeviceList(); + + DISALLOW_COPY_AND_ASSIGN(FakeInputServiceLinux); +}; + +} // namespace device + +#endif // DEVICE_HID_FAKE_INPUT_SERVICE_LINUX_H_
diff --git a/device/hid/hid.gyp b/device/hid/hid.gyp index 42215d75..00b9a90 100644 --- a/device/hid/hid.gyp +++ b/device/hid/hid.gyp
@@ -21,6 +21,8 @@ 'sources': [ 'device_monitor_linux.cc', 'device_monitor_linux.h', + 'fake_input_service_linux.cc', + 'fake_input_service_linux.h', 'hid_collection_info.cc', 'hid_collection_info.h', 'hid_connection.cc', @@ -66,6 +68,8 @@ 'device_monitor_linux.h', 'hid_service_linux.cc', 'hid_service_linux.h', + 'fake_input_service_linux.cc', + 'fake_input_service_linux.h', 'input_service_linux.cc', 'input_service_linux.h', ],
diff --git a/device/hid/input_service_linux.cc b/device/hid/input_service_linux.cc index f6fd0dce..81cac1a 100644 --- a/device/hid/input_service_linux.cc +++ b/device/hid/input_service_linux.cc
@@ -90,6 +90,9 @@ }; InputServiceLinuxImpl::InputServiceLinuxImpl() { + base::ThreadRestrictions::AssertIOAllowed(); + base::MessageLoop::current()->AddDestructionObserver(this); + DeviceMonitorLinux::GetInstance()->AddObserver(this); DeviceMonitorLinux::GetInstance()->Enumerate(base::Bind( &InputServiceLinuxImpl::OnDeviceAdded, base::Unretained(this))); @@ -98,6 +101,7 @@ InputServiceLinuxImpl::~InputServiceLinuxImpl() { if (DeviceMonitorLinux::HasInstance()) DeviceMonitorLinux::GetInstance()->RemoveObserver(this); + base::MessageLoop::current()->RemoveDestructionObserver(this); } void InputServiceLinuxImpl::OnDeviceAdded(udev_device* device) { @@ -162,13 +166,10 @@ is_touchscreen(false) {} InputServiceLinux::InputServiceLinux() { - base::ThreadRestrictions::AssertIOAllowed(); - base::MessageLoop::current()->AddDestructionObserver(this); } InputServiceLinux::~InputServiceLinux() { DCHECK(CalledOnValidThread()); - base::MessageLoop::current()->RemoveDestructionObserver(this); } // static
diff --git a/device/hid/input_service_linux.h b/device/hid/input_service_linux.h index 55bf70c..7eda3bb81 100644 --- a/device/hid/input_service_linux.h +++ b/device/hid/input_service_linux.h
@@ -45,6 +45,9 @@ bool is_touchscreen : 1; }; + + using DeviceMap = base::hash_map<std::string, InputDeviceInfo>; + class Observer { public: virtual ~Observer() {} @@ -53,6 +56,7 @@ }; InputServiceLinux(); + ~InputServiceLinux() override; static InputServiceLinux* GetInstance(); static bool HasInstance(); @@ -73,21 +77,18 @@ void WillDestroyCurrentMessageLoop() override; protected: - ~InputServiceLinux() override; void AddDevice(const InputDeviceInfo& info); void RemoveDevice(const std::string& id); bool CalledOnValidThread() const; - private: - friend struct base::DefaultDeleter<InputServiceLinux>; - - typedef base::hash_map<std::string, InputDeviceInfo> DeviceMap; - DeviceMap devices_; ObserverList<Observer> observers_; + private: + friend struct base::DefaultDeleter<InputServiceLinux>; + base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(InputServiceLinux);
diff --git a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc index 0f72677..2dddbce 100644 --- a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc +++ b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
@@ -72,8 +72,8 @@ dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kOpenStorage); dbus::MessageWriter writer(&method_call); writer.AppendString(storage_name); - DCHECK_EQ(mtpd::kReadOnlyMode, mode); - writer.AppendString(mtpd::kReadOnlyMode); + DCHECK(mode == mtpd::kReadOnlyMode || mode == mtpd::kReadWriteMode); + writer.AppendString(mode); proxy_->CallMethod( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&MediaTransferProtocolDaemonClientImpl::OnOpenStorage, @@ -171,6 +171,28 @@ error_callback)); } + void CopyFileFromLocal(const std::string& handle, + const int source_file_descriptor, + const uint32 parent_id, + const std::string& file_name, + const CopyFileFromLocalCallback& callback, + const ErrorCallback& error_callback) override { + dbus::FileDescriptor file_descriptor(source_file_descriptor); + file_descriptor.CheckValidity(); + + dbus::MethodCall method_call(mtpd::kMtpdInterface, + mtpd::kCopyFileFromLocal); + dbus::MessageWriter writer(&method_call); + writer.AppendString(handle); + writer.AppendFileDescriptor(file_descriptor); + writer.AppendUint32(parent_id); + writer.AppendString(file_name); + proxy_->CallMethod( + &method_call, dbus::ObjectProxy::TIMEOUT_INFINITE, + base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCopyFileFromLocal, + weak_ptr_factory_.GetWeakPtr(), callback, error_callback)); + } + // MediaTransferProtocolDaemonClient override. void ListenForChanges(const MTPStorageEventHandler& handler) override { DCHECK(!listen_for_changes_called_); @@ -349,6 +371,17 @@ callback.Run(data); } + void OnCopyFileFromLocal(const CopyFileFromLocalCallback& callback, + const ErrorCallback& error_callback, + dbus::Response* response) { + if (!response) { + error_callback.Run(); + return; + } + + callback.Run(); + } + // Handles MTPStorageAttached/Dettached signals and calls |handler|. void OnMTPStorageSignal(MTPStorageEventHandler handler, bool is_attach,
diff --git a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h index b051e6c..c44ba75 100644 --- a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h +++ b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
@@ -68,6 +68,9 @@ // The argument is a string containing the file data. typedef base::Callback<void(const std::string& data)> ReadFileCallback; + // A callback to handle the result of CopyFileFromLocal. + typedef base::Closure CopyFileFromLocalCallback; + // A callback to handle storage attach/detach events. // The first argument is true for attach, false for detach. // The second argument is the storage name. @@ -137,6 +140,18 @@ const ReadFileCallback& callback, const ErrorCallback& error_callback) = 0; + // Calls CopyFileFromLocal method. |callback| is called after the method call + // succeeds, otherwise, |error_callback| is called. + // |source_file_descriptor| is a file descriptor of source file. + // |parent_id| is a object id of a target directory. + // |file_name| is a file name of a target file. + virtual void CopyFileFromLocal(const std::string& handle, + const int source_file_descriptor, + const uint32 parent_id, + const std::string& file_name, + const CopyFileFromLocalCallback& callback, + const ErrorCallback& error_callback) = 0; + // Registers given callback for events. Should only be called once. // |storage_event_handler| is called when a mtp storage attach or detach // signal is received.
diff --git a/device/media_transfer_protocol/media_transfer_protocol_manager.cc b/device/media_transfer_protocol/media_transfer_protocol_manager.cc index cde9e53..fb59588b 100644 --- a/device/media_transfer_protocol/media_transfer_protocol_manager.cc +++ b/device/media_transfer_protocol/media_transfer_protocol_manager.cc
@@ -223,6 +223,25 @@ weak_ptr_factory_.GetWeakPtr())); } + void CopyFileFromLocal(const std::string& storage_handle, + const int source_file_descriptor, + const uint32 parent_id, + const std::string& file_name, + const CopyFileFromLocalCallback& callback) override { + DCHECK(thread_checker_.CalledOnValidThread()); + if (!ContainsKey(handles_, storage_handle) || !mtp_client_) { + callback.Run(true /* error */); + return; + } + copy_file_from_local_callbacks_.push(callback); + mtp_client_->CopyFileFromLocal( + storage_handle, source_file_descriptor, parent_id, file_name, + base::Bind(&MediaTransferProtocolManagerImpl::OnCopyFileFromLocal, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&MediaTransferProtocolManagerImpl::OnCopyFileFromLocalError, + weak_ptr_factory_.GetWeakPtr())); + } + private: // Map of storage names to storage info. typedef std::map<std::string, MtpStorageInfo> StorageInfoMap; @@ -235,6 +254,7 @@ typedef std::queue<ReadDirectoryCallback> ReadDirectoryCallbackQueue; typedef std::queue<ReadFileCallback> ReadFileCallbackQueue; typedef std::queue<GetFileInfoCallback> GetFileInfoCallbackQueue; + typedef std::queue<CopyFileFromLocalCallback> CopyFileFromLocalCallbackQueue; void OnStorageAttached(const std::string& storage_name) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -451,6 +471,18 @@ get_file_info_callbacks_.pop(); } + void OnCopyFileFromLocal() { + DCHECK(thread_checker_.CalledOnValidThread()); + copy_file_from_local_callbacks_.front().Run(false /* no error */); + copy_file_from_local_callbacks_.pop(); + } + + void OnCopyFileFromLocalError() { + DCHECK(thread_checker_.CalledOnValidThread()); + copy_file_from_local_callbacks_.front().Run(true /* error */); + copy_file_from_local_callbacks_.pop(); + } + // Get the Bus object used to communicate with mtpd. dbus::Bus* GetBus() { DCHECK(thread_checker_.CalledOnValidThread()); @@ -532,6 +564,7 @@ ReadDirectoryCallbackQueue read_directory_callbacks_; ReadFileCallbackQueue read_file_callbacks_; GetFileInfoCallbackQueue get_file_info_callbacks_; + CopyFileFromLocalCallbackQueue copy_file_from_local_callbacks_; base::ThreadChecker thread_checker_;
diff --git a/device/media_transfer_protocol/media_transfer_protocol_manager.h b/device/media_transfer_protocol/media_transfer_protocol_manager.h index 7ff89e9..39eea9b 100644 --- a/device/media_transfer_protocol/media_transfer_protocol_manager.h +++ b/device/media_transfer_protocol/media_transfer_protocol_manager.h
@@ -59,6 +59,10 @@ typedef base::Callback<void(const MtpFileEntry& file_entry, bool error)> GetFileInfoCallback; + // A callback to handle the result of CopyFileFromLocal. + // The first argument is true if there was an error. + typedef base::Callback<void(bool error)> CopyFileFromLocalCallback; + // Implement this interface to be notified about MTP storage // attachment / detachment events. class Observer { @@ -115,6 +119,14 @@ uint32 file_id, const GetFileInfoCallback& callback) = 0; + // Copies the file from |source_file_descriptor| to |file_name| on + // |parent_id|. + virtual void CopyFileFromLocal(const std::string& storage_handle, + const int source_file_descriptor, + const uint32 parent_id, + const std::string& file_name, + const CopyFileFromLocalCallback& callback) = 0; + // Creates and returns the global MediaTransferProtocolManager instance. // On Linux, |task_runner| specifies the task runner to process asynchronous // operations.
diff --git a/device/udev_linux/udev.cc b/device/udev_linux/udev.cc index 56f7b7e5..ae23bef 100644 --- a/device/udev_linux/udev.cc +++ b/device/udev_linux/udev.cc
@@ -54,6 +54,14 @@ return UdevLoader::Get()->udev_device_new_from_devnum(udev, type, devnum); } +udev_device* udev_device_new_from_subsystem_sysname( + udev* udev, + const char* subsystem, + const char* sysname) { + return UdevLoader::Get()->udev_device_new_from_subsystem_sysname( + udev, subsystem, sysname); +} + udev_device* udev_device_new_from_syspath(udev* udev, const char* syspath) { return UdevLoader::Get()->udev_device_new_from_syspath(udev, syspath); }
diff --git a/device/udev_linux/udev.h b/device/udev_linux/udev.h index d58960d5..2bb8df26 100644 --- a/device/udev_linux/udev.h +++ b/device/udev_linux/udev.h
@@ -42,6 +42,10 @@ const char* udev_device_get_sysname(udev_device* udev_device); const char* udev_device_get_syspath(udev_device* udev_device); udev_device* udev_device_new_from_devnum(udev* udev, char type, dev_t devnum); +udev_device* udev_device_new_from_subsystem_sysname( + udev* udev, + const char* subsystem, + const char* sysname); udev_device* udev_device_new_from_syspath(udev* udev, const char* syspath); void udev_device_unref(udev_device* udev_device); int udev_enumerate_add_match_subsystem(udev_enumerate* udev_enumerate,
diff --git a/device/udev_linux/udev0_loader.cc b/device/udev_linux/udev0_loader.cc index d70b2f2..9b0276ca 100644 --- a/device/udev_linux/udev0_loader.cc +++ b/device/udev_linux/udev0_loader.cc
@@ -70,6 +70,14 @@ return lib_loader_->udev_device_new_from_devnum(udev, type, devnum); } +udev_device* Udev0Loader::udev_device_new_from_subsystem_sysname( + udev* udev, + const char* subsystem, + const char* sysname) { + return lib_loader_->udev_device_new_from_subsystem_sysname( + udev, subsystem, sysname); +} + udev_device* Udev0Loader::udev_device_new_from_syspath(udev* udev, const char* syspath) { return lib_loader_->udev_device_new_from_syspath(udev, syspath);
diff --git a/device/udev_linux/udev0_loader.h b/device/udev_linux/udev0_loader.h index 2e48c7c7..8108ff9 100644 --- a/device/udev_linux/udev0_loader.h +++ b/device/udev_linux/udev0_loader.h
@@ -36,6 +36,10 @@ udev_device* udev_device_new_from_devnum(udev* udev, char type, dev_t devnum) override; + udev_device* udev_device_new_from_subsystem_sysname( + udev* udev, + const char* subsystem, + const char* sysname) override; udev_device* udev_device_new_from_syspath(udev* udev, const char* syspath) override; void udev_device_unref(udev_device* udev_device) override;
diff --git a/device/udev_linux/udev1_loader.cc b/device/udev_linux/udev1_loader.cc index ab741b9..34c2848e 100644 --- a/device/udev_linux/udev1_loader.cc +++ b/device/udev_linux/udev1_loader.cc
@@ -70,6 +70,14 @@ return lib_loader_->udev_device_new_from_devnum(udev, type, devnum); } +udev_device* Udev1Loader::udev_device_new_from_subsystem_sysname( + udev* udev, + const char* subsystem, + const char* sysname) { + return lib_loader_->udev_device_new_from_subsystem_sysname( + udev, subsystem, sysname); +} + udev_device* Udev1Loader::udev_device_new_from_syspath(udev* udev, const char* syspath) { return lib_loader_->udev_device_new_from_syspath(udev, syspath);
diff --git a/device/udev_linux/udev1_loader.h b/device/udev_linux/udev1_loader.h index 0c46c22..c765671 100644 --- a/device/udev_linux/udev1_loader.h +++ b/device/udev_linux/udev1_loader.h
@@ -36,6 +36,10 @@ udev_device* udev_device_new_from_devnum(udev* udev, char type, dev_t devnum) override; + udev_device* udev_device_new_from_subsystem_sysname( + udev* udev, + const char* subsystem, + const char* sysname) override; udev_device* udev_device_new_from_syspath(udev* udev, const char* syspath) override; void udev_device_unref(udev_device* udev_device) override;
diff --git a/device/udev_linux/udev_loader.h b/device/udev_linux/udev_loader.h index 9160a89..9d3837dd 100644 --- a/device/udev_linux/udev_loader.h +++ b/device/udev_linux/udev_loader.h
@@ -52,6 +52,10 @@ virtual udev_device* udev_device_new_from_devnum(udev* udev, char type, dev_t devnum) = 0; + virtual udev_device* udev_device_new_from_subsystem_sysname( + udev* udev, + const char* subsystem, + const char* sysname) = 0; virtual udev_device* udev_device_new_from_syspath(udev* udev, const char* syspath) = 0; virtual void udev_device_unref(udev_device* udev_device) = 0;
diff --git a/extensions/browser/api/app_window/app_window_api.cc b/extensions/browser/api/app_window/app_window_api.cc index f8cd74a..3f5123f 100644 --- a/extensions/browser/api/app_window/app_window_api.cc +++ b/extensions/browser/api/app_window/app_window_api.cc
@@ -182,7 +182,7 @@ view_id = created_view->GetRoutingID(); } - if (options->hidden.get() && !*options->hidden.get()) { + if (!options->hidden.get() || !*options->hidden.get()) { if (options->focused.get() && !*options->focused.get()) window->Show(AppWindow::SHOW_INACTIVE); else
diff --git a/extensions/browser/api/guest_view/guest_view_internal_api.cc b/extensions/browser/api/guest_view/guest_view_internal_api.cc index 0191220..6b70023 100644 --- a/extensions/browser/api/guest_view/guest_view_internal_api.cc +++ b/extensions/browser/api/guest_view/guest_view_internal_api.cc
@@ -39,6 +39,10 @@ return false; } + // Add flag to |create_params| to indicate that the element size is specified + // in logical units. + create_params->SetBoolean(guestview::kElementSizeIsLogical, true); + guest_view_manager->CreateGuest(view_type, sender_web_contents, *create_params,
diff --git a/extensions/browser/api/power/power_api.cc b/extensions/browser/api/power/power_api.cc index d731b9f..13dbbab1 100644 --- a/extensions/browser/api/power/power_api.cc +++ b/extensions/browser/api/power/power_api.cc
@@ -4,24 +4,128 @@ #include "extensions/browser/api/power/power_api.h" -#include "extensions/browser/api/power/power_api_manager.h" +#include "base/bind.h" +#include "base/lazy_instance.h" +#include "extensions/browser/extension_registry.h" #include "extensions/common/api/power.h" +#include "extensions/common/extension.h" namespace extensions { +namespace { + +const char kPowerSaveBlockerDescription[] = "extension"; + +content::PowerSaveBlocker::PowerSaveBlockerType LevelToPowerSaveBlockerType( + core_api::power::Level level) { + switch (level) { + case core_api::power::LEVEL_SYSTEM: + return content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension; + case core_api::power::LEVEL_DISPLAY: // fallthrough + case core_api::power::LEVEL_NONE: + return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep; + } + NOTREACHED() << "Unhandled level " << level; + return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep; +} + +base::LazyInstance<BrowserContextKeyedAPIFactory<PowerAPI>> g_factory = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + bool PowerRequestKeepAwakeFunction::RunSync() { scoped_ptr<core_api::power::RequestKeepAwake::Params> params( core_api::power::RequestKeepAwake::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); EXTENSION_FUNCTION_VALIDATE(params->level != core_api::power::LEVEL_NONE); - PowerApiManager::Get(browser_context())->AddRequest( - extension_id(), params->level); + PowerAPI::Get(browser_context())->AddRequest(extension_id(), params->level); return true; } bool PowerReleaseKeepAwakeFunction::RunSync() { - PowerApiManager::Get(browser_context())->RemoveRequest(extension_id()); + PowerAPI::Get(browser_context())->RemoveRequest(extension_id()); return true; } +// static +PowerAPI* PowerAPI::Get(content::BrowserContext* context) { + return BrowserContextKeyedAPIFactory<PowerAPI>::Get(context); +} + +// static +BrowserContextKeyedAPIFactory<PowerAPI>* PowerAPI::GetFactoryInstance() { + return g_factory.Pointer(); +} + +void PowerAPI::AddRequest(const std::string& extension_id, + core_api::power::Level level) { + extension_levels_[extension_id] = level; + UpdatePowerSaveBlocker(); +} + +void PowerAPI::RemoveRequest(const std::string& extension_id) { + extension_levels_.erase(extension_id); + UpdatePowerSaveBlocker(); +} + +void PowerAPI::SetCreateBlockerFunctionForTesting( + CreateBlockerFunction function) { + create_blocker_function_ = + !function.is_null() ? function + : base::Bind(&content::PowerSaveBlocker::Create); +} + +void PowerAPI::OnExtensionUnloaded(content::BrowserContext* browser_context, + const Extension* extension, + UnloadedExtensionInfo::Reason reason) { + RemoveRequest(extension->id()); + UpdatePowerSaveBlocker(); +} + +PowerAPI::PowerAPI(content::BrowserContext* context) + : browser_context_(context), + create_blocker_function_(base::Bind(&content::PowerSaveBlocker::Create)), + current_level_(core_api::power::LEVEL_SYSTEM) { + ExtensionRegistry::Get(browser_context_)->AddObserver(this); +} + +PowerAPI::~PowerAPI() { +} + +void PowerAPI::UpdatePowerSaveBlocker() { + if (extension_levels_.empty()) { + power_save_blocker_.reset(); + return; + } + + core_api::power::Level new_level = core_api::power::LEVEL_SYSTEM; + for (ExtensionLevelMap::const_iterator it = extension_levels_.begin(); + it != extension_levels_.end(); ++it) { + if (it->second == core_api::power::LEVEL_DISPLAY) + new_level = it->second; + } + + // If the level changed and we need to create a new blocker, do a swap + // to ensure that there isn't a brief period where power management is + // unblocked. + if (!power_save_blocker_ || new_level != current_level_) { + content::PowerSaveBlocker::PowerSaveBlockerType type = + LevelToPowerSaveBlockerType(new_level); + scoped_ptr<content::PowerSaveBlocker> new_blocker( + create_blocker_function_.Run(type, + content::PowerSaveBlocker::kReasonOther, + kPowerSaveBlockerDescription)); + power_save_blocker_.swap(new_blocker); + current_level_ = new_level; + } +} + +void PowerAPI::Shutdown() { + // Unregister here rather than in the d'tor; otherwise this call will recreate + // the already-deleted ExtensionRegistry. + ExtensionRegistry::Get(browser_context_)->RemoveObserver(this); + power_save_blocker_.reset(); +} + } // namespace extensions
diff --git a/extensions/browser/api/power/power_api.h b/extensions/browser/api/power/power_api.h index 228e517b..7a4a752d 100644 --- a/extensions/browser/api/power/power_api.h +++ b/extensions/browser/api/power/power_api.h
@@ -5,7 +5,20 @@ #ifndef EXTENSIONS_BROWSER_API_POWER_POWER_API_H_ #define EXTENSIONS_BROWSER_API_POWER_POWER_API_H_ +#include <map> +#include <string> + +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "content/public/browser/power_save_blocker.h" +#include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/browser/extension_function.h" +#include "extensions/browser/extension_registry_observer.h" +#include "extensions/common/api/power.h" + +namespace content { +class BrowserContext; +} namespace extensions { @@ -33,6 +46,77 @@ bool RunSync() override; }; +// Handles calls made via the chrome.power API. There is a separate instance of +// this class for each profile, as requests are tracked by extension ID, but a +// regular and incognito profile will share the same instance. +class PowerAPI : public BrowserContextKeyedAPI, + public extensions::ExtensionRegistryObserver { + public: + typedef base::Callback<scoped_ptr<content::PowerSaveBlocker>( + content::PowerSaveBlocker::PowerSaveBlockerType, + content::PowerSaveBlocker::Reason, + const std::string&)> CreateBlockerFunction; + + static PowerAPI* Get(content::BrowserContext* context); + + // BrowserContextKeyedAPI implementation. + static BrowserContextKeyedAPIFactory<PowerAPI>* GetFactoryInstance(); + + // Adds an extension lock at |level| for |extension_id|, replacing the + // extension's existing lock, if any. + void AddRequest(const std::string& extension_id, + core_api::power::Level level); + + // Removes an extension lock for an extension. Calling this for an + // extension id without a lock will do nothing. + void RemoveRequest(const std::string& extension_id); + + // Replaces the function that will be called to create PowerSaveBlocker + // objects. Passing an empty callback will revert to the default. + void SetCreateBlockerFunctionForTesting(CreateBlockerFunction function); + + // Overridden from extensions::ExtensionRegistryObserver. + void OnExtensionUnloaded(content::BrowserContext* browser_context, + const Extension* extension, + UnloadedExtensionInfo::Reason reason) override; + + private: + friend class BrowserContextKeyedAPIFactory<PowerAPI>; + + explicit PowerAPI(content::BrowserContext* context); + ~PowerAPI() override; + + // Updates |power_save_blocker_| and |current_level_| after iterating + // over |extension_levels_|. + void UpdatePowerSaveBlocker(); + + // BrowserContextKeyedAPI implementation. + static const char* service_name() { return "PowerAPI"; } + static const bool kServiceRedirectedInIncognito = true; + static const bool kServiceIsCreatedWithBrowserContext = false; + void Shutdown() override; + + content::BrowserContext* browser_context_; + + // Function that should be called to create PowerSaveBlocker objects. + // Tests can change this to record what would've been done instead of + // actually changing the system power-saving settings. + CreateBlockerFunction create_blocker_function_; + + scoped_ptr<content::PowerSaveBlocker> power_save_blocker_; + + // Current level used by |power_save_blocker_|. Meaningless if + // |power_save_blocker_| is NULL. + core_api::power::Level current_level_; + + // Map from extension ID to the corresponding level for each extension + // that has an outstanding request. + typedef std::map<std::string, core_api::power::Level> ExtensionLevelMap; + ExtensionLevelMap extension_levels_; + + DISALLOW_COPY_AND_ASSIGN(PowerAPI); +}; + } // namespace extensions #endif // EXTENSIONS_BROWSER_API_POWER_POWER_API_H_
diff --git a/extensions/browser/api/power/power_api_manager.cc b/extensions/browser/api/power/power_api_manager.cc deleted file mode 100644 index 642e794..0000000 --- a/extensions/browser/api/power/power_api_manager.cc +++ /dev/null
@@ -1,116 +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 "extensions/browser/api/power/power_api_manager.h" - -#include "base/bind.h" -#include "base/lazy_instance.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/common/extension.h" - -namespace extensions { - -namespace { - -const char kPowerSaveBlockerDescription[] = "extension"; - -content::PowerSaveBlocker::PowerSaveBlockerType -LevelToPowerSaveBlockerType(core_api::power::Level level) { - switch (level) { - case core_api::power::LEVEL_SYSTEM: - return content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension; - case core_api::power::LEVEL_DISPLAY: // fallthrough - case core_api::power::LEVEL_NONE: - return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep; - } - NOTREACHED() << "Unhandled level " << level; - return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep; -} - -base::LazyInstance<BrowserContextKeyedAPIFactory<PowerApiManager> > g_factory = - LAZY_INSTANCE_INITIALIZER; - -} // namespace - -// static -PowerApiManager* PowerApiManager::Get(content::BrowserContext* context) { - return BrowserContextKeyedAPIFactory<PowerApiManager>::Get(context); -} - -// static -BrowserContextKeyedAPIFactory<PowerApiManager>* -PowerApiManager::GetFactoryInstance() { - return g_factory.Pointer(); -} - -void PowerApiManager::AddRequest(const std::string& extension_id, - core_api::power::Level level) { - extension_levels_[extension_id] = level; - UpdatePowerSaveBlocker(); -} - -void PowerApiManager::RemoveRequest(const std::string& extension_id) { - extension_levels_.erase(extension_id); - UpdatePowerSaveBlocker(); -} - -void PowerApiManager::SetCreateBlockerFunctionForTesting( - CreateBlockerFunction function) { - create_blocker_function_ = !function.is_null() ? function : - base::Bind(&content::PowerSaveBlocker::Create); -} - -void PowerApiManager::OnExtensionUnloaded( - content::BrowserContext* browser_context, - const Extension* extension, - UnloadedExtensionInfo::Reason reason) { - RemoveRequest(extension->id()); - UpdatePowerSaveBlocker(); -} - -PowerApiManager::PowerApiManager(content::BrowserContext* context) - : browser_context_(context), - create_blocker_function_(base::Bind(&content::PowerSaveBlocker::Create)), - current_level_(core_api::power::LEVEL_SYSTEM) { - ExtensionRegistry::Get(browser_context_)->AddObserver(this); -} - -PowerApiManager::~PowerApiManager() {} - -void PowerApiManager::UpdatePowerSaveBlocker() { - if (extension_levels_.empty()) { - power_save_blocker_.reset(); - return; - } - - core_api::power::Level new_level = core_api::power::LEVEL_SYSTEM; - for (ExtensionLevelMap::const_iterator it = extension_levels_.begin(); - it != extension_levels_.end(); ++it) { - if (it->second == core_api::power::LEVEL_DISPLAY) - new_level = it->second; - } - - // If the level changed and we need to create a new blocker, do a swap - // to ensure that there isn't a brief period where power management is - // unblocked. - if (!power_save_blocker_ || new_level != current_level_) { - content::PowerSaveBlocker::PowerSaveBlockerType type = - LevelToPowerSaveBlockerType(new_level); - scoped_ptr<content::PowerSaveBlocker> new_blocker( - create_blocker_function_.Run(type, - content::PowerSaveBlocker::kReasonOther, - kPowerSaveBlockerDescription)); - power_save_blocker_.swap(new_blocker); - current_level_ = new_level; - } -} - -void PowerApiManager::Shutdown() { - // Unregister here rather than in the d'tor; otherwise this call will recreate - // the already-deleted ExtensionRegistry. - ExtensionRegistry::Get(browser_context_)->RemoveObserver(this); - power_save_blocker_.reset(); -} - -} // namespace extensions
diff --git a/extensions/browser/api/power/power_api_manager.h b/extensions/browser/api/power/power_api_manager.h deleted file mode 100644 index 4037811..0000000 --- a/extensions/browser/api/power/power_api_manager.h +++ /dev/null
@@ -1,98 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef EXTENSIONS_BROWSER_API_POWER_POWER_API_MANAGER_H_ -#define EXTENSIONS_BROWSER_API_POWER_POWER_API_MANAGER_H_ - -#include <map> -#include <string> - -#include "base/callback.h" -#include "base/memory/scoped_ptr.h" -#include "content/public/browser/power_save_blocker.h" -#include "extensions/browser/browser_context_keyed_api_factory.h" -#include "extensions/browser/extension_registry_observer.h" -#include "extensions/common/api/power.h" - -namespace content { -class BrowserContext; -} - -namespace extensions { - -// Handles calls made via the chrome.power API. There is a separate instance of -// this class for each profile, as requests are tracked by extension ID, but a -// regular and incognito profile will share the same instance. -// TODO(derat): Move this to power_api.h and rename it to PowerApi. -class PowerApiManager : public BrowserContextKeyedAPI, - public extensions::ExtensionRegistryObserver { - public: - typedef base::Callback<scoped_ptr<content::PowerSaveBlocker>( - content::PowerSaveBlocker::PowerSaveBlockerType, - content::PowerSaveBlocker::Reason, - const std::string&)> CreateBlockerFunction; - - static PowerApiManager* Get(content::BrowserContext* context); - - // BrowserContextKeyedAPI implementation. - static BrowserContextKeyedAPIFactory<PowerApiManager>* GetFactoryInstance(); - - // Adds an extension lock at |level| for |extension_id|, replacing the - // extension's existing lock, if any. - void AddRequest(const std::string& extension_id, - core_api::power::Level level); - - // Removes an extension lock for an extension. Calling this for an - // extension id without a lock will do nothing. - void RemoveRequest(const std::string& extension_id); - - // Replaces the function that will be called to create PowerSaveBlocker - // objects. Passing an empty callback will revert to the default. - void SetCreateBlockerFunctionForTesting(CreateBlockerFunction function); - - // Overridden from extensions::ExtensionRegistryObserver. - void OnExtensionUnloaded(content::BrowserContext* browser_context, - const Extension* extension, - UnloadedExtensionInfo::Reason reason) override; - - private: - friend class BrowserContextKeyedAPIFactory<PowerApiManager>; - - explicit PowerApiManager(content::BrowserContext* context); - ~PowerApiManager() override; - - // Updates |power_save_blocker_| and |current_level_| after iterating - // over |extension_levels_|. - void UpdatePowerSaveBlocker(); - - // BrowserContextKeyedAPI implementation. - static const char* service_name() { return "PowerApiManager"; } - static const bool kServiceRedirectedInIncognito = true; - static const bool kServiceIsCreatedWithBrowserContext = false; - void Shutdown() override; - - content::BrowserContext* browser_context_; - - // Function that should be called to create PowerSaveBlocker objects. - // Tests can change this to record what would've been done instead of - // actually changing the system power-saving settings. - CreateBlockerFunction create_blocker_function_; - - scoped_ptr<content::PowerSaveBlocker> power_save_blocker_; - - // Current level used by |power_save_blocker_|. Meaningless if - // |power_save_blocker_| is NULL. - core_api::power::Level current_level_; - - // Map from extension ID to the corresponding level for each extension - // that has an outstanding request. - typedef std::map<std::string, core_api::power::Level> ExtensionLevelMap; - ExtensionLevelMap extension_levels_; - - DISALLOW_COPY_AND_ASSIGN(PowerApiManager); -}; - -} // namespace extensions - -#endif // EXTENSIONS_BROWSER_API_POWER_POWER_API_MANAGER_H_
diff --git a/extensions/browser/api/power/power_api_unittest.cc b/extensions/browser/api/power/power_api_unittest.cc index e4e0a07..eb6c6a2 100644 --- a/extensions/browser/api/power/power_api_unittest.cc +++ b/extensions/browser/api/power/power_api_unittest.cc
@@ -12,7 +12,6 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "content/public/browser/power_save_blocker.h" -#include "extensions/browser/api/power/power_api_manager.h" #include "extensions/browser/api_test_utils.h" #include "extensions/browser/api_unittest.h" #include "extensions/common/extension.h" @@ -56,7 +55,7 @@ }; // Manages PowerSaveBlockerStub objects. Tests can instantiate this class -// to make PowerApiManager's calls to create PowerSaveBlockers record the +// to make PowerAPI's calls to create PowerSaveBlockers record the // actions that would've been performed instead of actually blocking and // unblocking power management. class PowerSaveBlockerStubManager { @@ -66,14 +65,14 @@ weak_ptr_factory_(this) { // Use base::Unretained since callbacks with return values can't use // weak pointers. - PowerApiManager::Get(browser_context_)->SetCreateBlockerFunctionForTesting( - base::Bind(&PowerSaveBlockerStubManager::CreateStub, - base::Unretained(this))); + PowerAPI::Get(browser_context_) + ->SetCreateBlockerFunctionForTesting(base::Bind( + &PowerSaveBlockerStubManager::CreateStub, base::Unretained(this))); } ~PowerSaveBlockerStubManager() { - PowerApiManager::Get(browser_context_)->SetCreateBlockerFunctionForTesting( - PowerApiManager::CreateBlockerFunction()); + PowerAPI::Get(browser_context_) + ->SetCreateBlockerFunctionForTesting(PowerAPI::CreateBlockerFunction()); } // Removes and returns the first item from |requests_|. Returns NONE if @@ -127,7 +126,7 @@ } // namespace -class PowerApiTest : public ApiUnitTest { +class PowerAPITest : public ApiUnitTest { public: void SetUp() override { ApiUnitTest::SetUp(); @@ -162,17 +161,18 @@ return api_test_utils::RunFunction(function.get(), args, browser_context()); } - // Send a notification to PowerApiManager saying that |extension| has + // Send a notification to PowerAPI saying that |extension| has // been unloaded. void UnloadExtension(const extensions::Extension* extension) { - PowerApiManager::Get(browser_context())->OnExtensionUnloaded( - browser_context(), extension, UnloadedExtensionInfo::REASON_UNINSTALL); + PowerAPI::Get(browser_context()) + ->OnExtensionUnloaded(browser_context(), extension, + UnloadedExtensionInfo::REASON_UNINSTALL); } scoped_ptr<PowerSaveBlockerStubManager> manager_; }; -TEST_F(PowerApiTest, RequestAndRelease) { +TEST_F(PowerAPITest, RequestAndRelease) { // Simulate an extension making and releasing a "display" request and a // "system" request. ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension())); @@ -190,7 +190,7 @@ EXPECT_EQ(NONE, manager_->PopFirstRequest()); } -TEST_F(PowerApiTest, RequestWithoutRelease) { +TEST_F(PowerAPITest, RequestWithoutRelease) { // Simulate an extension calling requestKeepAwake() without calling // releaseKeepAwake(). The override should be automatically removed when // the extension is unloaded. @@ -203,14 +203,14 @@ EXPECT_EQ(NONE, manager_->PopFirstRequest()); } -TEST_F(PowerApiTest, ReleaseWithoutRequest) { +TEST_F(PowerAPITest, ReleaseWithoutRequest) { // Simulate an extension calling releaseKeepAwake() without having // calling requestKeepAwake() earlier. The call should be ignored. ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension())); EXPECT_EQ(NONE, manager_->PopFirstRequest()); } -TEST_F(PowerApiTest, UpgradeRequest) { +TEST_F(PowerAPITest, UpgradeRequest) { // Simulate an extension calling requestKeepAwake("system") and then // requestKeepAwake("display"). When the second call is made, a // display-sleep-blocking request should be made before the initial @@ -229,7 +229,7 @@ EXPECT_EQ(NONE, manager_->PopFirstRequest()); } -TEST_F(PowerApiTest, DowngradeRequest) { +TEST_F(PowerAPITest, DowngradeRequest) { // Simulate an extension calling requestKeepAwake("display") and then // requestKeepAwake("system"). When the second call is made, an // app-suspension-blocking request should be made before the initial @@ -248,7 +248,7 @@ EXPECT_EQ(NONE, manager_->PopFirstRequest()); } -TEST_F(PowerApiTest, MultipleExtensions) { +TEST_F(PowerAPITest, MultipleExtensions) { // Simulate an extension blocking the display from sleeping. ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension())); EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
diff --git a/extensions/browser/api/printer_provider/printer_provider_api.cc b/extensions/browser/api/printer_provider/printer_provider_api.cc index a74838d..90749420 100644 --- a/extensions/browser/api/printer_provider/printer_provider_api.cc +++ b/extensions/browser/api/printer_provider/printer_provider_api.cc
@@ -471,8 +471,8 @@ core_api::printer_provider::PrintJob print_job; print_job.printer_id = internal_printer_id; - JSONStringValueSerializer serializer(job.ticket_json); - scoped_ptr<base::Value> ticket_value(serializer.Deserialize(NULL, NULL)); + JSONStringValueDeserializer deserializer(job.ticket_json); + scoped_ptr<base::Value> ticket_value(deserializer.Deserialize(NULL, NULL)); if (!ticket_value || !core_api::printer_provider::PrintJob::Ticket::Populate( *ticket_value, &print_job.ticket)) {
diff --git a/extensions/browser/api/printer_provider/printer_provider_apitest.cc b/extensions/browser/api/printer_provider/printer_provider_apitest.cc index 0a4662a4..84e47f7 100644 --- a/extensions/browser/api/printer_provider/printer_provider_apitest.cc +++ b/extensions/browser/api/printer_provider/printer_provider_apitest.cc
@@ -212,10 +212,10 @@ const std::vector<std::string>& expected_printers) { ASSERT_EQ(expected_printers.size(), printers.GetSize()); for (size_t i = 0; i < expected_printers.size(); ++i) { - JSONStringValueSerializer serializer(expected_printers[i]); + JSONStringValueDeserializer deserializer(expected_printers[i]); int error_code; scoped_ptr<base::Value> printer_value( - serializer.Deserialize(&error_code, NULL)); + deserializer.Deserialize(&error_code, NULL)); ASSERT_TRUE(printer_value) << "Failed to deserialize " << expected_printers[i] << ": " << "error code " << error_code;
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc index 0e036a6..7de492e 100644 --- a/extensions/browser/api/web_request/web_request_api.cc +++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -889,6 +889,8 @@ ExtractRequestInfo(request, dict); dict->SetString(keys::kStatusLineKey, original_response_headers->GetStatusLine()); + dict->SetInteger(keys::kStatusCodeKey, + original_response_headers->response_code()); if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) { dict->Set(keys::kResponseHeadersKey, GetResponseHeadersList(original_response_headers)); @@ -960,6 +962,8 @@ challenger->SetInteger(keys::kPortKey, auth_info.challenger.port()); dict->Set(keys::kChallengerKey, challenger); dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers())); + dict->SetInteger(keys::kStatusCodeKey, + request->response_headers()->response_code()); if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) { dict->Set(keys::kResponseHeadersKey, GetResponseHeadersList(request->response_headers()));
diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc index a508074..7d0e7c3 100644 --- a/extensions/browser/app_window/app_window.cc +++ b/extensions/browser/app_window/app_window.cc
@@ -238,6 +238,7 @@ is_hidden_(false), cached_always_on_top_(false), requested_alpha_enabled_(false), + is_ime_window_(false), image_loader_ptr_factory_(this) { ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get(); CHECK(!client->IsGuestSession(context) || context->IsOffTheRecord()) @@ -273,6 +274,8 @@ requested_alpha_enabled_ = new_params.alpha_enabled; + is_ime_window_ = params.is_ime_window; + AppWindowClient* app_window_client = AppWindowClient::Get(); native_app_window_.reset( app_window_client->CreateNativeAppWindow(this, &new_params));
diff --git a/extensions/browser/app_window/app_window.h b/extensions/browser/app_window/app_window.h index c7abf3d9..6c0e135 100644 --- a/extensions/browser/app_window/app_window.h +++ b/extensions/browser/app_window/app_window.h
@@ -351,6 +351,12 @@ // Whether the app window wants to be alpha enabled. bool requested_alpha_enabled() const { return requested_alpha_enabled_; } + // Whether the app window is created by IME extensions. + // TODO(bshe): rename to hide_app_window_in_launcher if it is not used + // anywhere other than app_window_launcher_controller after M45. Otherwise, + // remove this TODO. + bool is_ime_window() const { return is_ime_window_; } + void SetAppWindowContentsForTesting(scoped_ptr<AppWindowContents> contents) { app_window_contents_ = contents.Pass(); } @@ -559,6 +565,9 @@ // Whether |alpha_enabled| was set in the CreateParams. bool requested_alpha_enabled_; + // Whether |is_ime_window| was set in the CreateParams. + bool is_ime_window_; + base::WeakPtrFactory<AppWindow> image_loader_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(AppWindow);
diff --git a/extensions/browser/extension_function.cc b/extensions/browser/extension_function.cc index b970fe3..6a136b2c 100644 --- a/extensions/browser/extension_function.cc +++ b/extensions/browser/extension_function.cc
@@ -404,7 +404,7 @@ if (!results_) results_.reset(new base::ListValue()); - response_callback_.Run(type, *results_, GetError()); + response_callback_.Run(type, *results_, GetError(), histogram_value()); } void ExtensionFunction::OnRespondingLater(ResponseValue value) {
diff --git a/extensions/browser/extension_function.h b/extensions/browser/extension_function.h index 9385719..f9a2a79d 100644 --- a/extensions/browser/extension_function.h +++ b/extensions/browser/extension_function.h
@@ -100,9 +100,11 @@ BAD_MESSAGE }; - typedef base::Callback<void(ResponseType type, - const base::ListValue& results, - const std::string& error)> ResponseCallback; + using ResponseCallback = base::Callback<void( + ResponseType type, + const base::ListValue& results, + const std::string& error, + extensions::functions::HistogramValue histogram_value)>; ExtensionFunction();
diff --git a/extensions/browser/extension_function_dispatcher.cc b/extensions/browser/extension_function_dispatcher.cc index cbc08cca..fcf4ab4 100644 --- a/extensions/browser/extension_function_dispatcher.cc +++ b/extensions/browser/extension_function_dispatcher.cc
@@ -9,6 +9,7 @@ #include "base/lazy_instance.h" #include "base/logging.h" #include "base/memory/ref_counted.h" +#include "base/metrics/histogram_macros.h" #include "base/metrics/sparse_histogram.h" #include "base/process/process.h" #include "base/profiler/scoped_profile.h" @@ -81,9 +82,14 @@ base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER; // Kills the specified process because it sends us a malformed message. -void KillBadMessageSender(base::ProcessHandle process) { +// Track the specific function's |histogram_value|, as this may indicate a bug +// in that API's implementation on the renderer. +void KillBadMessageSender(base::ProcessHandle process, + functions::HistogramValue histogram_value) { NOTREACHED(); content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD")); + UMA_HISTOGRAM_ENUMERATION("Extensions.BadMessageFunctionName", + histogram_value, functions::ENUM_BOUNDARY); if (process) base::KillProcess(process, content::RESULT_CODE_KILLED_BAD_MESSAGE, false); } @@ -94,7 +100,8 @@ int request_id, ExtensionFunction::ResponseType type, const base::ListValue& results, - const std::string& error) { + const std::string& error, + functions::HistogramValue histogram_value) { DCHECK(ipc_sender); if (type == ExtensionFunction::BAD_MESSAGE) { @@ -108,9 +115,8 @@ // In single process mode it is better if we don't suicide but just crash. CHECK(false); } else { - KillBadMessageSender(peer_process); + KillBadMessageSender(peer_process, histogram_value); } - return; } @@ -125,17 +131,13 @@ int request_id, ExtensionFunction::ResponseType type, const base::ListValue& results, - const std::string& error) { + const std::string& error, + functions::HistogramValue histogram_value) { if (!ipc_sender.get()) return; - CommonResponseCallback(ipc_sender.get(), - routing_id, - ipc_sender->PeerHandle(), - request_id, - type, - results, - error); + CommonResponseCallback(ipc_sender.get(), routing_id, ipc_sender->PeerHandle(), + request_id, type, results, error, histogram_value); } } // namespace @@ -180,11 +182,11 @@ void OnExtensionFunctionCompleted(int request_id, ExtensionFunction::ResponseType type, const base::ListValue& results, - const std::string& error) { - CommonResponseCallback( - render_view_host_, render_view_host_->GetRoutingID(), - render_view_host_->GetProcess()->GetHandle(), request_id, type, - results, error); + const std::string& error, + functions::HistogramValue histogram_value) { + CommonResponseCallback(render_view_host_, render_view_host_->GetRoutingID(), + render_view_host_->GetProcess()->GetHandle(), + request_id, type, results, error, histogram_value); } base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_; @@ -438,7 +440,7 @@ const ExtensionFunction::ResponseCallback& callback) { if (!function->HasPermission()) { LOG(ERROR) << "Permission denied for " << params.name; - SendAccessDenied(callback); + SendAccessDenied(callback, function->histogram_value()); return false; } return true; @@ -457,7 +459,7 @@ ExtensionFunctionRegistry::GetInstance()->NewFunction(params.name); if (!function) { LOG(ERROR) << "Unknown Extension API - " << params.name; - SendAccessDenied(callback); + SendAccessDenied(callback, function->histogram_value()); return NULL; } @@ -478,10 +480,11 @@ // static void ExtensionFunctionDispatcher::SendAccessDenied( - const ExtensionFunction::ResponseCallback& callback) { + const ExtensionFunction::ResponseCallback& callback, + functions::HistogramValue histogram_value) { base::ListValue empty_list; callback.Run(ExtensionFunction::FAILED, empty_list, - "Access to extension API denied."); + "Access to extension API denied.", histogram_value); } } // namespace extensions
diff --git a/extensions/browser/extension_function_dispatcher.h b/extensions/browser/extension_function_dispatcher.h index 0ae80dc..9224bbde 100644 --- a/extensions/browser/extension_function_dispatcher.h +++ b/extensions/browser/extension_function_dispatcher.h
@@ -146,7 +146,8 @@ // Helper to run the response callback with an access denied error. Can be // called on any thread. static void SendAccessDenied( - const ExtensionFunction::ResponseCallback& callback); + const ExtensionFunction::ResponseCallback& callback, + functions::HistogramValue histogram_value); void DispatchWithCallbackInternal( const ExtensionHostMsg_Request_Params& params,
diff --git a/extensions/browser/extension_host.cc b/extensions/browser/extension_host.cc index 973c1a49..61d0626d 100644 --- a/extensions/browser/extension_host.cc +++ b/extensions/browser/extension_host.cc
@@ -13,8 +13,6 @@ #include "content/public/browser/content_browser_client.h" #include "content/public/browser/native_web_keyboard_event.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 "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" @@ -25,6 +23,7 @@ #include "extensions/browser/extension_host_delegate.h" #include "extensions/browser/extension_host_observer.h" #include "extensions/browser/extension_host_queue.h" +#include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/extensions_browser_client.h" #include "extensions/browser/load_monitoring_extension_host_queue.h" @@ -77,15 +76,15 @@ // Listen for when an extension is unloaded from the same profile, as it may // be the same extension that this points to. - registrar_.Add(this, - extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, - content::Source<BrowserContext>(browser_context_)); + ExtensionRegistry::Get(browser_context_)->AddObserver(this); // Set up web contents observers and pref observers. delegate_->OnExtensionHostCreated(host_contents()); } ExtensionHost::~ExtensionHost() { + ExtensionRegistry::Get(browser_context_)->RemoveObserver(this); + if (extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE && extension_ && BackgroundInfo::HasLazyBackgroundPage(extension_) && load_start_.get()) { @@ -210,23 +209,15 @@ return true; } -void ExtensionHost::Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - switch (type) { - case extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: - // The extension object will be deleted after this notification has been - // sent. Null it out so that dirty pointer issues don't arise in cases - // when multiple ExtensionHost objects pointing to the same Extension are - // present. - if (extension_ == content::Details<UnloadedExtensionInfo>(details)-> - extension) { - extension_ = nullptr; - } - break; - default: - NOTREACHED() << "Unexpected notification sent."; - break; +void ExtensionHost::OnExtensionUnloaded( + content::BrowserContext* browser_context, + const Extension* extension, + UnloadedExtensionInfo::Reason reason) { + // The extension object will be deleted after this notification has been sent. + // Null it out so that dirty pointer issues don't arise in cases when multiple + // ExtensionHost objects pointing to the same Extension are present. + if (extension_ == extension) { + extension_ = nullptr; } }
diff --git a/extensions/browser/extension_host.h b/extensions/browser/extension_host.h index 953dc99..c308874 100644 --- a/extensions/browser/extension_host.h +++ b/extensions/browser/extension_host.h
@@ -7,18 +7,16 @@ #include <set> #include <string> -#include <vector> #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/observer_list.h" #include "base/timer/elapsed_timer.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" #include "extensions/browser/deferred_start_render_host.h" #include "extensions/browser/extension_function_dispatcher.h" +#include "extensions/browser/extension_registry_observer.h" #include "extensions/common/stack_frame.h" #include "extensions/common/view_type.h" @@ -49,7 +47,7 @@ public content::WebContentsDelegate, public content::WebContentsObserver, public ExtensionFunctionDispatcher::Delegate, - public content::NotificationObserver { + public ExtensionRegistryObserver { public: ExtensionHost(const Extension* extension, content::SiteInstance* site_instance, @@ -127,14 +125,12 @@ content::MediaStreamType type) override; bool IsNeverVisible(content::WebContents* web_contents) override; - // content::NotificationObserver: - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; + // ExtensionRegistryObserver: + void OnExtensionUnloaded(content::BrowserContext* browser_context, + const Extension* extension, + UnloadedExtensionInfo::Reason reason) override; protected: - content::NotificationRegistrar* registrar() { return ®istrar_; } - // Called after the extension page finishes loading but before the // EXTENSION_HOST_DID_STOP_LOADING notification is sent. virtual void OnDidStopLoading(); @@ -191,8 +187,6 @@ // Messages sent out to the renderer that have not been acknowledged yet. std::set<int> unacked_messages_; - content::NotificationRegistrar registrar_; - ExtensionFunctionDispatcher extension_function_dispatcher_; // The type of view being hosted.
diff --git a/extensions/browser/extension_icon_image_unittest.cc b/extensions/browser/extension_icon_image_unittest.cc index 24d0ac2..3fb4e691 100644 --- a/extensions/browser/extension_icon_image_unittest.cc +++ b/extensions/browser/extension_icon_image_unittest.cc
@@ -150,10 +150,11 @@ test_file = test_file.AppendASCII(name); int error_code = 0; std::string error; - JSONFileValueSerializer serializer(test_file.AppendASCII("manifest.json")); + JSONFileValueDeserializer deserializer( + test_file.AppendASCII("manifest.json")); scoped_ptr<base::DictionaryValue> valid_value( - static_cast<base::DictionaryValue*>(serializer.Deserialize(&error_code, - &error))); + static_cast<base::DictionaryValue*>( + deserializer.Deserialize(&error_code, &error))); EXPECT_EQ(0, error_code) << error; if (error_code != 0) return NULL;
diff --git a/extensions/browser/external_provider_interface.h b/extensions/browser/external_provider_interface.h index d14fc7c..801f4ed 100644 --- a/extensions/browser/external_provider_interface.h +++ b/extensions/browser/external_provider_interface.h
@@ -40,7 +40,8 @@ const base::FilePath& path, Manifest::Location location, int creation_flags, - bool mark_acknowledged) = 0; + bool mark_acknowledged, + bool install_immediately) = 0; // Return true if the extension install will proceed. Install might not // proceed if the extension is already installed from a higher priority
diff --git a/extensions/browser/guest_view/guest_view_base.cc b/extensions/browser/guest_view/guest_view_base.cc index b7bf687..7e556871 100644 --- a/extensions/browser/guest_view/guest_view_base.cc +++ b/extensions/browser/guest_view/guest_view_base.cc
@@ -754,9 +754,21 @@ double element_width = 0.0; params.GetDouble(guestview::kElementHeight, &element_height); params.GetDouble(guestview::kElementWidth, &element_width); - // Convert the element size from logical pixels to physical pixels. - int normal_height = LogicalPixelsToPhysicalPixels(element_height); - int normal_width = LogicalPixelsToPhysicalPixels(element_width); + + // If the element size was provided in logical units (versus physical), then + // it will be converted to physical units. + bool element_size_is_logical = false; + params.GetBoolean(guestview::kElementSizeIsLogical, &element_size_is_logical); + int normal_height = 0; + int normal_width = 0; + if (element_size_is_logical) { + // Convert the element size from logical pixels to physical pixels. + normal_height = LogicalPixelsToPhysicalPixels(element_height); + normal_width = LogicalPixelsToPhysicalPixels(element_width); + } else { + normal_height = lround(element_height); + normal_width = lround(element_width); + } SetSizeParams set_size_params; set_size_params.enable_auto_size.reset(new bool(auto_size_enabled));
diff --git a/extensions/browser/image_loader_unittest.cc b/extensions/browser/image_loader_unittest.cc index d67ed98f..f1f2aad 100644 --- a/extensions/browser/image_loader_unittest.cc +++ b/extensions/browser/image_loader_unittest.cc
@@ -10,9 +10,11 @@ #include "base/path_service.h" #include "base/strings/string_util.h" #include "content/public/browser/notification_service.h" +#include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread.h" +#include "extensions/browser/extension_registry.h" #include "extensions/browser/extensions_browser_client.h" -#include "extensions/browser/notification_types.h" +#include "extensions/browser/extensions_test.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/extension_icon_set.h" @@ -32,7 +34,7 @@ namespace extensions { -class ImageLoaderTest : public testing::Test { +class ImageLoaderTest : public ExtensionsTest { public: ImageLoaderTest() : image_loaded_count_(0), @@ -79,11 +81,11 @@ extension_dir = extension_dir.AppendASCII(dir_name); int error_code = 0; std::string error; - JSONFileValueSerializer serializer( + JSONFileValueDeserializer deserializer( extension_dir.AppendASCII("manifest.json")); scoped_ptr<base::DictionaryValue> valid_value( - static_cast<base::DictionaryValue*>(serializer.Deserialize(&error_code, - &error))); + static_cast<base::DictionaryValue*>( + deserializer.Deserialize(&error_code, &error))); EXPECT_EQ(0, error_code) << error; if (error_code != 0) return NULL; @@ -174,12 +176,8 @@ EXPECT_EQ(0, image_loaded_count()); // Send out notification the extension was uninstalled. - UnloadedExtensionInfo details(extension.get(), - UnloadedExtensionInfo::REASON_UNINSTALL); - content::NotificationService::current()->Notify( - NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, - content::NotificationService::AllSources(), - content::Details<UnloadedExtensionInfo>(&details)); + ExtensionRegistry::Get(browser_context())->TriggerOnUnloaded( + extension.get(), UnloadedExtensionInfo::REASON_UNINSTALL); // Chuck the extension, that way if anyone tries to access it we should crash // or get valgrind errors.
diff --git a/extensions/browser/user_script_loader.cc b/extensions/browser/user_script_loader.cc index 2b836332..ab7aaaea 100644 --- a/extensions/browser/user_script_loader.cc +++ b/extensions/browser/user_script_loader.cc
@@ -444,11 +444,24 @@ // We've got scripts ready to go. shared_memory_.reset(shared_memory.release()); - for (content::RenderProcessHost::iterator i( - content::RenderProcessHost::AllHostsIterator()); - !i.IsAtEnd(); - i.Advance()) { - SendUpdate(i.GetCurrentValue(), shared_memory_.get(), changed_hosts_); + // If user scripts are coming from a <webview>, will only notify the + // RenderProcessHost of that <webview>; otherwise will notify all of the + // RenderProcessHosts. + if (user_scripts && !user_scripts->empty() && + (*user_scripts)[0].consumer_instance_type() == + UserScript::ConsumerInstanceType::WEBVIEW) { + DCHECK_EQ(1u, user_scripts->size()); + int render_process_id = (*user_scripts)[0].routing_info().render_process_id; + content::RenderProcessHost* host = + content::RenderProcessHost::FromID(render_process_id); + if (host) + SendUpdate(host, shared_memory_.get(), changed_hosts_); + } else { + for (content::RenderProcessHost::iterator i( + content::RenderProcessHost::AllHostsIterator()); + !i.IsAtEnd(); i.Advance()) { + SendUpdate(i.GetCurrentValue(), shared_memory_.get(), changed_hosts_); + } } changed_hosts_.clear();
diff --git a/extensions/common/api/_manifest_features.json b/extensions/common/api/_manifest_features.json index 0d04b6d..8a1966d8 100644 --- a/extensions/common/api/_manifest_features.json +++ b/extensions/common/api/_manifest_features.json
@@ -86,13 +86,16 @@ "81986D4F846CEDDDB962643FA501D1780DD441BB" // http://crbug.com/407693 ] }], - "content_capabilities": { + "content_capabilities": [{ "channel": "stable", "extension_types": ["extension"], "whitelist": [ "950D13BB9B4794F4CA2A68D3597E5DFAA47C88AE" // Drive ] - }, + }, { + "channel": "canary", + "extension_types": ["extension"] + }], "content_security_policy": { "channel": "stable", // Platform apps have a restricted content security policy that cannot be
diff --git a/extensions/common/api/app_window.idl b/extensions/common/api/app_window.idl index 18247037..04c8a43 100644 --- a/extensions/common/api/app_window.idl +++ b/extensions/common/api/app_window.idl
@@ -331,10 +331,10 @@ static void restore(); // Move the window to the position (|left|, |top|). - static void moveTo(long left, long top); + [deprecated="Use outerBounds."] static void moveTo(long left, long top); // Resize the window to |width|x|height| pixels in size. - static void resizeTo(long width, long height); + [deprecated="Use outerBounds."] static void resizeTo(long width, long height); // Draw attention to the window. static void drawAttention();
diff --git a/extensions/common/api/web_request.json b/extensions/common/api/web_request.json index 5d279c76..200bfa9 100644 --- a/extensions/common/api/web_request.json +++ b/extensions/common/api/web_request.json
@@ -289,7 +289,8 @@ "type": {"type": "string", "enum": ["main_frame", "sub_frame", "stylesheet", "script", "image", "object", "xmlhttprequest", "other"], "description": "How the requested resource will be used."}, "timeStamp": {"type": "number", "description": "The time when this signal is triggered, in milliseconds since the epoch."}, "statusLine": {"type": "string", "description": "HTTP status line of the response or the 'HTTP/0.9 200 OK' string for HTTP/0.9 responses (i.e., responses that lack a status line)."}, - "responseHeaders": {"$ref": "HttpHeaders", "optional": true, "description": "The HTTP response headers that have been received with this response."} + "responseHeaders": {"$ref": "HttpHeaders", "optional": true, "description": "The HTTP response headers that have been received with this response."}, + "statusCode": {"type": "integer", "description": "Standard HTTP status code returned by the server."} } } ], @@ -339,7 +340,8 @@ "challenger": {"type": "object", "description": "The server requesting authentication.", "properties": {"host": {"type": "string"}, "port": {"type": "integer"}}}, "isProxy": {"type": "boolean", "description": "True for Proxy-Authenticate, false for WWW-Authenticate."}, "responseHeaders": {"$ref": "HttpHeaders", "optional": true, "description": "The HTTP response headers that were received along with this response."}, - "statusLine": {"type": "string", "description": "HTTP status line of the response or the 'HTTP/0.9 200 OK' string for HTTP/0.9 responses (i.e., responses that lack a status line) or an empty string if there are no headers."} + "statusLine": {"type": "string", "description": "HTTP status line of the response or the 'HTTP/0.9 200 OK' string for HTTP/0.9 responses (i.e., responses that lack a status line) or an empty string if there are no headers."}, + "statusCode": {"type": "integer", "description": "Standard HTTP status code returned by the server."} } }, {
diff --git a/extensions/common/extension_l10n_util.cc b/extensions/common/extension_l10n_util.cc index e60e2ec7..dbdd5d9 100644 --- a/extensions/common/extension_l10n_util.cc +++ b/extensions/common/extension_l10n_util.cc
@@ -38,8 +38,8 @@ std::string* error) { base::FilePath file = locale_path.AppendASCII(locale).Append(extensions::kMessagesFilename); - JSONFileValueSerializer messages_serializer(file); - base::Value* dictionary = messages_serializer.Deserialize(NULL, error); + JSONFileValueDeserializer messages_deserializer(file); + base::Value* dictionary = messages_deserializer.Deserialize(NULL, error); if (!dictionary) { if (error->empty()) { // JSONFileValueSerializer just returns NULL if file cannot be found. It
diff --git a/extensions/common/file_util.cc b/extensions/common/file_util.cc index e0ce3399..399b6e7 100644 --- a/extensions/common/file_util.cc +++ b/extensions/common/file_util.cc
@@ -168,8 +168,8 @@ return NULL; } - JSONFileValueSerializer serializer(manifest_path); - scoped_ptr<base::Value> root(serializer.Deserialize(NULL, error)); + JSONFileValueDeserializer deserializer(manifest_path); + scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, error)); if (!root.get()) { if (error->empty()) { // If |error| is empty, than the file could not be read.
diff --git a/extensions/common/file_util_unittest.cc b/extensions/common/file_util_unittest.cc index 7e2f51d..750f598 100644 --- a/extensions/common/file_util_unittest.cc +++ b/extensions/common/file_util_unittest.cc
@@ -43,8 +43,8 @@ Manifest::Location location, int extra_flags, std::string* error) { - JSONStringValueSerializer serializer(manifest_value); - scoped_ptr<base::Value> result(serializer.Deserialize(NULL, error)); + JSONStringValueDeserializer deserializer(manifest_value); + scoped_ptr<base::Value> result(deserializer.Deserialize(NULL, error)); if (!result.get()) return NULL; CHECK_EQ(base::Value::TYPE_DICTIONARY, result->GetType());
diff --git a/extensions/common/guest_view/guest_view_constants.cc b/extensions/common/guest_view/guest_view_constants.cc index 3ce10726..f478c64a 100644 --- a/extensions/common/guest_view/guest_view_constants.cc +++ b/extensions/common/guest_view/guest_view_constants.cc
@@ -14,6 +14,7 @@ const char kAttributeMinWidth[] = "minwidth"; const char kElementWidth[] = "elementWidth"; const char kElementHeight[] = "elementHeight"; +const char kElementSizeIsLogical[] = "elementSizeIsLogical"; // Events. const char kEventResize[] = "guestViewInternal.onResize";
diff --git a/extensions/common/guest_view/guest_view_constants.h b/extensions/common/guest_view/guest_view_constants.h index f42cab7d..16bf023 100644 --- a/extensions/common/guest_view/guest_view_constants.h +++ b/extensions/common/guest_view/guest_view_constants.h
@@ -17,6 +17,7 @@ extern const char kAttributeMinWidth[]; extern const char kElementWidth[]; extern const char kElementHeight[]; +extern const char kElementSizeIsLogical[]; // Events. extern const char kEventResize[];
diff --git a/extensions/common/manifest_test.cc b/extensions/common/manifest_test.cc index 14e0aef..a3712d0 100644 --- a/extensions/common/manifest_test.cc +++ b/extensions/common/manifest_test.cc
@@ -26,9 +26,9 @@ EXPECT_TRUE(base::PathExists(manifest_path)) << "Couldn't find " << manifest_path.value(); - JSONFileValueSerializer serializer(manifest_path); - base::DictionaryValue* manifest = - static_cast<base::DictionaryValue*>(serializer.Deserialize(NULL, error)); + JSONFileValueDeserializer deserializer(manifest_path); + base::DictionaryValue* manifest = static_cast<base::DictionaryValue*>( + deserializer.Deserialize(NULL, error)); // Most unit tests don't need localization, and they'll fail if we try to // localize them, since their manifests don't have a default_locale key.
diff --git a/extensions/common/user_script.cc b/extensions/common/user_script.cc index b8ba22e1..ea7b6a7 100644 --- a/extensions/common/user_script.cc +++ b/extensions/common/user_script.cc
@@ -81,6 +81,7 @@ UserScript::UserScript() : run_location_(DOCUMENT_IDLE), + consumer_instance_type_(TAB), user_script_id_(-1), emulate_greasemonkey_(false), match_all_frames_(false), @@ -145,6 +146,8 @@ pickle->WriteBool(is_incognito_enabled()); PickleHostID(pickle, host_id_); + pickle->WriteInt(consumer_instance_type()); + PickleRoutingInfo(pickle, routing_info_); PickleGlobs(pickle, globs_); PickleGlobs(pickle, exclude_globs_); PickleURLPatternSet(pickle, url_set_); @@ -167,6 +170,12 @@ pickle->WriteString(host_id.id()); } +void UserScript::PickleRoutingInfo(::Pickle* pickle, + const RoutingInfo& routing_info) const { + pickle->WriteInt(routing_info.render_process_id); + pickle->WriteInt(routing_info.render_view_id); +} + void UserScript::PickleURLPatternSet(::Pickle* pickle, const URLPatternSet& pattern_list) const { pickle->WriteSizeT(pattern_list.patterns().size()); @@ -200,6 +209,13 @@ CHECK(iter->ReadBool(&incognito_enabled_)); UnpickleHostID(pickle, iter, &host_id_); + + int consumer_instance_type = 0; + CHECK(iter->ReadInt(&consumer_instance_type)); + consumer_instance_type_ = + static_cast<ConsumerInstanceType>(consumer_instance_type); + + UnpickleRoutingInfo(pickle, iter, &routing_info_); UnpickleGlobs(pickle, iter, &globs_); UnpickleGlobs(pickle, iter, &exclude_globs_); UnpickleURLPatternSet(pickle, iter, &url_set_); @@ -230,6 +246,13 @@ *host_id = HostID(static_cast<HostID::HostType>(type), id); } +void UserScript::UnpickleRoutingInfo(const ::Pickle& pickle, + PickleIterator* iter, + RoutingInfo* routing_info) { + CHECK(iter->ReadInt(&routing_info->render_process_id)); + CHECK(iter->ReadInt(&routing_info->render_view_id)); +} + void UserScript::UnpickleURLPatternSet(const ::Pickle& pickle, PickleIterator* iter, URLPatternSet* pattern_list) {
diff --git a/extensions/common/user_script.h b/extensions/common/user_script.h index 6069161..48e31cd 100644 --- a/extensions/common/user_script.h +++ b/extensions/common/user_script.h
@@ -126,6 +126,19 @@ typedef std::vector<File> FileList; + // Render's routing info of a <webview> that the user script will be injected + // on. Only user scripts from <webview>s have a custom routing info. + struct RoutingInfo { + RoutingInfo() : render_process_id(-1), render_view_id(-1) {} + ~RoutingInfo() {} + + int render_process_id; + int render_view_id; + }; + + // Type of a API consumer instance that user scripts will be injected on. + enum ConsumerInstanceType { TAB, WEBVIEW }; + // Constructor. Default the run location to document end, which is like // Greasemonkey and probably more useful for typical scripts. UserScript(); @@ -200,6 +213,19 @@ const HostID& host_id() const { return host_id_; } void set_host_id(const HostID& host_id) { host_id_ = host_id; } + const ConsumerInstanceType& consumer_instance_type() const { + return consumer_instance_type_; + } + void set_consumer_instance_type( + const ConsumerInstanceType& consumer_instance_type) { + consumer_instance_type_ = consumer_instance_type; + } + + const RoutingInfo& routing_info() const { return routing_info_; } + void set_routing_info(const RoutingInfo& routing_info) { + routing_info_ = routing_info; + } + int id() const { return user_script_id_; } void set_id(int id) { user_script_id_ = id; } @@ -226,6 +252,8 @@ void PickleGlobs(::Pickle* pickle, const std::vector<std::string>& globs) const; void PickleHostID(::Pickle* pickle, const HostID& host_id) const; + void PickleRoutingInfo(::Pickle* pickle, + const RoutingInfo& routing_info) const; void PickleURLPatternSet(::Pickle* pickle, const URLPatternSet& pattern_list) const; void PickleScripts(::Pickle* pickle, const FileList& scripts) const; @@ -236,6 +264,9 @@ void UnpickleHostID(const ::Pickle& pickle, PickleIterator* iter, HostID* host_id); + void UnpickleRoutingInfo(const ::Pickle& pickle, + PickleIterator* iter, + RoutingInfo* routing_info); void UnpickleURLPatternSet(const ::Pickle& pickle, PickleIterator* iter, URLPatternSet* pattern_list); void UnpickleScripts(const ::Pickle& pickle, PickleIterator* iter, @@ -278,6 +309,12 @@ // |host_id| can be empty if the script is a "standlone" user script. HostID host_id_; + // The type of the consumer instance that the script will be injected. + ConsumerInstanceType consumer_instance_type_; + + // The render side's rounting info for content_scripts of <webview>. + RoutingInfo routing_info_; + // The globally-unique id associated with this user script. Defaults to // -1 for invalid. int user_script_id_;
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi index bc780bab..20ed947 100644 --- a/extensions/extensions.gypi +++ b/extensions/extensions.gypi
@@ -383,8 +383,6 @@ 'browser/api/networking_private/networking_private_event_router_factory.h', 'browser/api/power/power_api.cc', 'browser/api/power/power_api.h', - 'browser/api/power/power_api_manager.cc', - 'browser/api/power/power_api_manager.h', 'browser/api/printer_provider/printer_provider_api.cc', 'browser/api/printer_provider/printer_provider_api.h', 'browser/api/printer_provider/printer_provider_api_factory.cc', @@ -972,6 +970,8 @@ 'renderer/v8_context_native_handler.h', 'renderer/v8_schema_registry.cc', 'renderer/v8_schema_registry.h', + 'renderer/web_ui_injection_host.cc', + 'renderer/web_ui_injection_host.h', ], 'extensions_utility_sources': [ 'utility/unpacker.cc',
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 4fd36a0..38c3e03 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc
@@ -194,11 +194,11 @@ webrequest_used_(false) { const base::CommandLine& command_line = *(base::CommandLine::ForCurrentProcess()); - is_extension_process_ = + set_idle_notifications_ = command_line.HasSwitch(switches::kExtensionProcess) || command_line.HasSwitch(::switches::kSingleProcess); - if (is_extension_process_) { + if (set_idle_notifications_) { RenderThread::Get()->SetIdleNotificationDelayInMs( kInitialExtensionIdleHandlerDelayMs); } @@ -528,7 +528,7 @@ // Reset the idle handler each time there's any activity like event or message // dispatch, for which Invoke is the chokepoint. - if (is_extension_process_) { + if (set_idle_notifications_) { RenderThread::Get()->ScheduleIdleHandler( kInitialExtensionIdleHandlerDelayMs); } @@ -830,7 +830,7 @@ void Dispatcher::WebKitInitialized() { // For extensions, we want to ensure we call the IdleHandler every so often, // even if the extension keeps up activity. - if (is_extension_process_) { + if (set_idle_notifications_) { forced_idle_timer_.reset(new base::RepeatingTimer<content::RenderThread>); forced_idle_timer_->Start( FROM_HERE, @@ -856,7 +856,7 @@ } void Dispatcher::IdleNotification() { - if (is_extension_process_ && forced_idle_timer_) { + if (set_idle_notifications_ && forced_idle_timer_) { // Dampen the forced delay as well if the extension stays idle for long // periods of time. (forced_idle_timer_ can be NULL after // OnRenderProcessShutdown has been called.) @@ -1036,6 +1036,8 @@ extensions_.Remove(id); active_extension_ids_.erase(id); + script_injection_manager_->OnExtensionUnloaded(id); + // If the extension is later reloaded with a different set of permissions, // we'd like it to get a new isolated world ID, so that it can pick up the // changed origin whitelist.
diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h index 44cb751..2e976a4db 100644 --- a/extensions/renderer/dispatcher.h +++ b/extensions/renderer/dispatcher.h
@@ -72,8 +72,6 @@ return function_names_; } - bool is_extension_process() const { return is_extension_process_; } - const ExtensionSet* extensions() const { return &extensions_; } const ScriptContextSet& script_context_set() const { @@ -267,8 +265,8 @@ // Dispatcher's own lifetime. DispatcherDelegate* delegate_; - // True if this renderer is running extensions. - bool is_extension_process_; + // True if the IdleNotification timer should be set. + bool set_idle_notifications_; // Contains all loaded extensions. This is essentially the renderer // counterpart to ExtensionService in the browser. It contains information
diff --git a/extensions/renderer/extension_injection_host.cc b/extensions/renderer/extension_injection_host.cc index 5b3c463..7a27a08 100644 --- a/extensions/renderer/extension_injection_host.cc +++ b/extensions/renderer/extension_injection_host.cc
@@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "extensions/common/extension_set.h" #include "extensions/common/manifest_handlers/csp_info.h" #include "extensions/renderer/extension_injection_host.h" namespace extensions { ExtensionInjectionHost::ExtensionInjectionHost( - const scoped_refptr<const Extension>& extension) + const Extension* extension) : InjectionHost(HostID(HostID::EXTENSIONS, extension->id())), extension_(extension) { } @@ -16,8 +17,18 @@ ExtensionInjectionHost::~ExtensionInjectionHost() { } -const std::string& ExtensionInjectionHost::GetContentSecurityPolicy() const { - return CSPInfo::GetContentSecurityPolicy(extension_.get()); +// static +scoped_ptr<const ExtensionInjectionHost> ExtensionInjectionHost::Create( + const std::string& extension_id, const ExtensionSet* extensions) { + const Extension* extension = extensions->GetByID(extension_id); + if (!extension) + return scoped_ptr<const ExtensionInjectionHost>(); + return scoped_ptr<const ExtensionInjectionHost>( + new ExtensionInjectionHost(extension)); +} + +std::string ExtensionInjectionHost::GetContentSecurityPolicy() const { + return CSPInfo::GetContentSecurityPolicy(extension_); } const GURL& ExtensionInjectionHost::url() const { @@ -29,16 +40,21 @@ } PermissionsData::AccessType ExtensionInjectionHost::CanExecuteOnFrame( - const GURL& document_url, - const GURL& top_frame_url, - int tab_id, - bool is_declarative) const { + const GURL& document_url, + const GURL& top_frame_url, + int tab_id, + bool is_declarative) const { + // If we don't have a tab id, we have no UI surface to ask for user consent. + // For now, we treat this as an automatic allow. + if (tab_id == -1) + return PermissionsData::ACCESS_ALLOWED; + // Declarative user scripts use "page access" (from "permissions" section in // manifest) whereas non-declarative user scripts use custom // "content script access" logic. if (is_declarative) { return extension_->permissions_data()->GetPageAccess( - extension_.get(), + extension_, document_url, top_frame_url, tab_id, @@ -46,7 +62,7 @@ nullptr /* ignore error */); } else { return extension_->permissions_data()->GetContentScriptAccess( - extension_.get(), + extension_, document_url, top_frame_url, tab_id, @@ -61,7 +77,7 @@ // otherwise been affected by the scripts-require-action feature. return extension_->permissions_data()->withheld_permissions()->IsEmpty() && PermissionsData::ScriptsMayRequireActionForExtension( - extension_.get(), + extension_, extension_->permissions_data()->active_permissions().get()); }
diff --git a/extensions/renderer/extension_injection_host.h b/extensions/renderer/extension_injection_host.h index d940c94..bdf6f41 100644 --- a/extensions/renderer/extension_injection_host.h +++ b/extensions/renderer/extension_injection_host.h
@@ -10,17 +10,23 @@ #include "extensions/renderer/injection_host.h" namespace extensions { +class ExtensionSet; // A wrapper class that holds an extension and implements the InjectionHost // interface. class ExtensionInjectionHost : public InjectionHost { public: - ExtensionInjectionHost(const scoped_refptr<const Extension>& extension); + ExtensionInjectionHost(const Extension* extension); ~ExtensionInjectionHost() override; + // Create an ExtensionInjectionHost object. If the extension is gone, returns + // a null scoped ptr. + static scoped_ptr<const ExtensionInjectionHost> Create( + const std::string& extension_id, const ExtensionSet* extensions); + private: // InjectionHost: - const std::string& GetContentSecurityPolicy() const override; + std::string GetContentSecurityPolicy() const override; const GURL& url() const override; const std::string& name() const override; PermissionsData::AccessType CanExecuteOnFrame( @@ -30,7 +36,7 @@ bool is_declarative) const override; bool ShouldNotifyBrowserOfInjection() const override; - scoped_refptr<const Extension> extension_; + const Extension* extension_; DISALLOW_COPY_AND_ASSIGN(ExtensionInjectionHost); };
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 49dae79..ff18e04b 100644 --- a/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc +++ b/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc
@@ -11,6 +11,7 @@ #include "content/public/renderer/render_view.h" #include "extensions/common/extension.h" #include "extensions/common/extension_messages.h" +#include "extensions/common/guest_view/guest_view_constants.h" #include "extensions/renderer/guest_view/extensions_guest_view_container.h" #include "extensions/renderer/script_context.h" #include "v8/include/v8.h" @@ -74,6 +75,10 @@ static_cast<base::DictionaryValue*>(params_as_value.release())); } + // Add flag to |params| to indicate that the element size is specified in + // logical units. + params->SetBoolean(guestview::kElementSizeIsLogical, true); + linked_ptr<ExtensionsGuestViewContainer::Request> request( new ExtensionsGuestViewContainer::AttachRequest( guest_view_container,
diff --git a/extensions/renderer/injection_host.h b/extensions/renderer/injection_host.h index 6c23c2d3..4dcb225 100644 --- a/extensions/renderer/injection_host.h +++ b/extensions/renderer/injection_host.h
@@ -15,7 +15,7 @@ InjectionHost(const HostID& host_id); virtual ~InjectionHost(); - virtual const std::string& GetContentSecurityPolicy() const = 0; + virtual std::string GetContentSecurityPolicy() const = 0; // The base url for the host. virtual const GURL& url() const = 0; @@ -35,6 +35,7 @@ virtual bool ShouldNotifyBrowserOfInjection() const = 0; const HostID& id() const { return id_; } + private: // The ID of the host. HostID id_;
diff --git a/extensions/renderer/resources/binding.js b/extensions/renderer/resources/binding.js index b1a3efca..22ccb7bd 100644 --- a/extensions/renderer/resources/binding.js +++ b/extensions/renderer/resources/binding.js
@@ -275,13 +275,35 @@ mod = mod[name]; } - // Add types to global schemaValidator, the types we depend on from other - // namespaces will be added as needed. if (schema.types) { $Array.forEach(schema.types, function(t) { if (!isSchemaNodeSupported(t, platform, manifestVersion)) return; + + // Add types to global schemaValidator; the types we depend on from + // other namespaces will be added as needed. schemaUtils.schemaValidator.addTypes(t); + + // Generate symbols for enums. + var enumValues = t['enum']; + if (enumValues) { + // Type IDs are qualified with the namespace during compilation, + // unfortunately, so remove it here. + logging.DCHECK( + t.id.substr(0, schema.namespace.length) == schema.namespace); + // Note: + 1 because it ends in a '.', e.g., 'fooApi.Type'. + var id = t.id.substr(schema.namespace.length + 1); + mod[id] = {}; + $Array.forEach(enumValues, function(enumValue) { + // Note: enums can be declared either as a list of strings + // ['foo', 'bar'] or as a list of objects + // [{'name': 'foo'}, {'name': 'bar'}]. + enumValue = + enumValue.hasOwnProperty('name') ? enumValue.name : enumValue; + if (enumValue) // Avoid setting any empty enums. + mod[id][enumValue] = enumValue; + }); + } }, this); }
diff --git a/extensions/renderer/resources/guest_view/web_view.js b/extensions/renderer/resources/guest_view/web_view.js index ff8c6718..401dbe5 100644 --- a/extensions/renderer/resources/guest_view/web_view.js +++ b/extensions/renderer/resources/guest_view/web_view.js
@@ -231,10 +231,6 @@ // Implemented when the experimental WebView API is available. WebViewImpl.maybeGetExperimentalApiMethods = function() { return []; }; WebViewImpl.prototype.setupExperimentalContextMenus = function() {}; -WebViewImpl.prototype.maybeSetupExperimentalChromeWebViewEvents = - function(request) { - return request; -}; GuestViewContainer.registerElement(WebViewImpl);
diff --git a/extensions/renderer/resources/guest_view/web_view_events.js b/extensions/renderer/resources/guest_view/web_view_events.js index 7d42d261..9c451e8c4 100644 --- a/extensions/renderer/resources/guest_view/web_view_events.js +++ b/extensions/renderer/resources/guest_view/web_view_events.js
@@ -266,7 +266,6 @@ ); } - request = this.webViewImpl.maybeSetupExperimentalChromeWebViewEvents(request); this.webViewImpl.setRequestPropertyOnWebViewElement(request); };
diff --git a/extensions/renderer/script_injection.cc b/extensions/renderer/script_injection.cc index 58cf328..3bb279a7 100644 --- a/extensions/renderer/script_injection.cc +++ b/extensions/renderer/script_injection.cc
@@ -108,16 +108,17 @@ ScriptInjection::ScriptInjection( scoped_ptr<ScriptInjector> injector, blink::WebLocalFrame* web_frame, - const HostID& host_id, + scoped_ptr<const InjectionHost> injection_host, UserScript::RunLocation run_location, int tab_id) : injector_(injector.Pass()), web_frame_(web_frame), - host_id_(host_id), + injection_host_(injection_host.Pass()), run_location_(run_location), tab_id_(tab_id), request_id_(kInvalidRequestId), complete_(false) { + CHECK(injection_host_.get()); } ScriptInjection::~ScriptInjection() { @@ -126,7 +127,6 @@ } bool ScriptInjection::TryToInject(UserScript::RunLocation current_location, - const InjectionHost* injection_host, ScriptsRunInfo* scripts_run_info) { if (current_location < run_location_) return false; // Wait for the right location. @@ -134,13 +134,14 @@ if (request_id_ != kInvalidRequestId) return false; // We're waiting for permission right now, try again later. - if (!injection_host) { + if (!injection_host_) { NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED); return true; // We're done. } - switch (injector_->CanExecuteOnFrame(injection_host, web_frame_, tab_id_, - web_frame_->top()->document().url())) { + switch (injector_->CanExecuteOnFrame( + injection_host_.get(), web_frame_, tab_id_, + web_frame_->top()->document().url())) { case PermissionsData::ACCESS_DENIED: NotifyWillNotInject(ScriptInjector::NOT_ALLOWED); return true; // We're done. @@ -148,7 +149,7 @@ SendInjectionMessage(true /* request permission */); return false; // Wait around for permission. case PermissionsData::ACCESS_ALLOWED: - Inject(injection_host, scripts_run_info); + Inject(scripts_run_info); return true; // We're done! } @@ -156,17 +157,20 @@ return false; } -bool ScriptInjection::OnPermissionGranted(const InjectionHost* injection_host, - ScriptsRunInfo* scripts_run_info) { - if (!injection_host) { +bool ScriptInjection::OnPermissionGranted(ScriptsRunInfo* scripts_run_info) { + if (!injection_host_) { NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED); return false; } - Inject(injection_host, scripts_run_info); + Inject(scripts_run_info); return true; } +void ScriptInjection::OnHostRemoved() { + injection_host_.reset(nullptr); +} + void ScriptInjection::SendInjectionMessage(bool request_permission) { content::RenderView* render_view = content::RenderView::FromWebView(web_frame()->top()->view()); @@ -176,7 +180,7 @@ request_id_ = request_permission ? g_next_pending_id++ : kInvalidRequestId; render_view->Send(new ExtensionHostMsg_RequestScriptInjectionPermission( render_view->GetRoutingID(), - host_id_.id(), + host_id().id(), injector_->script_type(), request_id_)); } @@ -187,13 +191,12 @@ injector_->OnWillNotInject(reason); } -void ScriptInjection::Inject(const InjectionHost* injection_host, - ScriptsRunInfo* scripts_run_info) { - DCHECK(injection_host); +void ScriptInjection::Inject(ScriptsRunInfo* scripts_run_info) { + DCHECK(injection_host_); DCHECK(scripts_run_info); DCHECK(!complete_); - if (injection_host->ShouldNotifyBrowserOfInjection()) + if (injection_host_->ShouldNotifyBrowserOfInjection()) SendInjectionMessage(false /* don't request permission */); std::vector<blink::WebFrame*> frame_vector; @@ -226,13 +229,14 @@ // Note: we don't consider ACCESS_WITHHELD because there is nowhere to // surface a request for a child frame. // TODO(rdevlin.cronin): We should ask for permission somehow. - if (injector_->CanExecuteOnFrame(injection_host, frame, tab_id_, top_url) == - PermissionsData::ACCESS_DENIED) { + if (injector_->CanExecuteOnFrame( + injection_host_.get(), frame, tab_id_, top_url) == + PermissionsData::ACCESS_DENIED) { DCHECK(frame->parent()); continue; } if (inject_js) - InjectJs(injection_host, frame, execution_results.get()); + InjectJs(frame, execution_results.get()); if (inject_css) InjectCss(frame); } @@ -245,20 +249,20 @@ run_location_); } -void ScriptInjection::InjectJs(const InjectionHost* injection_host, - blink::WebLocalFrame* frame, +void ScriptInjection::InjectJs(blink::WebLocalFrame* frame, base::ListValue* execution_results) { std::vector<blink::WebScriptSource> sources = injector_->GetJsSources(run_location_); bool in_main_world = injector_->ShouldExecuteInMainWorld(); int world_id = in_main_world ? DOMActivityLogger::kMainWorldId - : GetIsolatedWorldIdForInstance(injection_host, frame); + : GetIsolatedWorldIdForInstance(injection_host_.get(), + frame); bool expects_results = injector_->ExpectsResults(); base::ElapsedTimer exec_timer; - if (injection_host->id().type() == HostID::EXTENSIONS) - DOMActivityLogger::AttachToWorld(world_id, injection_host->id().id()); + if (injection_host_->id().type() == HostID::EXTENSIONS) + DOMActivityLogger::AttachToWorld(world_id, injection_host_->id().id()); v8::HandleScope scope(v8::Isolate::GetCurrent()); v8::Local<v8::Value> script_value; if (in_main_world) { @@ -283,7 +287,7 @@ script_value = (*results)[0]; } - if (injection_host->id().type() == HostID::EXTENSIONS) + if (injection_host_->id().type() == HostID::EXTENSIONS) UMA_HISTOGRAM_TIMES("Extensions.InjectScriptTime", exec_timer.Elapsed()); if (expects_results) {
diff --git a/extensions/renderer/script_injection.h b/extensions/renderer/script_injection.h index a883545..9f4691c 100644 --- a/extensions/renderer/script_injection.h +++ b/extensions/renderer/script_injection.h
@@ -8,9 +8,9 @@ #include "base/basictypes.h" #include "base/macros.h" #include "extensions/common/user_script.h" +#include "extensions/renderer/injection_host.h" #include "extensions/renderer/script_injector.h" -class InjectionHost; struct HostID; namespace blink { @@ -32,7 +32,7 @@ ScriptInjection(scoped_ptr<ScriptInjector> injector, blink::WebLocalFrame* web_frame, - const HostID& host_id, + scoped_ptr<const InjectionHost> injection_host, UserScript::RunLocation run_location, int tab_id); ~ScriptInjection(); @@ -41,19 +41,19 @@ // the script has either injected or will never inject (i.e., if the object // is done), and false if injection is delayed (either for permission purposes // or because |current_location| is not the designated |run_location_|). - // NOTE: |injection_host| may be NULL, if the injection_host is removed! bool TryToInject(UserScript::RunLocation current_location, - const InjectionHost* injection_host, ScriptsRunInfo* scripts_run_info); // Called when permission for the given injection has been granted. // Returns true if the injection ran. - bool OnPermissionGranted(const InjectionHost* injection_host, - ScriptsRunInfo* scripts_run_info); + bool OnPermissionGranted(ScriptsRunInfo* scripts_run_info); + + // Resets the pointer of the injection host when the host is gone. + void OnHostRemoved(); // Accessors. blink::WebLocalFrame* web_frame() const { return web_frame_; } - const HostID& host_id() const { return host_id_; } + const HostID& host_id() const { return injection_host_->id(); } int64 request_id() const { return request_id_; } private: @@ -62,13 +62,11 @@ void SendInjectionMessage(bool request_permission); // Injects the script, optionally populating |scripts_run_info|. - void Inject(const InjectionHost* injection_host, - ScriptsRunInfo* scripts_run_info); + void Inject(ScriptsRunInfo* scripts_run_info); // Inject any JS scripts into the |frame|, optionally populating // |execution_results|. - void InjectJs(const InjectionHost* injection_host, - blink::WebLocalFrame* frame, + void InjectJs(blink::WebLocalFrame* frame, base::ListValue* execution_results); // Inject any CSS source into the |frame|. @@ -83,8 +81,8 @@ // The (main) WebFrame into which this should inject the script. blink::WebLocalFrame* web_frame_; - // The id of the associated injection_host. - HostID host_id_; + // The associated injection host. + scoped_ptr<const InjectionHost> injection_host_; // The location in the document load at which we inject the script. UserScript::RunLocation run_location_;
diff --git a/extensions/renderer/script_injection_manager.cc b/extensions/renderer/script_injection_manager.cc index 93862dd..7deb027 100644 --- a/extensions/renderer/script_injection_manager.cc +++ b/extensions/renderer/script_injection_manager.cc
@@ -53,20 +53,6 @@ return UserScript::RUN_LOCATION_LAST; } - -// TODO(hanxi): let ScriptInjection own an InjectionHost to avoid constructing -// an ExtensionInjectionHost many times. -// Note: the ScriptInjection should be able to know when the backing extension -// is removed. -scoped_ptr<ExtensionInjectionHost> GetExtensionInjectionHost( - const std::string& extension_id, const ExtensionSet* extensions) { - const Extension* extension = extensions->GetByID(extension_id); - if (!extension) - return scoped_ptr<ExtensionInjectionHost>(); - return scoped_ptr<ExtensionInjectionHost>( - new ExtensionInjectionHost(extension)); -} - } // namespace class ScriptInjectionManager::RVOHelper : public content::RenderViewObserver { @@ -256,6 +242,23 @@ rvo_helpers_.push_back(new RVOHelper(render_view, this)); } +void ScriptInjectionManager::OnExtensionUnloaded( + const std::string& extension_id) { + for (auto iter = pending_injections_.begin(); + iter != pending_injections_.end();) { + if ((*iter)->host_id().id() == extension_id) { + (*iter)->OnHostRemoved(); + iter = pending_injections_.erase(iter); + } else { + ++iter; + } + } + // If we are currently injection scripts, we need to make a note that this + // extension is "dirty" (invalidated). + if (injecting_scripts_) + invalidated_while_injecting_.insert(extension_id); +} + void ScriptInjectionManager::OnUserScriptsUpdated( const std::set<std::string>& changed_extensions, const std::vector<UserScript*>& scripts) { @@ -392,15 +395,12 @@ if (!IsFrameValid(frame)) break; - const std::string& extension_id = (*iter)->host_id().id(); - scoped_ptr<ExtensionInjectionHost> extension_injection_host = - GetExtensionInjectionHost(extension_id, extensions_); - // Try to inject the script if the extension is not "dirty" (invalidated by - // an update). If the injection does not finish (i.e., it is waiting for - // permission), add it to the list of pending injections. - if (invalidated_while_injecting_.count(extension_id) == 0 && + // Try to inject the script if the injection host is not "dirty" + // (invalidated by an update). If the injection does not finish + // (i.e., it is waiting for permission), add it to the list of pending + // injections. + if (invalidated_while_injecting_.count((*iter)->host_id().id()) == 0 && !(*iter)->TryToInject(run_location, - extension_injection_host.get(), &scripts_run_info)) { pending_injections_.insert(pending_injections_.begin(), *iter); iter = frame_injections.weak_erase(iter); @@ -433,23 +433,25 @@ return; } + scoped_ptr<const ExtensionInjectionHost> extension_injection_host = + ExtensionInjectionHost::Create(params.extension_id, extensions_); + + if (!extension_injection_host) + return; + scoped_ptr<ScriptInjection> injection(new ScriptInjection( scoped_ptr<ScriptInjector>( new ProgrammaticScriptInjector(params, main_frame)), main_frame, - HostID(HostID::EXTENSIONS, params.extension_id), + extension_injection_host.Pass(), static_cast<UserScript::RunLocation>(params.run_at), ExtensionHelper::Get(render_view)->tab_id())); ScriptsRunInfo scripts_run_info; FrameStatusMap::const_iterator iter = frame_statuses_.find(main_frame); - scoped_ptr<ExtensionInjectionHost> extension_injection_host = - GetExtensionInjectionHost(injection->host_id().id(), extensions_); - if (!injection->TryToInject( iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second, - extension_injection_host.get(), &scripts_run_info)) { pending_injections_.push_back(injection.release()); } @@ -461,9 +463,6 @@ const ExtensionId& extension_id, int script_id, const GURL& url) { - scoped_ptr<ExtensionInjectionHost> extension_injection_host = - GetExtensionInjectionHost(extension_id, extensions_); - const Extension* extension = extensions_->GetByID(extension_id); // TODO(dcheng): This function signature should really be a WebLocalFrame, // rather than trying to coerce it here. scoped_ptr<ScriptInjection> injection = @@ -472,12 +471,11 @@ web_frame->toWebLocalFrame(), tab_id, url, - extension); - if (injection.get()) { + extension_id); + if (injection) { ScriptsRunInfo scripts_run_info; // TODO(markdittmer): Use return value of TryToInject for error handling. injection->TryToInject(UserScript::BROWSER_DRIVEN, - extension_injection_host.get(), &scripts_run_info); scripts_run_info.LogRun(web_frame, UserScript::BROWSER_DRIVEN); } @@ -487,8 +485,10 @@ ScopedVector<ScriptInjection>::iterator iter = pending_injections_.begin(); for (; iter != pending_injections_.end(); ++iter) { - if ((*iter)->request_id() == request_id) + if ((*iter)->request_id() == request_id) { + DCHECK((*iter)->host_id().type() == HostID::EXTENSIONS); break; + } } if (iter == pending_injections_.end()) return; @@ -502,10 +502,7 @@ pending_injections_.weak_erase(iter); ScriptsRunInfo scripts_run_info; - scoped_ptr<ExtensionInjectionHost> extension_injection_host = - GetExtensionInjectionHost(injection->host_id().id(), extensions_); - if (injection->OnPermissionGranted(extension_injection_host.get(), - &scripts_run_info)) { + if (injection->OnPermissionGranted(&scripts_run_info)) { scripts_run_info.LogRun(injection->web_frame(), UserScript::RUN_DEFERRED); } }
diff --git a/extensions/renderer/script_injection_manager.h b/extensions/renderer/script_injection_manager.h index 8ec3d94..08cf1e1 100644 --- a/extensions/renderer/script_injection_manager.h +++ b/extensions/renderer/script_injection_manager.h
@@ -45,6 +45,9 @@ // Notifies that a new render view has been created. void OnRenderViewCreated(content::RenderView* render_view); + // Removes pending injections of the unloaded extension. + void OnExtensionUnloaded(const std::string& extension_id); + private: // A RenderViewObserver implementation which watches the various render views // in order to notify the ScriptInjectionManager of different document load
diff --git a/extensions/renderer/user_script_injector.cc b/extensions/renderer/user_script_injector.cc index c3e15ef..e620a7c 100644 --- a/extensions/renderer/user_script_injector.cc +++ b/extensions/renderer/user_script_injector.cc
@@ -8,6 +8,7 @@ #include "base/lazy_instance.h" #include "content/public/common/url_constants.h" +#include "content/public/renderer/render_view.h" #include "extensions/common/extension.h" #include "extensions/common/permissions/permissions_data.h" #include "extensions/renderer/injection_host.h" @@ -127,15 +128,21 @@ blink::WebFrame* web_frame, int tab_id, const GURL& top_url) const { - // If we don't have a tab id, we have no UI surface to ask for user consent. - // For now, we treat this as an automatic allow. - if (tab_id == -1) - return PermissionsData::ACCESS_ALLOWED; - GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL( web_frame, web_frame->document().url(), script_->match_about_blank()); - return injection_host->CanExecuteOnFrame( + PermissionsData::AccessType can_execute = injection_host->CanExecuteOnFrame( effective_document_url, top_url, tab_id, is_declarative_); + + if (script_->consumer_instance_type() != + UserScript::ConsumerInstanceType::WEBVIEW || + can_execute == PermissionsData::ACCESS_DENIED) + return can_execute; + + int routing_id = content::RenderView::FromWebView(web_frame->top()->view()) + ->GetRoutingID(); + return script_->routing_info().render_view_id == routing_id + ? PermissionsData::ACCESS_ALLOWED + : PermissionsData::ACCESS_DENIED; } std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
diff --git a/extensions/renderer/user_script_set.cc b/extensions/renderer/user_script_set.cc index 1d66aaa1..df7c7c9 100644 --- a/extensions/renderer/user_script_set.cc +++ b/extensions/renderer/user_script_set.cc
@@ -12,9 +12,11 @@ #include "extensions/common/permissions/permissions_data.h" #include "extensions/renderer/extension_injection_host.h" #include "extensions/renderer/extensions_renderer_client.h" +#include "extensions/renderer/injection_host.h" #include "extensions/renderer/script_context.h" #include "extensions/renderer/script_injection.h" #include "extensions/renderer/user_script_injector.h" +#include "extensions/renderer/web_ui_injection_host.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "url/gurl.h" @@ -55,6 +57,8 @@ for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin(); iter != scripts_.end(); ++iter) { + if ((*iter)->host_id().type() != HostID::EXTENSIONS) + continue; DCHECK(!(*iter)->extension_id().empty()); ids->insert((*iter)->extension_id()); } @@ -69,16 +73,12 @@ for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin(); iter != scripts_.end(); ++iter) { - const Extension* extension = extensions_->GetByID((*iter)->extension_id()); - if (!extension) - continue; scoped_ptr<ScriptInjection> injection = GetInjectionForScript( *iter, web_frame, tab_id, run_location, document_url, - extension, false /* is_declarative */); if (injection.get()) injections->push_back(injection.release()); @@ -155,8 +155,7 @@ blink::WebFrame* web_frame, int tab_id, UserScript::RunLocation run_location, - const GURL& document_url, - const Extension* extension) { + const GURL& document_url) { for (ScopedVector<UserScript>::const_iterator it = scripts_.begin(); it != scripts_.end(); ++it) { @@ -166,7 +165,6 @@ tab_id, run_location, document_url, - extension, true /* is_declarative */); } } @@ -181,9 +179,20 @@ int tab_id, UserScript::RunLocation run_location, const GURL& document_url, - const Extension* extension, bool is_declarative) { scoped_ptr<ScriptInjection> injection; + scoped_ptr<const InjectionHost> injection_host; + + const HostID& host_id = script->host_id(); + if (host_id.type() == HostID::EXTENSIONS) { + injection_host = ExtensionInjectionHost::Create(host_id.id(), extensions_); + if (!injection_host) + return injection.Pass(); + } else { + DCHECK_EQ(host_id.type(), HostID::WEBUI); + injection_host.reset(new WebUIInjectionHost(host_id)); + } + if (web_frame->parent() && !script->match_all_frames()) return injection.Pass(); // Only match subframes if the script declared it. @@ -196,11 +205,8 @@ scoped_ptr<ScriptInjector> injector(new UserScriptInjector(script, this, is_declarative)); - HostID host_id(HostID::EXTENSIONS, extension->id()); - ExtensionInjectionHost extension_injection_host( - make_scoped_refptr<const Extension>(extension)); if (injector->CanExecuteOnFrame( - &extension_injection_host, + injection_host.get(), web_frame, -1, // Content scripts are not tab-specific. web_frame->top()->document().url()) == @@ -216,7 +222,7 @@ injection.reset(new ScriptInjection( injector.Pass(), web_frame->toWebLocalFrame(), - host_id, + injection_host.Pass(), run_location, tab_id)); }
diff --git a/extensions/renderer/user_script_set.h b/extensions/renderer/user_script_set.h index e8d48f9..ab2b585 100644 --- a/extensions/renderer/user_script_set.h +++ b/extensions/renderer/user_script_set.h
@@ -24,7 +24,6 @@ } namespace extensions { -class Extension; class ExtensionSet; class ScriptInjection; @@ -64,8 +63,7 @@ blink::WebFrame* web_frame, int tab_id, UserScript::RunLocation run_location, - const GURL& document_url, - const Extension* extension); + const GURL& document_url); // Updates scripts given the shared memory region containing user scripts. // Returns true if the scripts were successfully updated. @@ -83,7 +81,6 @@ int tab_id, UserScript::RunLocation run_location, const GURL& document_url, - const Extension* extension, bool is_declarative); // Shared memory containing raw script data.
diff --git a/extensions/renderer/user_script_set_manager.cc b/extensions/renderer/user_script_set_manager.cc index 4379bab..2a6425f 100644 --- a/extensions/renderer/user_script_set_manager.cc +++ b/extensions/renderer/user_script_set_manager.cc
@@ -38,9 +38,9 @@ blink::WebFrame* web_frame, int tab_id, const GURL& url, - const Extension* extension) { + const std::string& extension_id) { UserScriptSet* user_script_set = - GetProgrammaticScriptsByExtension(extension->id()); + GetProgrammaticScriptsByExtension(extension_id); if (!user_script_set) return scoped_ptr<ScriptInjection>(); @@ -49,8 +49,7 @@ web_frame, tab_id, UserScript::BROWSER_DRIVEN, - url, - extension); + url); } bool UserScriptSetManager::OnControlMessageReceived(
diff --git a/extensions/renderer/user_script_set_manager.h b/extensions/renderer/user_script_set_manager.h index d102ea33..4b5e4f0 100644 --- a/extensions/renderer/user_script_set_manager.h +++ b/extensions/renderer/user_script_set_manager.h
@@ -56,14 +56,15 @@ void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); - // Looks up the script injection associated with |script_id| and |extension| - // in the context of the given |web_frame|, |tab_id|, and |url|. + // Looks up the script injection associated with |script_id| and + // |extension_id| in the context of the given |web_frame|, |tab_id|, + // and |url|. scoped_ptr<ScriptInjection> GetInjectionForDeclarativeScript( int script_id, blink::WebFrame* web_frame, int tab_id, const GURL& url, - const Extension* extension); + const std::string& extension_id); // Append all injections from |static_scripts| and each of // |programmatic_scripts_| to |injections|.
diff --git a/extensions/renderer/web_ui_injection_host.cc b/extensions/renderer/web_ui_injection_host.cc new file mode 100644 index 0000000..334358a0 --- /dev/null +++ b/extensions/renderer/web_ui_injection_host.cc
@@ -0,0 +1,41 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/renderer/web_ui_injection_host.h" + +WebUIInjectionHost::WebUIInjectionHost(const HostID& host_id) + : InjectionHost(host_id), + url_(host_id.id()) { +} + +WebUIInjectionHost::~WebUIInjectionHost() { +} + + +std::string WebUIInjectionHost::GetContentSecurityPolicy() const { + return std::string(); +} + +const GURL& WebUIInjectionHost::url() const { + return url_; +} + +const std::string& WebUIInjectionHost::name() const { + return id().id(); +} + +extensions::PermissionsData::AccessType WebUIInjectionHost::CanExecuteOnFrame( + const GURL& document_url, + const GURL& top_frame_url, + int tab_id, + bool is_declarative) const { + // Content scripts are allowed to inject on webviews created by WebUI. + return extensions::PermissionsData::AccessType::ACCESS_ALLOWED; +} + +bool WebUIInjectionHost::ShouldNotifyBrowserOfInjection() const { + // We don't notify browser of any injection made from WebUI, since the + // decision for injection is made in the render. + return false; +}
diff --git a/extensions/renderer/web_ui_injection_host.h b/extensions/renderer/web_ui_injection_host.h new file mode 100644 index 0000000..c81dd5d --- /dev/null +++ b/extensions/renderer/web_ui_injection_host.h
@@ -0,0 +1,33 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_RENDERER_WEBUI_INJECTION_HOST_H_ +#define EXTENSIONS_RENDERER_WEBUI_INJECTION_HOST_H_ + +#include "extensions/renderer/injection_host.h" + +class WebUIInjectionHost : public InjectionHost { + public: + WebUIInjectionHost(const HostID& host_id); + ~WebUIInjectionHost() override; + + private: + // InjectionHost: + std::string GetContentSecurityPolicy() const override; + const GURL& url() const override; + const std::string& name() const override; + extensions::PermissionsData::AccessType CanExecuteOnFrame( + const GURL& document_url, + const GURL& top_frame_url, + int tab_id, + bool is_declarative) const override; + bool ShouldNotifyBrowserOfInjection() const override; + + private: + GURL url_; + + DISALLOW_COPY_AND_ASSIGN(WebUIInjectionHost); +}; + +#endif // EXTENSIONS_RENDERER_WEBUI_INJECTION_HOST_H_
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn index 70aef276..2e12978 100644 --- a/extensions/shell/BUILD.gn +++ b/extensions/shell/BUILD.gn
@@ -127,7 +127,7 @@ } } -if (!(is_chromeos && !use_ozone) && (!is_win || link_chrome_on_windows)) { +if (!(is_chromeos && !use_ozone)) { executable("app_shell") { # testonly because :app_shell_lib is testonly. See :app_shell_lib comment. testonly = true
diff --git a/extensions/utility/unpacker.cc b/extensions/utility/unpacker.cc index d244ba5..c61faa2 100644 --- a/extensions/utility/unpacker.cc +++ b/extensions/utility/unpacker.cc
@@ -118,9 +118,9 @@ return NULL; } - JSONFileValueSerializer serializer(manifest_path); + JSONFileValueDeserializer deserializer(manifest_path); std::string error; - scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error)); + scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, &error)); if (!root.get()) { SetError(error); return NULL; @@ -270,9 +270,9 @@ bool Unpacker::ReadMessageCatalog(const base::FilePath& message_path) { std::string error; - JSONFileValueSerializer serializer(message_path); + JSONFileValueDeserializer deserializer(message_path); scoped_ptr<base::DictionaryValue> root(static_cast<base::DictionaryValue*>( - serializer.Deserialize(NULL, &error))); + deserializer.Deserialize(NULL, &error))); if (!root.get()) { base::string16 messages_file = message_path.LossyDisplayName(); if (error.empty()) {
diff --git a/gin/function_template.h b/gin/function_template.h index dff1bb2..a2e1755 100644 --- a/gin/function_template.h +++ b/gin/function_template.h
@@ -220,6 +220,11 @@ // JavaScript functions that execute a provided C++ function or base::Callback. // JavaScript arguments are automatically converted via gin::Converter, as is // the return value of the C++ function, if any. +// +// NOTE: V8 caches FunctionTemplates for a lifetime of a web page for its own +// internal reasons, thus it is generally a good idea to cache the template +// returned by this function. Otherwise, repeated method invocations from JS +// will create substantial memory leaks. See http://crbug.com/463487. template<typename Sig> v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( v8::Isolate* isolate, const base::Callback<Sig> callback,
diff --git a/google_apis/BUILD.gn b/google_apis/BUILD.gn index 1eae08f..b8ab4b6 100644 --- a/google_apis/BUILD.gn +++ b/google_apis/BUILD.gn
@@ -198,45 +198,43 @@ } } -if (!is_win || link_chrome_on_windows) { - test("google_apis_unittests") { - sources = [ - "gaia/gaia_auth_fetcher_unittest.cc", - "gaia/gaia_auth_util_unittest.cc", - "gaia/gaia_oauth_client_unittest.cc", - "gaia/google_service_auth_error_unittest.cc", - "gaia/merge_session_helper_unittest.cc", - "gaia/oauth2_access_token_fetcher_impl_unittest.cc", - "gaia/oauth2_api_call_flow_unittest.cc", - "gaia/oauth2_mint_token_flow_unittest.cc", - "gaia/oauth2_token_service_unittest.cc", - "gaia/oauth_request_signer_unittest.cc", - "gaia/ubertoken_fetcher_unittest.cc", - "google_api_keys_unittest.cc", +test("google_apis_unittests") { + sources = [ + "gaia/gaia_auth_fetcher_unittest.cc", + "gaia/gaia_auth_util_unittest.cc", + "gaia/gaia_oauth_client_unittest.cc", + "gaia/google_service_auth_error_unittest.cc", + "gaia/merge_session_helper_unittest.cc", + "gaia/oauth2_access_token_fetcher_impl_unittest.cc", + "gaia/oauth2_api_call_flow_unittest.cc", + "gaia/oauth2_mint_token_flow_unittest.cc", + "gaia/oauth2_token_service_unittest.cc", + "gaia/oauth_request_signer_unittest.cc", + "gaia/ubertoken_fetcher_unittest.cc", + "google_api_keys_unittest.cc", + ] + + configs += [ ":key_defines" ] + + deps = [ + ":google_apis", + ":test_support", + "//base", + "//base/test:run_all_unittests", + "//testing/gmock", + "//testing/gtest", + ] + + if (enable_extensions) { + sources += [ + "drive/base_requests_server_unittest.cc", + "drive/base_requests_unittest.cc", + "drive/drive_api_parser_unittest.cc", + "drive/drive_api_requests_unittest.cc", + "drive/drive_api_url_generator_unittest.cc", + "drive/request_sender_unittest.cc", + "drive/request_util_unittest.cc", + "drive/time_util_unittest.cc", ] - - configs += [ ":key_defines" ] - - deps = [ - ":google_apis", - ":test_support", - "//base", - "//base/test:run_all_unittests", - "//testing/gmock", - "//testing/gtest", - ] - - if (enable_extensions) { - sources += [ - "drive/base_requests_server_unittest.cc", - "drive/base_requests_unittest.cc", - "drive/drive_api_parser_unittest.cc", - "drive/drive_api_requests_unittest.cc", - "drive/drive_api_url_generator_unittest.cc", - "drive/request_sender_unittest.cc", - "drive/request_util_unittest.cc", - "drive/time_util_unittest.cc", - ] - } } }
diff --git a/google_apis/drive/test_util.cc b/google_apis/drive/test_util.cc index ea193c4..db14c9d7 100644 --- a/google_apis/drive/test_util.cc +++ b/google_apis/drive/test_util.cc
@@ -81,8 +81,8 @@ base::FilePath path = GetTestFilePath(relative_path); std::string error; - JSONFileValueSerializer serializer(path); - scoped_ptr<base::Value> value(serializer.Deserialize(NULL, &error)); + JSONFileValueDeserializer deserializer(path); + scoped_ptr<base::Value> value(deserializer.Deserialize(NULL, &error)); LOG_IF(WARNING, !value.get()) << "Failed to parse " << path.value() << ": " << error; return value.Pass();
diff --git a/google_apis/gcm/engine/connection_factory_impl.cc b/google_apis/gcm/engine/connection_factory_impl.cc index 218f833..5be2eb6 100644 --- a/google_apis/gcm/engine/connection_factory_impl.cc +++ b/google_apis/gcm/engine/connection_factory_impl.cc
@@ -145,6 +145,10 @@ DVLOG(1) << "Attempting connection to MCS endpoint."; waiting_for_backoff_ = false; + // It's necessary to close the socket before attempting any new connection, + // otherwise it's possible to hit a use-after-free in the connection handler. + // crbug.com/462319 + CloseSocket(); ConnectImpl(); } @@ -212,7 +216,12 @@ return; } - if (logging_in_) { + if (reason == NETWORK_CHANGE) { + // Canary attempts bypass backoff without resetting it. These will have no + // effect if we're already in the process of connecting. + ConnectImpl(); + return; + } else if (logging_in_) { // Failures prior to login completion just reuse the existing backoff entry. logging_in_ = false; backoff_entry_->InformOfRequest(false); @@ -222,9 +231,6 @@ // the backoff entry that was saved off at login completion time. backoff_entry_.swap(previous_backoff_); backoff_entry_->InformOfRequest(false); - } else if (reason == NETWORK_CHANGE) { - ConnectImpl(); // Canary attempts bypass backoff without resetting it. - return; } else { // We shouldn't be in backoff in thise case. DCHECK_EQ(0, backoff_entry_->failure_count()); @@ -287,7 +293,8 @@ void ConnectionFactoryImpl::ConnectImpl() { DCHECK(!IsEndpointReachable()); - DCHECK(!socket_handle_.socket()); + // TODO(zea): Make this a dcheck again. crbug.com/462319 + CHECK(!socket_handle_.socket()); // TODO(zea): if the network is offline, don't attempt to connect. // See crbug.com/396687
diff --git a/google_apis/gcm/engine/connection_factory_impl_unittest.cc b/google_apis/gcm/engine/connection_factory_impl_unittest.cc index a6c05ebe..ed23da9f 100644 --- a/google_apis/gcm/engine/connection_factory_impl_unittest.cc +++ b/google_apis/gcm/engine/connection_factory_impl_unittest.cc
@@ -132,6 +132,9 @@ // Force a login handshake to be delayed. void SetDelayLogin(bool delay_login); + // Simulate a socket error. + void SetSocketError(); + base::SimpleTestTickClock* tick_clock() { return &tick_clock_; } private: @@ -184,6 +187,7 @@ void TestConnectionFactoryImpl::ConnectImpl() { ASSERT_GT(num_expected_attempts_, 0); + ASSERT_FALSE(GetConnectionHandler()->CanSendMessage()); scoped_ptr<mcs_proto::LoginRequest> request(BuildLoginRequest(0, 0, "")); GetConnectionHandler()->Init(*request, NULL); OnConnectDone(connect_result_); @@ -255,6 +259,10 @@ fake_handler_->set_fail_login(delay_login_); } +void TestConnectionFactoryImpl::SetSocketError() { + fake_handler_->set_had_error(true); +} + } // namespace class ConnectionFactoryImplTest @@ -561,4 +569,26 @@ EXPECT_TRUE(factory()->IsEndpointReachable()); } +// Test that if the client attempts to reconnect while a connection is already +// open, we don't crash. +TEST_F(ConnectionFactoryImplTest, ConnectionResetRace) { + // Initial successful connection. + factory()->SetConnectResult(net::OK); + factory()->Connect(); + WaitForConnections(); + EXPECT_TRUE(factory()->IsEndpointReachable()); + + // Trigger a connection error under the hood. + factory()->SetSocketError(); + EXPECT_FALSE(factory()->IsEndpointReachable()); + + // Now trigger force a re-connection. + factory()->SetConnectResult(net::OK); + factory()->Connect(); + WaitForConnections(); + + // Re-connection should succeed. + EXPECT_TRUE(factory()->IsEndpointReachable()); +} + } // namespace gcm
diff --git a/google_apis/gcm/engine/fake_connection_handler.cc b/google_apis/gcm/engine/fake_connection_handler.cc index dbffbce..243c280 100644 --- a/google_apis/gcm/engine/fake_connection_handler.cc +++ b/google_apis/gcm/engine/fake_connection_handler.cc
@@ -32,7 +32,8 @@ write_callback_(write_callback), fail_login_(false), fail_send_(false), - initialized_(false) { + initialized_(false), + had_error_(false) { } FakeConnectionHandler::~FakeConnectionHandler() { @@ -51,10 +52,11 @@ void FakeConnectionHandler::Reset() { initialized_ = false; + had_error_ = false; } bool FakeConnectionHandler::CanSendMessage() const { - return initialized_; + return initialized_ && !had_error_; } void FakeConnectionHandler::SendMessage(
diff --git a/google_apis/gcm/engine/fake_connection_handler.h b/google_apis/gcm/engine/fake_connection_handler.h index 4e43d12..f109478 100644 --- a/google_apis/gcm/engine/fake_connection_handler.h +++ b/google_apis/gcm/engine/fake_connection_handler.h
@@ -51,6 +51,13 @@ fail_send_ = fail_send; } + // Whether a socket-level error was encountered or not. + void set_had_error(bool had_error) { + had_error_ = had_error; + } + + bool initialized() const { return initialized_; } + private: ConnectionHandler::ProtoReceivedCallback read_callback_; ConnectionHandler::ProtoSentCallback write_callback_; @@ -66,6 +73,9 @@ // Whether a successful login has completed. bool initialized_; + // Whether an error was encountered after a successful login. + bool had_error_; + DISALLOW_COPY_AND_ASSIGN(FakeConnectionHandler); };
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn index 86888bd..830464e9 100644 --- a/gpu/BUILD.gn +++ b/gpu/BUILD.gn
@@ -66,221 +66,219 @@ ] } -if (!is_win || link_chrome_on_windows) { - test("gl_tests") { - sources = [ - "command_buffer/tests/compressed_texture_test.cc", - "command_buffer/tests/gl_bind_uniform_location_unittest.cc", - "command_buffer/tests/gl_chromium_framebuffer_multisample_unittest.cc", - "command_buffer/tests/gl_chromium_path_rendering_unittest.cc", - "command_buffer/tests/gl_clear_framebuffer_unittest.cc", - "command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc", - "command_buffer/tests/gl_depth_texture_unittest.cc", - "command_buffer/tests/gl_gpu_memory_buffer_unittest.cc", - "command_buffer/tests/gl_lose_context_chromium_unittest.cc", - "command_buffer/tests/gl_manager.cc", - "command_buffer/tests/gl_manager.h", - "command_buffer/tests/gl_pointcoord_unittest.cc", - "command_buffer/tests/gl_program_unittest.cc", - "command_buffer/tests/gl_query_unittest.cc", - "command_buffer/tests/gl_readback_unittest.cc", - "command_buffer/tests/gl_shared_resources_unittest.cc", - "command_buffer/tests/gl_stream_draw_unittest.cc", - "command_buffer/tests/gl_test_utils.cc", - "command_buffer/tests/gl_test_utils.h", - "command_buffer/tests/gl_tests_main.cc", - "command_buffer/tests/gl_texture_mailbox_unittest.cc", - "command_buffer/tests/gl_texture_storage_unittest.cc", - "command_buffer/tests/gl_unittest.cc", - "command_buffer/tests/gl_unittests_android.cc", - "command_buffer/tests/gl_virtual_contexts_unittest.cc", - "command_buffer/tests/occlusion_query_unittest.cc", - ] +test("gl_tests") { + sources = [ + "command_buffer/tests/compressed_texture_test.cc", + "command_buffer/tests/gl_bind_uniform_location_unittest.cc", + "command_buffer/tests/gl_chromium_framebuffer_multisample_unittest.cc", + "command_buffer/tests/gl_chromium_path_rendering_unittest.cc", + "command_buffer/tests/gl_clear_framebuffer_unittest.cc", + "command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc", + "command_buffer/tests/gl_depth_texture_unittest.cc", + "command_buffer/tests/gl_gpu_memory_buffer_unittest.cc", + "command_buffer/tests/gl_lose_context_chromium_unittest.cc", + "command_buffer/tests/gl_manager.cc", + "command_buffer/tests/gl_manager.h", + "command_buffer/tests/gl_pointcoord_unittest.cc", + "command_buffer/tests/gl_program_unittest.cc", + "command_buffer/tests/gl_query_unittest.cc", + "command_buffer/tests/gl_readback_unittest.cc", + "command_buffer/tests/gl_shared_resources_unittest.cc", + "command_buffer/tests/gl_stream_draw_unittest.cc", + "command_buffer/tests/gl_test_utils.cc", + "command_buffer/tests/gl_test_utils.h", + "command_buffer/tests/gl_tests_main.cc", + "command_buffer/tests/gl_texture_mailbox_unittest.cc", + "command_buffer/tests/gl_texture_storage_unittest.cc", + "command_buffer/tests/gl_unittest.cc", + "command_buffer/tests/gl_unittests_android.cc", + "command_buffer/tests/gl_virtual_contexts_unittest.cc", + "command_buffer/tests/occlusion_query_unittest.cc", + ] - defines = [ "GL_GLEXT_PROTOTYPES" ] + defines = [ "GL_GLEXT_PROTOTYPES" ] - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] - deps = [ - ":gpu", - ":test_support", - "//base", - "//base/test:test_support", - "//base/third_party/dynamic_annotations", - "//testing/gmock", - "//testing/gtest", - "//third_party/angle:translator", - "//ui/gfx", - "//ui/gfx:test_support", - "//ui/gfx/geometry", - "//ui/gl", - "//gpu/command_buffer/common:gles2_utils", - "//gpu/command_buffer/client:gles2_c_lib", - "//gpu/command_buffer/client:gles2_implementation", - ] + deps = [ + ":gpu", + ":test_support", + "//base", + "//base/test:test_support", + "//base/third_party/dynamic_annotations", + "//testing/gmock", + "//testing/gtest", + "//third_party/angle:translator", + "//ui/gfx", + "//ui/gfx:test_support", + "//ui/gfx/geometry", + "//ui/gl", + "//gpu/command_buffer/common:gles2_utils", + "//gpu/command_buffer/client:gles2_c_lib", + "//gpu/command_buffer/client:gles2_implementation", + ] - libs = [] + libs = [] - if (is_android) { - deps += [ "//testing/android:native_test_native_code" ] - libs += [ "android" ] - } - - # TODO(GYP) - # ['OS == "win"', { - # 'dependencies': [ - # '../third_party/angle/src/build_angle.gyp:libEGL', - # '../third_party/angle/src/build_angle.gyp:libGLESv2', - # ], - # }], + if (is_android) { + deps += [ "//testing/android:native_test_native_code" ] + libs += [ "android" ] } - test("gpu_unittests") { - sources = [ - "command_buffer/client/buffer_tracker_unittest.cc", - "command_buffer/client/client_test_helper.cc", - "command_buffer/client/client_test_helper.h", - "command_buffer/client/cmd_buffer_helper_test.cc", - "command_buffer/client/fenced_allocator_test.cc", - "command_buffer/client/gles2_implementation_unittest.cc", - "command_buffer/client/mapped_memory_unittest.cc", - "command_buffer/client/program_info_manager_unittest.cc", - "command_buffer/client/query_tracker_unittest.cc", - "command_buffer/client/ring_buffer_test.cc", - "command_buffer/client/transfer_buffer_unittest.cc", - "command_buffer/client/vertex_array_object_manager_unittest.cc", - "command_buffer/common/bitfield_helpers_test.cc", - "command_buffer/common/command_buffer_mock.cc", - "command_buffer/common/command_buffer_mock.h", - "command_buffer/common/command_buffer_shared_test.cc", - "command_buffer/common/debug_marker_manager_unittest.cc", - "command_buffer/common/gles2_cmd_format_test.cc", - "command_buffer/common/gles2_cmd_format_test_autogen.h", - "command_buffer/common/gles2_cmd_utils_unittest.cc", - "command_buffer/common/id_allocator_test.cc", - "command_buffer/common/trace_event.h", - "command_buffer/common/unittest_main.cc", - "command_buffer/service/async_pixel_transfer_delegate_mock.cc", - "command_buffer/service/async_pixel_transfer_delegate_mock.h", - "command_buffer/service/async_pixel_transfer_manager_mock.cc", - "command_buffer/service/async_pixel_transfer_manager_mock.h", - "command_buffer/service/buffer_manager_unittest.cc", - "command_buffer/service/cmd_parser_test.cc", - "command_buffer/service/command_buffer_service_unittest.cc", - "command_buffer/service/common_decoder_unittest.cc", - "command_buffer/service/context_group_unittest.cc", - "command_buffer/service/feature_info_unittest.cc", - "command_buffer/service/framebuffer_manager_unittest.cc", - "command_buffer/service/gl_surface_mock.cc", - "command_buffer/service/gl_surface_mock.h", - "command_buffer/service/gles2_cmd_decoder_unittest.cc", - "command_buffer/service/gles2_cmd_decoder_unittest.h", - "command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h", - "command_buffer/service/gles2_cmd_decoder_unittest_1.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h", - "command_buffer/service/gles2_cmd_decoder_unittest_2.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h", - "command_buffer/service/gles2_cmd_decoder_unittest_3.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h", - "command_buffer/service/gles2_cmd_decoder_unittest_async_pixel.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_base.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_base.h", - "command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_programs.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_textures.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc", - "command_buffer/service/gpu_scheduler_unittest.cc", - "command_buffer/service/gpu_service_test.cc", - "command_buffer/service/gpu_service_test.h", - "command_buffer/service/gpu_tracer_unittest.cc", - "command_buffer/service/id_manager_unittest.cc", - "command_buffer/service/mailbox_manager_unittest.cc", - "command_buffer/service/memory_program_cache_unittest.cc", - "command_buffer/service/mocks.cc", - "command_buffer/service/mocks.h", - "command_buffer/service/program_cache_unittest.cc", - "command_buffer/service/program_manager_unittest.cc", - "command_buffer/service/query_manager_unittest.cc", - "command_buffer/service/renderbuffer_manager_unittest.cc", - "command_buffer/service/shader_manager_unittest.cc", - "command_buffer/service/shader_translator_cache_unittest.cc", - "command_buffer/service/shader_translator_unittest.cc", - "command_buffer/service/test_helper.cc", - "command_buffer/service/test_helper.h", - "command_buffer/service/texture_manager_unittest.cc", - "command_buffer/service/transfer_buffer_manager_unittest.cc", - "command_buffer/service/valuebuffer_manager_unittest.cc", - "command_buffer/service/vertex_array_manager_unittest.cc", - "command_buffer/service/vertex_attrib_manager_unittest.cc", - "config/gpu_blacklist_unittest.cc", - "config/gpu_control_list_entry_unittest.cc", - "config/gpu_control_list_number_info_unittest.cc", - "config/gpu_control_list_os_info_unittest.cc", - "config/gpu_control_list_unittest.cc", - "config/gpu_control_list_version_info_unittest.cc", - "config/gpu_driver_bug_list_unittest.cc", - "config/gpu_info_collector_unittest.cc", - "config/gpu_info_unittest.cc", - "config/gpu_test_config_unittest.cc", - "config/gpu_test_expectations_parser_unittest.cc", - "config/gpu_util_unittest.cc", - ] + # TODO(GYP) + # ['OS == "win"', { + # 'dependencies': [ + # '../third_party/angle/src/build_angle.gyp:libEGL', + # '../third_party/angle/src/build_angle.gyp:libGLESv2', + # ], + # }], +} - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] +test("gpu_unittests") { + sources = [ + "command_buffer/client/buffer_tracker_unittest.cc", + "command_buffer/client/client_test_helper.cc", + "command_buffer/client/client_test_helper.h", + "command_buffer/client/cmd_buffer_helper_test.cc", + "command_buffer/client/fenced_allocator_test.cc", + "command_buffer/client/gles2_implementation_unittest.cc", + "command_buffer/client/mapped_memory_unittest.cc", + "command_buffer/client/program_info_manager_unittest.cc", + "command_buffer/client/query_tracker_unittest.cc", + "command_buffer/client/ring_buffer_test.cc", + "command_buffer/client/transfer_buffer_unittest.cc", + "command_buffer/client/vertex_array_object_manager_unittest.cc", + "command_buffer/common/bitfield_helpers_test.cc", + "command_buffer/common/command_buffer_mock.cc", + "command_buffer/common/command_buffer_mock.h", + "command_buffer/common/command_buffer_shared_test.cc", + "command_buffer/common/debug_marker_manager_unittest.cc", + "command_buffer/common/gles2_cmd_format_test.cc", + "command_buffer/common/gles2_cmd_format_test_autogen.h", + "command_buffer/common/gles2_cmd_utils_unittest.cc", + "command_buffer/common/id_allocator_test.cc", + "command_buffer/common/trace_event.h", + "command_buffer/common/unittest_main.cc", + "command_buffer/service/async_pixel_transfer_delegate_mock.cc", + "command_buffer/service/async_pixel_transfer_delegate_mock.h", + "command_buffer/service/async_pixel_transfer_manager_mock.cc", + "command_buffer/service/async_pixel_transfer_manager_mock.h", + "command_buffer/service/buffer_manager_unittest.cc", + "command_buffer/service/cmd_parser_test.cc", + "command_buffer/service/command_buffer_service_unittest.cc", + "command_buffer/service/common_decoder_unittest.cc", + "command_buffer/service/context_group_unittest.cc", + "command_buffer/service/feature_info_unittest.cc", + "command_buffer/service/framebuffer_manager_unittest.cc", + "command_buffer/service/gl_surface_mock.cc", + "command_buffer/service/gl_surface_mock.h", + "command_buffer/service/gles2_cmd_decoder_unittest.cc", + "command_buffer/service/gles2_cmd_decoder_unittest.h", + "command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h", + "command_buffer/service/gles2_cmd_decoder_unittest_1.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h", + "command_buffer/service/gles2_cmd_decoder_unittest_2.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h", + "command_buffer/service/gles2_cmd_decoder_unittest_3.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h", + "command_buffer/service/gles2_cmd_decoder_unittest_async_pixel.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_base.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_base.h", + "command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_programs.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_textures.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc", + "command_buffer/service/gpu_scheduler_unittest.cc", + "command_buffer/service/gpu_service_test.cc", + "command_buffer/service/gpu_service_test.h", + "command_buffer/service/gpu_tracer_unittest.cc", + "command_buffer/service/id_manager_unittest.cc", + "command_buffer/service/mailbox_manager_unittest.cc", + "command_buffer/service/memory_program_cache_unittest.cc", + "command_buffer/service/mocks.cc", + "command_buffer/service/mocks.h", + "command_buffer/service/program_cache_unittest.cc", + "command_buffer/service/program_manager_unittest.cc", + "command_buffer/service/query_manager_unittest.cc", + "command_buffer/service/renderbuffer_manager_unittest.cc", + "command_buffer/service/shader_manager_unittest.cc", + "command_buffer/service/shader_translator_cache_unittest.cc", + "command_buffer/service/shader_translator_unittest.cc", + "command_buffer/service/test_helper.cc", + "command_buffer/service/test_helper.h", + "command_buffer/service/texture_manager_unittest.cc", + "command_buffer/service/transfer_buffer_manager_unittest.cc", + "command_buffer/service/valuebuffer_manager_unittest.cc", + "command_buffer/service/vertex_array_manager_unittest.cc", + "command_buffer/service/vertex_attrib_manager_unittest.cc", + "config/gpu_blacklist_unittest.cc", + "config/gpu_control_list_entry_unittest.cc", + "config/gpu_control_list_number_info_unittest.cc", + "config/gpu_control_list_os_info_unittest.cc", + "config/gpu_control_list_unittest.cc", + "config/gpu_control_list_version_info_unittest.cc", + "config/gpu_driver_bug_list_unittest.cc", + "config/gpu_info_collector_unittest.cc", + "config/gpu_info_unittest.cc", + "config/gpu_test_config_unittest.cc", + "config/gpu_test_expectations_parser_unittest.cc", + "config/gpu_util_unittest.cc", + ] - deps = [ - ":gpu", - ":test_support", - "//base", - "//base/test:test_support", - "//base/third_party/dynamic_annotations", - "//testing/gmock", - "//testing/gtest", - "//third_party/angle:translator", - "//ui/gfx", - "//ui/gfx:test_support", - "//ui/gfx/geometry", - "//ui/gl", - "//gpu/command_buffer/common:gles2_utils", - "//gpu/command_buffer/client:gles2_c_lib", - "//gpu/command_buffer/client:gles2_implementation", - ] - } + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] - test("gpu_perftests") { - sources = [ - "perftests/measurements.cc", - "perftests/run_all_tests.cc", - "perftests/texture_upload_perftest.cc", - ] + deps = [ + ":gpu", + ":test_support", + "//base", + "//base/test:test_support", + "//base/third_party/dynamic_annotations", + "//testing/gmock", + "//testing/gtest", + "//third_party/angle:translator", + "//ui/gfx", + "//ui/gfx:test_support", + "//ui/gfx/geometry", + "//ui/gl", + "//gpu/command_buffer/common:gles2_utils", + "//gpu/command_buffer/client:gles2_c_lib", + "//gpu/command_buffer/client:gles2_implementation", + ] +} - deps = [ - "//base", - "//base/test:test_support", - "//gpu/command_buffer/service", - "//testing/gtest", - "//testing/perf", - "//ui/gfx/geometry", - "//ui/gl", - ] - } +test("gpu_perftests") { + sources = [ + "perftests/measurements.cc", + "perftests/run_all_tests.cc", + "perftests/texture_upload_perftest.cc", + ] - test("angle_unittests") { - sources = [ - "angle_unittest_main.cc", - ] + deps = [ + "//base", + "//base/test:test_support", + "//gpu/command_buffer/service", + "//testing/gtest", + "//testing/perf", + "//ui/gfx/geometry", + "//ui/gl", + ] +} - deps = [ - "//base", - "//base/test:test_support", - "//base/third_party/dynamic_annotations", - "//testing/gmock", - "//testing/gtest", - "//third_party/angle:translator_static", - ] - } +test("angle_unittests") { + sources = [ + "angle_unittest_main.cc", + ] + + deps = [ + "//base", + "//base/test:test_support", + "//base/third_party/dynamic_annotations", + "//testing/gmock", + "//testing/gtest", + "//third_party/angle:translator_static", + ] }
diff --git a/gpu/blink/webgraphicscontext3d_impl.cc b/gpu/blink/webgraphicscontext3d_impl.cc index 4f728cfd..a80a4d7b 100644 --- a/gpu/blink/webgraphicscontext3d_impl.cc +++ b/gpu/blink/webgraphicscontext3d_impl.cc
@@ -1183,6 +1183,8 @@ output_attribs->fail_if_major_perf_caveat = attributes.failIfMajorPerformanceCaveat; output_attribs->bind_generates_resource = false; + output_attribs->es3_context_required = + (attributes.webGL && attributes.webGLVersion == 2); } } // namespace gpu_blink
diff --git a/gpu/command_buffer/client/BUILD.gn b/gpu/command_buffer/client/BUILD.gn index a5532cb..7e47f24 100644 --- a/gpu/command_buffer/client/BUILD.gn +++ b/gpu/command_buffer/client/BUILD.gn
@@ -140,6 +140,27 @@ ] } +# Library emulates GLES2 using command_buffers. +component("gles2_implementation_no_check") { + sources = gles2_implementation_source_files + + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + + defines = [ + "GLES2_IMPL_IMPLEMENTATION", + "GLES2_CONFORMANCE_TESTS=1", + ] + + deps = [ + ":gles2_cmd_helper", + "//base", + "//gpu/command_buffer/common:gles2_utils", + "//ui/gfx", + "//ui/gfx/geometry", + ] +} + component("gl_in_process_context") { sources = [ "gl_in_process_context.cc",
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index 2acbc635..3af9413 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -381,8 +381,7 @@ static const GLuint kMaxTransformFeedbackSeparateAttribs = 4; static const GLuint kMaxUniformBufferBindings = 36; static const GLuint kStartId = 1024; - static const GLuint kBuffersStartId = - GLES2Implementation::kClientSideArrayId + 2 * kNumTestContexts; + static const GLuint kBuffersStartId = 1; static const GLuint kFramebuffersStartId = 1; static const GLuint kProgramsAndShadersStartId = 1; static const GLuint kRenderbuffersStartId = 1;
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc index 3985193e..0950b41 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.cc +++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -894,6 +894,7 @@ const int32 kBindGeneratesResource = 0x10000; const int32 kFailIfMajorPerfCaveat = 0x10001; const int32 kLoseContextWhenOutOfMemory = 0x10002; +const int32 kES3ContextRequired = 0x10003; } // namespace @@ -909,7 +910,8 @@ buffer_preserved(true), bind_generates_resource(true), fail_if_major_perf_caveat(false), - lose_context_when_out_of_memory(false) {} + lose_context_when_out_of_memory(false), + es3_context_required(false) {} void ContextCreationAttribHelper::Serialize(std::vector<int32>* attribs) const { if (alpha_size != -1) { @@ -952,6 +954,8 @@ attribs->push_back(fail_if_major_perf_caveat ? 1 : 0); attribs->push_back(kLoseContextWhenOutOfMemory); attribs->push_back(lose_context_when_out_of_memory ? 1 : 0); + attribs->push_back(kES3ContextRequired); + attribs->push_back(es3_context_required ? 1 : 0); attribs->push_back(kNone); } @@ -1006,6 +1010,9 @@ case kLoseContextWhenOutOfMemory: lose_context_when_out_of_memory = value != 0; break; + case kES3ContextRequired: + es3_context_required = value != 0; + break; case kNone: // Terminate list, even if more attributes. return true;
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h index 3528cfdb..9dd8f28 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.h +++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -223,6 +223,7 @@ bool bind_generates_resource; bool fail_if_major_perf_caveat; bool lose_context_when_out_of_memory; + bool es3_context_required; }; } // namespace gles2
diff --git a/gpu/command_buffer/common/id_allocator.cc b/gpu/command_buffer/common/id_allocator.cc index 507b14e..eccb468 100644 --- a/gpu/command_buffer/common/id_allocator.cc +++ b/gpu/command_buffer/common/id_allocator.cc
@@ -6,84 +6,200 @@ #include "gpu/command_buffer/common/id_allocator.h" +#include <limits> #include "base/logging.h" namespace gpu { -IdAllocator::IdAllocator() {} +IdAllocator::IdAllocator() { + COMPILE_ASSERT(kInvalidResource == 0u, invalid_resource_is_not_zero); + // Simplify the code by making sure that lower_bound(id) never + // returns the beginning of the map, if id is valid (eg != + // kInvalidResource). + used_ids_.insert(std::make_pair(0u, 0u)); +} IdAllocator::~IdAllocator() {} ResourceId IdAllocator::AllocateID() { - ResourceId id; - ResourceIdSet::iterator iter = free_ids_.begin(); - if (iter != free_ids_.end()) { - id = *iter; - } else { - id = LastUsedId() + 1; - if (!id) { - // We wrapped around to 0. - id = FindFirstUnusedId(); - } - } - MarkAsUsed(id); - return id; + return AllocateIDRange(1u); } ResourceId IdAllocator::AllocateIDAtOrAbove(ResourceId desired_id) { - ResourceId id; - ResourceIdSet::iterator iter = free_ids_.lower_bound(desired_id); - if (iter != free_ids_.end()) { - id = *iter; - } else if (LastUsedId() < desired_id) { - id = desired_id; - } else { - id = LastUsedId() + 1; - if (!id) { - // We wrapped around to 0. - id = FindFirstUnusedId(); - } + if (desired_id == 0u || desired_id == 1u) { + return AllocateIDRange(1u); } - MarkAsUsed(id); - return id; + + ResourceIdRangeMap::iterator current = used_ids_.lower_bound(desired_id); + ResourceIdRangeMap::iterator next = current; + if (current == used_ids_.end() || current->first > desired_id) { + current--; + } else { + next++; + } + + ResourceId first_id = current->first; + ResourceId last_id = current->second; + + DCHECK(desired_id >= first_id); + + if (desired_id - 1u <= last_id) { + // Append to current range. + last_id++; + if (last_id == 0) { + // The increment overflowed. + return AllocateIDRange(1u); + } + + current->second = last_id; + + if (next != used_ids_.end() && next->first - 1u == last_id) { + // Merge with next range. + current->second = next->second; + used_ids_.erase(next); + } + return last_id; + } else if (next != used_ids_.end() && next->first - 1u == desired_id) { + // Prepend to next range. + ResourceId last_existing_id = next->second; + used_ids_.erase(next); + used_ids_.insert(std::make_pair(desired_id, last_existing_id)); + return desired_id; + } + used_ids_.insert(std::make_pair(desired_id, desired_id)); + return desired_id; +} + +ResourceId IdAllocator::AllocateIDRange(uint32_t range) { + DCHECK(range > 0u); + + ResourceIdRangeMap::iterator current = used_ids_.begin(); + ResourceIdRangeMap::iterator next = current; + + while (++next != used_ids_.end()) { + if (next->first - current->second > range) { + break; + } + current = next; + } + + ResourceId first_id = current->second + 1u; + ResourceId last_id = first_id + range - 1u; + + if (first_id == 0u || last_id < first_id) { + return kInvalidResource; + } + + current->second = last_id; + + if (next != used_ids_.end() && next->first - 1u == last_id) { + // Merge with next range. + current->second = next->second; + used_ids_.erase(next); + } + + return first_id; } bool IdAllocator::MarkAsUsed(ResourceId id) { DCHECK(id); - free_ids_.erase(id); - std::pair<ResourceIdSet::iterator, bool> result = used_ids_.insert(id); - return result.second; + ResourceIdRangeMap::iterator current = used_ids_.lower_bound(id); + if (current != used_ids_.end() && current->first == id) { + return false; + } + + ResourceIdRangeMap::iterator next = current; + --current; + + if (current->second >= id) { + return false; + } + + DCHECK(current->first < id && current->second < id); + + if (current->second + 1u == id) { + // Append to current range. + current->second = id; + if (next != used_ids_.end() && next->first - 1u == id) { + // Merge with next range. + current->second = next->second; + used_ids_.erase(next); + } + return true; + } else if (next != used_ids_.end() && next->first - 1u == id) { + // Prepend to next range. + ResourceId last_existing_id = next->second; + used_ids_.erase(next); + used_ids_.insert(std::make_pair(id, last_existing_id)); + return true; + } + + used_ids_.insert(std::make_pair(id, id)); + return true; } void IdAllocator::FreeID(ResourceId id) { - if (id) { - used_ids_.erase(id); - free_ids_.insert(id); + FreeIDRange(id, 1u); +} + +void IdAllocator::FreeIDRange(ResourceId first_id, uint32 range) { + COMPILE_ASSERT(kInvalidResource == 0u, invalid_resource_is_not_zero); + + if (range == 0u || (first_id == 0u && range == 1u)) { + return; + } + + if (first_id == 0u) { + first_id++; + range--; + } + + ResourceId last_id = first_id + range - 1u; + if (last_id < first_id) { + last_id = std::numeric_limits<ResourceId>::max(); + } + + while (true) { + ResourceIdRangeMap::iterator current = used_ids_.lower_bound(last_id); + if (current == used_ids_.end() || current->first > last_id) { + --current; + } + + if (current->second < first_id) { + return; + } + + if (current->first >= first_id) { + ResourceId last_existing_id = current->second; + used_ids_.erase(current); + if (last_id < last_existing_id) { + used_ids_.insert(std::make_pair(last_id + 1u, last_existing_id)); + } + } else if (current->second <= last_id) { + current->second = first_id - 1u; + } else { + DCHECK(current->first < first_id && current->second > last_id); + ResourceId last_existing_id = current->second; + current->second = first_id - 1u; + used_ids_.insert(std::make_pair(last_id + 1u, last_existing_id)); + } } } bool IdAllocator::InUse(ResourceId id) const { - return id == kInvalidResource || used_ids_.find(id) != used_ids_.end(); -} - -ResourceId IdAllocator::LastUsedId() const { - if (used_ids_.empty()) { - return 0u; - } else { - return *used_ids_.rbegin(); + if (id == kInvalidResource) { + return false; } -} -ResourceId IdAllocator::FindFirstUnusedId() const { - ResourceId id = 1; - for (ResourceIdSet::const_iterator it = used_ids_.begin(); - it != used_ids_.end(); ++it) { - if ((*it) != id) { - return id; + ResourceIdRangeMap::const_iterator current = used_ids_.lower_bound(id); + if (current != used_ids_.end()) { + if (current->first == id) { + return true; } - ++id; } - return id; + + --current; + return current->second >= id; } } // namespace gpu
diff --git a/gpu/command_buffer/common/id_allocator.h b/gpu/command_buffer/common/id_allocator.h index b8770830..118424f 100644 --- a/gpu/command_buffer/common/id_allocator.h +++ b/gpu/command_buffer/common/id_allocator.h
@@ -9,7 +9,7 @@ #include <stdint.h> -#include <set> +#include <map> #include <utility> #include "base/compiler_specific.h" @@ -36,27 +36,28 @@ // Note: may wrap if it starts near limit. ResourceId AllocateIDAtOrAbove(ResourceId desired_id); + // Allocates |range| amount of contiguous ids. + // Returns the first id to |first_id| or |kInvalidResource| if + // allocation failed. + ResourceId AllocateIDRange(uint32_t range); + // Marks an id as used. Returns false if id was already used. bool MarkAsUsed(ResourceId id); // Frees a resource ID. void FreeID(ResourceId id); + // Frees a |range| amount of contiguous ids, starting from |first_id|. + void FreeIDRange(ResourceId first_id, uint32_t range); + // Checks whether or not a resource ID is in use. bool InUse(ResourceId id) const; private: - // TODO(gman): This would work much better with ranges or a hash table. - typedef std::set<ResourceId> ResourceIdSet; + // first_id -> last_id mapping. + typedef std::map<ResourceId, ResourceId> ResourceIdRangeMap; - // The highest ID on the used list. - ResourceId LastUsedId() const; - - // Lowest ID that isn't on the used list. This is slow, use as a last resort. - ResourceId FindFirstUnusedId() const; - - ResourceIdSet used_ids_; - ResourceIdSet free_ids_; + ResourceIdRangeMap used_ids_; DISALLOW_COPY_AND_ASSIGN(IdAllocator); };
diff --git a/gpu/command_buffer/common/id_allocator_test.cc b/gpu/command_buffer/common/id_allocator_test.cc index adeed5b0..7d93906 100644 --- a/gpu/command_buffer/common/id_allocator_test.cc +++ b/gpu/command_buffer/common/id_allocator_test.cc
@@ -125,4 +125,123 @@ EXPECT_NE(kInvalidResource, id3); } +TEST_F(IdAllocatorTest, AllocateIDRange) { + const ResourceId kMaxPossibleOffset = std::numeric_limits<ResourceId>::max(); + + IdAllocator* allocator = id_allocator(); + + ResourceId id1 = allocator->AllocateIDRange(1); + EXPECT_EQ(1u, id1); + ResourceId id2 = allocator->AllocateIDRange(2); + EXPECT_EQ(2u, id2); + ResourceId id3 = allocator->AllocateIDRange(3); + EXPECT_EQ(4u, id3); + ResourceId id4 = allocator->AllocateID(); + EXPECT_EQ(7u, id4); + allocator->FreeID(3); + ResourceId id5 = allocator->AllocateIDRange(1); + EXPECT_EQ(3u, id5); + allocator->FreeID(5); + allocator->FreeID(2); + allocator->FreeID(4); + ResourceId id6 = allocator->AllocateIDRange(2); + EXPECT_EQ(4u, id6); + ResourceId id7 = allocator->AllocateIDAtOrAbove(kMaxPossibleOffset); + EXPECT_EQ(kMaxPossibleOffset, id7); + ResourceId id8 = allocator->AllocateIDAtOrAbove(kMaxPossibleOffset); + EXPECT_EQ(2u, id8); + ResourceId id9 = allocator->AllocateIDRange(50); + EXPECT_EQ(8u, id9); + ResourceId id10 = allocator->AllocateIDRange(50); + EXPECT_EQ(58u, id10); + // Remove all the low-numbered ids. + allocator->FreeID(1); + allocator->FreeID(15); + allocator->FreeIDRange(2, 107); + ResourceId id11 = allocator->AllocateIDRange(100); + EXPECT_EQ(1u, id11); + allocator->FreeID(kMaxPossibleOffset); + ResourceId id12 = allocator->AllocateIDRange(100); + EXPECT_EQ(101u, id12); + + ResourceId id13 = allocator->AllocateIDAtOrAbove(kMaxPossibleOffset - 2u); + EXPECT_EQ(kMaxPossibleOffset - 2u, id13); + ResourceId id14 = allocator->AllocateIDRange(3); + EXPECT_EQ(201u, id14); +} + +TEST_F(IdAllocatorTest, AllocateIDRangeEndNoEffect) { + const ResourceId kMaxPossibleOffset = std::numeric_limits<ResourceId>::max(); + + IdAllocator* allocator = id_allocator(); + ResourceId id1 = allocator->AllocateIDAtOrAbove(kMaxPossibleOffset - 2u); + EXPECT_EQ(kMaxPossibleOffset - 2u, id1); + ResourceId id3 = allocator->AllocateIDRange(3); + EXPECT_EQ(1u, id3); + ResourceId id2 = allocator->AllocateIDRange(2); + EXPECT_EQ(4u, id2); +} + +TEST_F(IdAllocatorTest, AllocateFullIDRange) { + const uint32_t kMaxPossibleRange = std::numeric_limits<uint32_t>::max(); + const ResourceId kFreedId = 555u; + IdAllocator* allocator = id_allocator(); + + ResourceId id1 = allocator->AllocateIDRange(kMaxPossibleRange); + EXPECT_EQ(1u, id1); + ResourceId id2 = allocator->AllocateID(); + EXPECT_EQ(0u, id2); + allocator->FreeID(kFreedId); + ResourceId id3 = allocator->AllocateID(); + EXPECT_EQ(kFreedId, id3); + ResourceId id4 = allocator->AllocateID(); + EXPECT_EQ(0u, id4); + allocator->FreeID(kFreedId + 1u); + allocator->FreeID(kFreedId + 4u); + allocator->FreeID(kFreedId + 3u); + allocator->FreeID(kFreedId + 5u); + allocator->FreeID(kFreedId + 2u); + ResourceId id5 = allocator->AllocateIDRange(5); + EXPECT_EQ(kFreedId + 1u, id5); +} + +TEST_F(IdAllocatorTest, AllocateIDRangeNoWrapInRange) { + const uint32_t kMaxPossibleRange = std::numeric_limits<uint32_t>::max(); + const ResourceId kAllocId = 10u; + IdAllocator* allocator = id_allocator(); + + ResourceId id1 = allocator->AllocateIDAtOrAbove(kAllocId); + EXPECT_EQ(kAllocId, id1); + ResourceId id2 = allocator->AllocateIDRange(kMaxPossibleRange - 5u); + EXPECT_EQ(0u, id2); + ResourceId id3 = allocator->AllocateIDRange(kMaxPossibleRange - kAllocId); + EXPECT_EQ(kAllocId + 1u, id3); +} + +TEST_F(IdAllocatorTest, AllocateIdMax) { + const uint32_t kMaxPossibleRange = std::numeric_limits<uint32_t>::max(); + + IdAllocator* allocator = id_allocator(); + ResourceId id = allocator->AllocateIDRange(kMaxPossibleRange); + EXPECT_EQ(1u, id); + allocator->FreeIDRange(id, kMaxPossibleRange - 1u); + ResourceId id2 = allocator->AllocateIDRange(kMaxPossibleRange); + EXPECT_EQ(0u, id2); + allocator->FreeIDRange(id, kMaxPossibleRange); + ResourceId id3 = allocator->AllocateIDRange(kMaxPossibleRange); + EXPECT_EQ(1u, id3); +} + +TEST_F(IdAllocatorTest, ZeroIdCases) { + IdAllocator* allocator = id_allocator(); + EXPECT_FALSE(allocator->InUse(0)); + ResourceId id1 = allocator->AllocateIDAtOrAbove(0); + EXPECT_NE(0u, id1); + EXPECT_FALSE(allocator->InUse(0)); + allocator->FreeID(0); + EXPECT_FALSE(allocator->InUse(0)); + EXPECT_TRUE(allocator->InUse(id1)); + allocator->FreeID(id1); + EXPECT_FALSE(allocator->InUse(id1)); +} } // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 8c24d3c..766c0bf0 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -585,7 +585,7 @@ bool Initialize(const scoped_refptr<gfx::GLSurface>& surface, const scoped_refptr<gfx::GLContext>& context, bool offscreen, - const gfx::Size& size, + const gfx::Size& offscreen_size, const DisallowedFeatures& disallowed_features, const std::vector<int32>& attribs) override; void Destroy(bool have_context) override; @@ -2434,13 +2434,17 @@ const scoped_refptr<gfx::GLSurface>& surface, const scoped_refptr<gfx::GLContext>& context, bool offscreen, - const gfx::Size& size, + const gfx::Size& offscreen_size, const DisallowedFeatures& disallowed_features, const std::vector<int32>& attribs) { TRACE_EVENT0("gpu", "GLES2DecoderImpl::Initialize"); DCHECK(context->IsCurrent(surface.get())); DCHECK(!context_.get()); + ContextCreationAttribHelper attrib_parser; + if (!attrib_parser.Parse(attribs)) + return false; + surfaceless_ = surface->IsSurfaceless() && !offscreen; set_initialized(); @@ -2457,7 +2461,10 @@ } if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableUnsafeES3APIs)) { + switches::kEnableUnsafeES3APIs) && + attrib_parser.es3_context_required) { + // TODO(zmo): We need to implement capabilities check to ensure we can + // actually create ES3 contexts. set_unsafe_es3_apis_enabled(true); } @@ -2470,10 +2477,6 @@ context_ = context; surface_ = surface; - ContextCreationAttribHelper attrib_parser; - if (!attrib_parser.Parse(attribs)) - return false; - // Create GPU Tracer for timing values. gpu_tracer_.reset(new GPUTracer(this)); @@ -2675,12 +2678,15 @@ // Allocate the render buffers at their initial size and check the status // of the frame buffers is okay. - if (!ResizeOffscreenFrameBuffer(size)) { + if (!ResizeOffscreenFrameBuffer(offscreen_size)) { LOG(ERROR) << "Could not allocate offscreen buffer storage."; Destroy(true); return false; } + state_.viewport_width = offscreen_size.width(); + state_.viewport_height = offscreen_size.height(); + // Allocate the offscreen saved color texture. DCHECK(offscreen_saved_color_format_); offscreen_saved_color_texture_->AllocateStorage( @@ -2720,6 +2726,9 @@ glGetIntegerv(GL_STENCIL_BITS, &v); back_buffer_has_stencil_ = attrib_parser.stencil_size != 0 && v > 0; } + + state_.viewport_width = surface->GetSize().width(); + state_.viewport_height = surface->GetSize().height(); } // OpenGL ES 2.0 implicitly enables the desktop GL capability @@ -2742,9 +2751,6 @@ return false; } - state_.viewport_width = size.width(); - state_.viewport_height = size.height(); - GLint viewport_params[4] = { 0 }; glGetIntegerv(GL_MAX_VIEWPORT_DIMS, viewport_params); viewport_max_width_ = viewport_params[0]; @@ -2956,9 +2962,15 @@ features().nv_draw_buffers ? 1 : 0; } - ShShaderSpec shader_spec = force_webgl_glsl_validation_ ? SH_WEBGL_SPEC - : SH_GLES2_SPEC; - if (shader_spec == SH_WEBGL_SPEC && features().enable_shader_name_hashing) + ShShaderSpec shader_spec; + if (force_webgl_glsl_validation_) { + shader_spec = unsafe_es3_apis_enabled() ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC; + } else { + shader_spec = unsafe_es3_apis_enabled() ? SH_GLES3_SPEC : SH_GLES2_SPEC; + } + + if ((shader_spec == SH_WEBGL_SPEC || shader_spec == SH_WEBGL2_SPEC) && + features().enable_shader_name_hashing) resources.HashFunction = &CityHash64; else resources.HashFunction = NULL;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h index 5ccdf7b..0cbe0fe5 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -115,13 +115,13 @@ // offscreen: whether to make the context offscreen or not. When FBO 0 is // bound, offscreen contexts render to an internal buffer, onscreen ones // to the surface. - // size: the size if the GL context is offscreen. + // offscreen_size: the size if the GL context is offscreen. // Returns: // true if successful. virtual bool Initialize(const scoped_refptr<gfx::GLSurface>& surface, const scoped_refptr<gfx::GLContext>& context, bool offscreen, - const gfx::Size& size, + const gfx::Size& offscreen_size, const DisallowedFeatures& disallowed_features, const std::vector<int32>& attribs) = 0;
diff --git a/gpu/command_buffer/service/image_factory.cc b/gpu/command_buffer/service/image_factory.cc index 1665c1e..9a2d458a 100644 --- a/gpu/command_buffer/service/image_factory.cc +++ b/gpu/command_buffer/service/image_factory.cc
@@ -4,6 +4,7 @@ #include "gpu/command_buffer/service/image_factory.h" +#include "gpu/command_buffer/common/capabilities.h" #include "ui/gl/gl_bindings.h" namespace gpu { @@ -93,4 +94,52 @@ } } +// static +bool ImageFactory::IsGpuMemoryBufferFormatSupported( + gfx::GpuMemoryBuffer::Format format, + const gpu::Capabilities& capabilities) { + switch (format) { + case gfx::GpuMemoryBuffer::ATC: + case gfx::GpuMemoryBuffer::ATCIA: + return capabilities.texture_format_atc; + case gfx::GpuMemoryBuffer::BGRA_8888: + return capabilities.texture_format_bgra8888; + case gfx::GpuMemoryBuffer::DXT1: + return capabilities.texture_format_dxt1; + case gfx::GpuMemoryBuffer::DXT5: + return capabilities.texture_format_dxt5; + case gfx::GpuMemoryBuffer::ETC1: + return capabilities.texture_format_etc1; + case gfx::GpuMemoryBuffer::RGBA_8888: + case gfx::GpuMemoryBuffer::RGBX_8888: + return true; + } + + NOTREACHED(); + return false; +} + +// static +bool ImageFactory::IsImageSizeValidForGpuMemoryBufferFormat( + const gfx::Size& size, + gfx::GpuMemoryBuffer::Format format) { + switch (format) { + case gfx::GpuMemoryBuffer::ATC: + case gfx::GpuMemoryBuffer::ATCIA: + case gfx::GpuMemoryBuffer::DXT1: + case gfx::GpuMemoryBuffer::DXT5: + case gfx::GpuMemoryBuffer::ETC1: + // Compressed images must have a width and height that's evenly divisible + // by the block size. + return size.width() % 4 == 0 && size.height() % 4 == 0; + case gfx::GpuMemoryBuffer::RGBA_8888: + case gfx::GpuMemoryBuffer::BGRA_8888: + case gfx::GpuMemoryBuffer::RGBX_8888: + return true; + } + + NOTREACHED(); + return false; +} + } // namespace gpu
diff --git a/gpu/command_buffer/service/image_factory.h b/gpu/command_buffer/service/image_factory.h index 40dd15a0e..b581342 100644 --- a/gpu/command_buffer/service/image_factory.h +++ b/gpu/command_buffer/service/image_factory.h
@@ -15,6 +15,7 @@ } namespace gpu { +struct Capabilities; class GPU_EXPORT ImageFactory { public: @@ -35,6 +36,16 @@ unsigned internalformat, gfx::GpuMemoryBuffer::Format format); + // Returns true if |format| is supported by |capabilities|. + static bool IsGpuMemoryBufferFormatSupported( + gfx::GpuMemoryBuffer::Format format, + const Capabilities& capabilities); + + // Returns true if |size| is valid for |format|. + static bool IsImageSizeValidForGpuMemoryBufferFormat( + const gfx::Size& size, + gfx::GpuMemoryBuffer::Format format); + // Creates a GLImage instance for GPU memory buffer identified by |handle|. // |client_id| should be set to the client requesting the creation of instance // and can be used by factory implementation to verify access rights.
diff --git a/gpu/command_buffer/service/shader_translator.cc b/gpu/command_buffer/service/shader_translator.cc index 98d738d7..c0904c7b 100644 --- a/gpu/command_buffer/service/shader_translator.cc +++ b/gpu/command_buffer/service/shader_translator.cc
@@ -110,13 +110,19 @@ // Make sure Init is called only once. DCHECK(compiler_ == NULL); DCHECK(shader_type == GL_FRAGMENT_SHADER || shader_type == GL_VERTEX_SHADER); - DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC); + DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC || + shader_spec == SH_GLES3_SPEC || shader_spec == SH_WEBGL2_SPEC); DCHECK(resources != NULL); g_translator_initializer.Get(); - ShShaderOutput shader_output = - (glsl_implementation_type == kGlslES ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT); + ShShaderOutput shader_output; + if (glsl_implementation_type == kGlslES) { + shader_output = SH_ESSL_OUTPUT; + } else { + shader_output = (shader_spec == SH_WEBGL2_SPEC) ? SH_GLSL_CORE_OUTPUT : + SH_GLSL_COMPATIBILITY_OUTPUT; + } { TRACE_EVENT0("gpu", "ShConstructCompiler");
diff --git a/gpu/perftests/run_all_tests.cc b/gpu/perftests/run_all_tests.cc index ed0df88..60a6b03a 100644 --- a/gpu/perftests/run_all_tests.cc +++ b/gpu/perftests/run_all_tests.cc
@@ -9,7 +9,10 @@ int main(int argc, char** argv) { base::TestSuite test_suite(argc, argv); + // Always run the perf tests serially, to avoid distorting + // perf measurements with randomness resulting from running + // in parallel. const auto& run_test_suite = base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)); - return base::LaunchUnitTests(argc, argv, run_test_suite); + return base::LaunchUnitTestsSerially(argc, argv, run_test_suite); }
diff --git a/ios/build/bots/chromium.fyi/Chromium_iOS_Device.json b/ios/build/bots/chromium.fyi/Chromium_iOS_Device.json index e30db2c..5395929 100644 --- a/ios/build/bots/chromium.fyi/Chromium_iOS_Device.json +++ b/ios/build/bots/chromium.fyi/Chromium_iOS_Device.json
@@ -5,14 +5,14 @@ "comments": [ "Builder for 32-bit devices." ], - "xcode version": "5.1.1", + "xcode version": "6.1.1", "GYP_DEFINES": { "chromium_ios_signing": "0", "target_subarch": "arm32" }, "compiler": "xcodebuild", "configuration": "Release", - "sdk": "iphoneos7.1", + "sdk": "iphoneos8.1", "tests": [ ] }
diff --git "a/ios/build/bots/chromium.fyi/Chromium_iOS_Device_\050ninja\051.json" "b/ios/build/bots/chromium.fyi/Chromium_iOS_Device_\050ninja\051.json" index 5ff6f67..ffa2e6d 100644 --- "a/ios/build/bots/chromium.fyi/Chromium_iOS_Device_\050ninja\051.json" +++ "b/ios/build/bots/chromium.fyi/Chromium_iOS_Device_\050ninja\051.json"
@@ -5,14 +5,14 @@ "comments": [ "Builder for fat binaries using ninja." ], - "xcode version": "5.1.1", + "xcode version": "6.1.1", "GYP_DEFINES": { "chromium_ios_signing": "0", "target_subarch": "both" }, "compiler": "ninja", "configuration": "Release", - "sdk": "iphoneos7.1", + "sdk": "iphoneos8.1", "tests": [ ] }
diff --git "a/ios/build/bots/chromium.fyi/Chromium_iOS_Simulator_\050dbg\051.json" "b/ios/build/bots/chromium.fyi/Chromium_iOS_Simulator_\050dbg\051.json" index e6e7e5d..39627503 100644 --- "a/ios/build/bots/chromium.fyi/Chromium_iOS_Simulator_\050dbg\051.json" +++ "b/ios/build/bots/chromium.fyi/Chromium_iOS_Simulator_\050dbg\051.json"
@@ -3,86 +3,86 @@ "smut" ], "comments": [ - "Tests for 32-bit iOS 7.1 iPhone simulator." + "Tests for 32-bit iOS 8.1 iPhone simulator." ], - "xcode version": "5.1.1", + "xcode version": "6.1.1", "GYP_DEFINES": { "chromium_ios_signing": "0", "target_subarch": "arm32" }, "compiler": "xcodebuild", "configuration": "Debug", - "sdk": "iphonesimulator7.1", + "sdk": "iphonesimulator8.1", "tests": [ { "app": "ios_chrome_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "ios_web_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "base_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "components_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "crypto_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "gfx_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "url_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "content_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "net_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "ui_base_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "ui_ios_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "sync_unit_tests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "sql_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" }, { "app": "skia_unittests", - "device type": "iPhone Retina (4-inch)", - "os": "7.1" + "device type": "iPhone 5", + "os": "8.1" } ] }
diff --git a/ios/chrome/DEPS b/ios/chrome/DEPS index 32c8bbd..e568d4e2 100644 --- a/ios/chrome/DEPS +++ b/ios/chrome/DEPS
@@ -4,6 +4,8 @@ "-ios/chrome", "+ios/chrome/grit", + "+components/dom_distiller/core", + "+components/dom_distiller/ios", "+components/infobars/core", "+components/keyed_service/core", "+components/keyed_service/ios",
diff --git a/ios/chrome/browser/dom_distiller/OWNER b/ios/chrome/browser/dom_distiller/OWNER new file mode 100644 index 0000000..bf1620f --- /dev/null +++ b/ios/chrome/browser/dom_distiller/OWNER
@@ -0,0 +1 @@ +noyau@chromium.org
diff --git a/ios/chrome/browser/dom_distiller/distiller_viewer.cc b/ios/chrome/browser/dom_distiller/distiller_viewer.cc new file mode 100644 index 0000000..bf30950 --- /dev/null +++ b/ios/chrome/browser/dom_distiller/distiller_viewer.cc
@@ -0,0 +1,51 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/dom_distiller/distiller_viewer.h" + +#include <string> + +#include "components/dom_distiller/core/distilled_page_prefs.h" +#include "components/dom_distiller/core/dom_distiller_service.h" +#include "components/dom_distiller/core/proto/distilled_article.pb.h" +#include "components/dom_distiller/core/task_tracker.h" +#include "components/dom_distiller/core/viewer.h" +#include "ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h" +#include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h" +#include "ui/gfx/geometry/size.h" + +namespace dom_distiller { + +DistillerViewer::DistillerViewer(ios::ChromeBrowserState* browser_state, + const GURL& url, + const DistillationFinishedCallback& callback) + : url_(url), + callback_(callback), + distilled_page_prefs_(new DistilledPagePrefs(browser_state->GetPrefs())) { + DCHECK(browser_state); + DCHECK(url.is_valid()); + dom_distiller::DomDistillerService* distillerService = + dom_distiller::DomDistillerServiceFactory::GetForBrowserState( + browser_state); + + viewer_handle_ = distillerService->ViewUrl( + this, distillerService->CreateDefaultDistillerPage(gfx::Size()), url); +} + +DistillerViewer::~DistillerViewer() { +} + +void DistillerViewer::OnArticleReady( + const DistilledArticleProto* article_proto) { + const std::string html = viewer::GetUnsafeArticleHtml( + article_proto, distilled_page_prefs_->GetTheme(), + distilled_page_prefs_->GetFontFamily()); + + callback_.Run(url_, html); + + // No need to hold on to the ViewerHandle now that distillation is complete. + viewer_handle_.reset(); +} + +} // namespace dom_distiller
diff --git a/ios/chrome/browser/dom_distiller/distiller_viewer.h b/ios/chrome/browser/dom_distiller/distiller_viewer.h new file mode 100644 index 0000000..d822755 --- /dev/null +++ b/ios/chrome/browser/dom_distiller/distiller_viewer.h
@@ -0,0 +1,54 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_DOM_DISTILLER_DISTILLER_VIEWER_H_ +#define IOS_CHROME_BROWSER_DOM_DISTILLER_DISTILLER_VIEWER_H_ + +#include "base/memory/scoped_ptr.h" +#include "components/dom_distiller/core/task_tracker.h" + +class GURL; + +namespace ios { +class ChromeBrowserState; +} + +namespace dom_distiller { + +class DistilledPagePrefs; + +// A very simple and naive implementation of the dom_distiller +// ViewRequestDelegate: From an URL it builds an HTML string and notifies when +// finished. +class DistillerViewer : public dom_distiller::ViewRequestDelegate { + public: + typedef base::Callback<void(const GURL&, const std::string&)> + DistillationFinishedCallback; + + DistillerViewer(ios::ChromeBrowserState* browser_state, + const GURL& url, + const DistillationFinishedCallback& callback); + ~DistillerViewer() override; + + // ViewRequestDelegate. + void OnArticleUpdated( + dom_distiller::ArticleDistillationUpdate article_update) override {} + void OnArticleReady(const DistilledArticleProto* article_proto) override; + + private: + // The url of the distilled page. + const GURL url_; + // Callback to invoke when the page is finished. + DistillationFinishedCallback callback_; + // Interface for accessing preferences for distilled pages. + scoped_ptr<DistilledPagePrefs> distilled_page_prefs_; + // Keeps the distiller going until the view is released. + scoped_ptr<dom_distiller::ViewerHandle> viewer_handle_; + + DISALLOW_COPY_AND_ASSIGN(DistillerViewer); +}; + +} // namespace dom_distiller + +#endif // IOS_CHROME_BROWSER_DOM_DISTILLER_DISTILLER_VIEWER_H_
diff --git a/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc new file mode 100644 index 0000000..0adbfa7 --- /dev/null +++ b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
@@ -0,0 +1,113 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h" + +#include "base/files/file_path.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/singleton.h" +#include "base/threading/sequenced_worker_pool.h" +#include "components/dom_distiller/core/article_entry.h" +#include "components/dom_distiller/core/distiller.h" +#include "components/dom_distiller/core/dom_distiller_service.h" +#include "components/dom_distiller/core/dom_distiller_store.h" +#include "components/dom_distiller/ios/distiller_page_factory_ios.h" +#include "components/keyed_service/core/keyed_service.h" +#include "components/keyed_service/ios/browser_state_dependency_manager.h" +#include "components/leveldb_proto/proto_database.h" +#include "components/leveldb_proto/proto_database_impl.h" +#include "ios/chrome/browser/browser_state/browser_state_otr_helper.h" +#include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/web/public/browser_state.h" +#include "ios/web/public/web_thread.h" + +namespace { +// A simple wrapper for DomDistillerService to expose it as a +// KeyedService. +class DomDistillerKeyedService + : public KeyedService, + public dom_distiller::DomDistillerService { + public: + DomDistillerKeyedService( + scoped_ptr<dom_distiller::DomDistillerStoreInterface> store, + scoped_ptr<dom_distiller::DistillerFactory> distiller_factory, + scoped_ptr<dom_distiller::DistillerPageFactory> distiller_page_factory, + scoped_ptr<dom_distiller::DistilledPagePrefs> distilled_page_prefs) + : DomDistillerService(store.Pass(), + distiller_factory.Pass(), + distiller_page_factory.Pass(), + distilled_page_prefs.Pass()) {} + + ~DomDistillerKeyedService() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(DomDistillerKeyedService); +}; +} // namespace + +namespace dom_distiller { + +// static +DomDistillerServiceFactory* DomDistillerServiceFactory::GetInstance() { + return Singleton<DomDistillerServiceFactory>::get(); +} + +// static +DomDistillerService* DomDistillerServiceFactory::GetForBrowserState( + web::BrowserState* browser_state) { + return static_cast<DomDistillerKeyedService*>( + GetInstance()->GetServiceForBrowserState(browser_state, true)); +} + +DomDistillerServiceFactory::DomDistillerServiceFactory() + : BrowserStateKeyedServiceFactory( + "DomDistillerService", + BrowserStateDependencyManager::GetInstance()) { +} + +DomDistillerServiceFactory::~DomDistillerServiceFactory() { +} + +KeyedService* DomDistillerServiceFactory::BuildServiceInstanceFor( + web::BrowserState* browser_state) const { + scoped_refptr<base::SequencedTaskRunner> background_task_runner = + web::WebThread::GetBlockingPool()->GetSequencedTaskRunner( + web::WebThread::GetBlockingPool()->GetSequenceToken()); + + scoped_ptr<leveldb_proto::ProtoDatabaseImpl<ArticleEntry>> db( + new leveldb_proto::ProtoDatabaseImpl<ArticleEntry>( + background_task_runner)); + + base::FilePath database_dir( + browser_state->GetStatePath().Append(FILE_PATH_LITERAL("Articles"))); + + scoped_ptr<DomDistillerStore> dom_distiller_store( + new DomDistillerStore(db.Pass(), database_dir)); + + scoped_ptr<DistillerPageFactory> distiller_page_factory( + new DistillerPageFactoryIOS(browser_state)); + scoped_ptr<DistillerURLFetcherFactory> distiller_url_fetcher_factory( + new DistillerURLFetcherFactory(browser_state->GetRequestContext())); + + dom_distiller::proto::DomDistillerOptions options; + scoped_ptr<DistillerFactory> distiller_factory( + new DistillerFactoryImpl(distiller_url_fetcher_factory.Pass(), options)); + scoped_ptr<DistilledPagePrefs> distilled_page_prefs(new DistilledPagePrefs( + ios::ChromeBrowserState::FromBrowserState(browser_state)->GetPrefs())); + + DomDistillerKeyedService* service = + new DomDistillerKeyedService( + dom_distiller_store.Pass(), distiller_factory.Pass(), + distiller_page_factory.Pass(), distilled_page_prefs.Pass()); + + return service; +} + +web::BrowserState* DomDistillerServiceFactory::GetBrowserStateToUse( + web::BrowserState* browser_state) const { + // Makes normal profile and off-the-record profile use same service instance. + return GetBrowserStateRedirectedInIncognito(browser_state); +} + +} // namespace dom_distiller
diff --git a/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h new file mode 100644 index 0000000..802e0fe --- /dev/null +++ b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h
@@ -0,0 +1,46 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_DOM_DISTILLER_DOM_DISTILLER_SERVICE_FACTORY_H_ +#define IOS_CHROME_BROWSER_DOM_DISTILLER_DOM_DISTILLER_SERVICE_FACTORY_H_ + +#include "components/dom_distiller/core/distilled_page_prefs.h" +#include "components/keyed_service/ios/browser_state_keyed_service_factory.h" + +template <typename T> struct DefaultSingletonTraits; + +class KeyedService; + +namespace dom_distiller { +class DomDistillerService; +} + +namespace web { +class BrowserState; +} + +namespace dom_distiller { + +class DomDistillerServiceFactory : public BrowserStateKeyedServiceFactory { + public: + static DomDistillerServiceFactory* GetInstance(); + static DomDistillerService* GetForBrowserState( + web::BrowserState* browser_state); + + private: + friend struct DefaultSingletonTraits<DomDistillerServiceFactory>; + + DomDistillerServiceFactory(); + ~DomDistillerServiceFactory() override; + + // BrowserStateKeyedServiceFactory implementation. + KeyedService* BuildServiceInstanceFor( + web::BrowserState* browser_state) const override; + web::BrowserState* GetBrowserStateToUse( + web::BrowserState* browser_state) const override; +}; + +} // namespace dom_distiller + +#endif // IOS_CHROME_BROWSER_DOM_DISTILLER_DOM_DISTILLER_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/infobars/confirm_infobar_controller.mm b/ios/chrome/browser/infobars/confirm_infobar_controller.mm index 4ead1c1..74e54a6 100644 --- a/ios/chrome/browser/infobars/confirm_infobar_controller.mm +++ b/ios/chrome/browser/infobars/confirm_infobar_controller.mm
@@ -54,9 +54,7 @@ DCHECK(!infoBarView_); infoBarView_.reset([ios::GetChromeBrowserProvider()->CreateInfoBarView() initWithFrame:frame - delegate:delegate_ - isWarning:infoBarModel->GetInfoBarType() == - infobars::InfoBarDelegate::WARNING_TYPE]); + delegate:delegate_]); // Model data. NSString* modelMsg = nil;
diff --git a/ios/chrome/browser/suggestions/suggestions_service_factory.mm b/ios/chrome/browser/suggestions/suggestions_service_factory.mm index efd35e5..400ff13 100644 --- a/ios/chrome/browser/suggestions/suggestions_service_factory.mm +++ b/ios/chrome/browser/suggestions/suggestions_service_factory.mm
@@ -59,7 +59,7 @@ ios::ChromeBrowserState* chrome_browser_state = ios::ChromeBrowserState::FromBrowserState(browser_state); base::FilePath database_dir( - chrome_browser_state->GetPath().Append(kThumbnailDirectory)); + chrome_browser_state->GetStatePath().Append(kThumbnailDirectory)); scoped_ptr<SuggestionsStore> suggestions_store( new SuggestionsStore(chrome_browser_state->GetPrefs())); scoped_ptr<BlacklistStore> blacklist_store(
diff --git a/ios/chrome/browser/translate/after_translate_infobar_controller.mm b/ios/chrome/browser/translate/after_translate_infobar_controller.mm index b325b0f..c6c5c5d 100644 --- a/ios/chrome/browser/translate/after_translate_infobar_controller.mm +++ b/ios/chrome/browser/translate/after_translate_infobar_controller.mm
@@ -34,14 +34,10 @@ frame:(CGRect)frame { _translateInfoBarDelegate = delegate->AsTranslateInfoBarDelegate(); DCHECK(_translateInfoBarDelegate); - infobars::InfoBarDelegate* infoBarDelegate = - static_cast<infobars::InfoBarDelegate*>(_translateInfoBarDelegate); DCHECK(!infoBarView_); infoBarView_.reset([ios::GetChromeBrowserProvider()->CreateInfoBarView() initWithFrame:frame - delegate:delegate_ - isWarning:infoBarDelegate->GetInfoBarType() == - infobars::InfoBarDelegate::WARNING_TYPE]); + delegate:delegate_]); // Icon gfx::Image icon = _translateInfoBarDelegate->GetIcon(); if (!icon.IsEmpty())
diff --git a/ios/chrome/browser/translate/before_translate_infobar_controller.mm b/ios/chrome/browser/translate/before_translate_infobar_controller.mm index 8b98d4b..72aed8c1 100644 --- a/ios/chrome/browser/translate/before_translate_infobar_controller.mm +++ b/ios/chrome/browser/translate/before_translate_infobar_controller.mm
@@ -127,14 +127,10 @@ - (void)layoutForDelegate:(infobars::InfoBarDelegate*)delegate frame:(CGRect)frame { _translateInfoBarDelegate = delegate->AsTranslateInfoBarDelegate(); - infobars::InfoBarDelegate* infoBarDelegate = - static_cast<infobars::InfoBarDelegate*>(_translateInfoBarDelegate); DCHECK(!infoBarView_); infoBarView_.reset([ios::GetChromeBrowserProvider()->CreateInfoBarView() initWithFrame:frame - delegate:delegate_ - isWarning:infoBarDelegate->GetInfoBarType() == - infobars::InfoBarDelegate::WARNING_TYPE]); + delegate:delegate_]); // Icon gfx::Image icon = _translateInfoBarDelegate->GetIcon(); if (!icon.IsEmpty())
diff --git a/ios/chrome/browser/translate/never_translate_infobar_controller.mm b/ios/chrome/browser/translate/never_translate_infobar_controller.mm index bffa013..6ce746e 100644 --- a/ios/chrome/browser/translate/never_translate_infobar_controller.mm +++ b/ios/chrome/browser/translate/never_translate_infobar_controller.mm
@@ -32,15 +32,11 @@ frame:(CGRect)frame { translate::TranslateInfoBarDelegate* translateInfoBarDelegate = delegate->AsTranslateInfoBarDelegate(); - infobars::InfoBarDelegate* infoBarDelegate = - static_cast<infobars::InfoBarDelegate*>(translateInfoBarDelegate); DCHECK(!infoBarView_); ios::ChromeBrowserProvider* provider = ios::GetChromeBrowserProvider(); infoBarView_.reset([provider->CreateInfoBarView() initWithFrame:frame - delegate:delegate_ - isWarning:infoBarDelegate->GetInfoBarType() == - infobars::InfoBarDelegate::WARNING_TYPE]); + delegate:delegate_]); // Icon gfx::Image icon = translateInfoBarDelegate->GetIcon(); if (!icon.IsEmpty())
diff --git a/ios/chrome/browser/translate/translate_message_infobar_controller.mm b/ios/chrome/browser/translate/translate_message_infobar_controller.mm index f3466fc..442d9a17 100644 --- a/ios/chrome/browser/translate/translate_message_infobar_controller.mm +++ b/ios/chrome/browser/translate/translate_message_infobar_controller.mm
@@ -28,14 +28,10 @@ frame:(CGRect)frame { translate::TranslateInfoBarDelegate* translateInfoBarDelegate = delegate->AsTranslateInfoBarDelegate(); - infobars::InfoBarDelegate* infoBarDelegate = - static_cast<infobars::InfoBarDelegate*>(translateInfoBarDelegate); DCHECK(!infoBarView_); infoBarView_.reset([ios::GetChromeBrowserProvider()->CreateInfoBarView() initWithFrame:frame - delegate:delegate_ - isWarning:infoBarDelegate->GetInfoBarType() == - infobars::InfoBarDelegate::WARNING_TYPE]); + delegate:delegate_]); // Icon gfx::Image icon = translateInfoBarDelegate->GetIcon(); if (!icon.IsEmpty())
diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp index 5e68dea..4c2de56 100644 --- a/ios/chrome/ios_chrome.gyp +++ b/ios/chrome/ios_chrome.gyp
@@ -15,6 +15,8 @@ ], 'dependencies': [ '../../base/base.gyp:base', + '../../components/components.gyp:dom_distiller_core', + '../../components/components.gyp:dom_distiller_ios', '../../components/components.gyp:infobars_core', '../../components/components.gyp:keyed_service_core', '../../components/components.gyp:keyed_service_ios', @@ -54,6 +56,10 @@ 'browser/browser_state/browser_state_otr_helper.h', 'browser/chrome_url_constants.cc', 'browser/chrome_url_constants.h', + 'browser/dom_distiller/distiller_viewer.cc', + 'browser/dom_distiller/distiller_viewer.h', + 'browser/dom_distiller/dom_distiller_service_factory.cc', + 'browser/dom_distiller/dom_distiller_service_factory.h', 'browser/infobars/confirm_infobar_controller.h', 'browser/infobars/confirm_infobar_controller.mm', 'browser/infobars/infobar.h', @@ -101,12 +107,12 @@ 'browser/translate/translate_service_ios.h', 'browser/ui/animation_util.h', 'browser/ui/animation_util.mm', - 'browser/ui/commands/UIKit+ChromeExecuteCommand.h', - 'browser/ui/commands/UIKit+ChromeExecuteCommand.mm', 'browser/ui/commands/generic_chrome_command.h', 'browser/ui/commands/generic_chrome_command.mm', 'browser/ui/commands/open_url_command.h', 'browser/ui/commands/open_url_command.mm', + 'browser/ui/commands/UIKit+ChromeExecuteCommand.h', + 'browser/ui/commands/UIKit+ChromeExecuteCommand.mm', 'browser/ui/image_util.h', 'browser/ui/image_util.mm', 'browser/ui/reversed_animation.h',
diff --git a/ios/public/provider/chrome/browser/string_provider.h b/ios/public/provider/chrome/browser/string_provider.h index cefcb0a..573b8ec 100644 --- a/ios/public/provider/chrome/browser/string_provider.h +++ b/ios/public/provider/chrome/browser/string_provider.h
@@ -12,8 +12,8 @@ // A class that provides access to localized strings. class StringProvider { public: - StringProvider() {}; - virtual ~StringProvider() {}; + StringProvider() {} + virtual ~StringProvider() {} // Strings used in //ios/chrome. // TODO(droger): Find a long term solution for strings used in //ios/chrome.
diff --git a/ios/public/provider/chrome/browser/ui/infobar_view_protocol.h b/ios/public/provider/chrome/browser/ui/infobar_view_protocol.h index ed54be8..02aed8b1 100644 --- a/ios/public/provider/chrome/browser/ui/infobar_view_protocol.h +++ b/ios/public/provider/chrome/browser/ui/infobar_view_protocol.h
@@ -17,11 +17,9 @@ // showing/hiding animation. @property(nonatomic, assign) CGFloat visibleHeight; -// The designated initializer. Set |isWarning| to YES to have a warning infobar, -// and to NO to have an informational infobar. +// The designated initializer. - (instancetype)initWithFrame:(CGRect)frame - delegate:(InfoBarViewDelegate*)delegate - isWarning:(BOOL)isWarning; + delegate:(InfoBarViewDelegate*)delegate; // Stops propagating events to delegate. - (void)resetDelegate;
diff --git a/ios/third_party/gcdwebserver/LICENSE b/ios/third_party/gcdwebserver/LICENSE new file mode 100644 index 0000000..12335de --- /dev/null +++ b/ios/third_party/gcdwebserver/LICENSE
@@ -0,0 +1,24 @@ +Copyright (c) 2012-2014, Pierre-Olivier Latour +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. + * The name of Pierre-Olivier Latour may not 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 PIERRE-OLIVIER LATOUR 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.
diff --git a/ios/third_party/gcdwebserver/OWNERS b/ios/third_party/gcdwebserver/OWNERS new file mode 100644 index 0000000..1b3348e7 --- /dev/null +++ b/ios/third_party/gcdwebserver/OWNERS
@@ -0,0 +1,2 @@ +rohitrao@chromium.org +stuartmorgan@chromium.org
diff --git a/ios/third_party/gcdwebserver/README.chromium b/ios/third_party/gcdwebserver/README.chromium new file mode 100644 index 0000000..829fed3 --- /dev/null +++ b/ios/third_party/gcdwebserver/README.chromium
@@ -0,0 +1,10 @@ +Name: gcdwebserver +URL: https://github.com/swisspol/GCDWebServer +Version: 3.2 +License: 3-clause BSD +License File: NOT_SHIPPED +Security Critical: no + +Description: +GCDWebServer is a modern and lightweight GCD based HTTP 1.1 server designed to +be embedded in OS X & iOS apps.
diff --git a/ios/third_party/gcdwebserver/gcdwebserver.gyp b/ios/third_party/gcdwebserver/gcdwebserver.gyp new file mode 100644 index 0000000..a1b4210 --- /dev/null +++ b/ios/third_party/gcdwebserver/gcdwebserver.gyp
@@ -0,0 +1,63 @@ +# 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. +{ + 'targets' : [ + { + 'target_name' : 'gcdwebserver', + 'type': 'static_library', + 'include_dirs': [ + 'src/GCDWebServer/Core', + 'src/GCDWebServer/Requests', + 'src/GCDWebServer/Responses', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + 'src/GCDWebServer/Core', + 'src/GCDWebServer/Requests', + 'src/GCDWebServer/Responses', + ], + }, + 'xcode_settings': { + 'CLANG_ENABLE_OBJC_ARC': 'YES', + }, + 'sources': [ + 'src/GCDWebServer/Core/GCDWebServer.h', + 'src/GCDWebServer/Core/GCDWebServer.m', + 'src/GCDWebServer/Core/GCDWebServerConnection.h', + 'src/GCDWebServer/Core/GCDWebServerConnection.m', + 'src/GCDWebServer/Core/GCDWebServerFunctions.h', + 'src/GCDWebServer/Core/GCDWebServerFunctions.m', + 'src/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h', + 'src/GCDWebServer/Core/GCDWebServerPrivate.h', + 'src/GCDWebServer/Core/GCDWebServerRequest.h', + 'src/GCDWebServer/Core/GCDWebServerRequest.m', + 'src/GCDWebServer/Core/GCDWebServerResponse.h', + 'src/GCDWebServer/Core/GCDWebServerResponse.m', + 'src/GCDWebServer/Requests/GCDWebServerDataRequest.h', + 'src/GCDWebServer/Requests/GCDWebServerDataRequest.m', + 'src/GCDWebServer/Requests/GCDWebServerFileRequest.h', + 'src/GCDWebServer/Requests/GCDWebServerFileRequest.m', + 'src/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h', + 'src/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m', + 'src/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h', + 'src/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m', + 'src/GCDWebServer/Responses/GCDWebServerDataResponse.h', + 'src/GCDWebServer/Responses/GCDWebServerDataResponse.m', + 'src/GCDWebServer/Responses/GCDWebServerErrorResponse.h', + 'src/GCDWebServer/Responses/GCDWebServerErrorResponse.m', + 'src/GCDWebServer/Responses/GCDWebServerFileResponse.h', + 'src/GCDWebServer/Responses/GCDWebServerFileResponse.m', + 'src/GCDWebServer/Responses/GCDWebServerStreamedResponse.h', + 'src/GCDWebServer/Responses/GCDWebServerStreamedResponse.m', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/CFNetwork.framework', + '$(SDKROOT)/System/Library/Frameworks/MobileCoreServices.framework', + '$(SDKROOT)/usr/lib/libz.dylib', + ], + }, + }, + ], +}
diff --git a/ios/web/public/browser_state.h b/ios/web/public/browser_state.h index 0a3c131..b4f2ade 100644 --- a/ios/web/public/browser_state.h +++ b/ios/web/public/browser_state.h
@@ -28,7 +28,9 @@ virtual bool IsOffTheRecord() const = 0; // Returns the path where the BrowserState data is stored. - virtual base::FilePath GetPath() const = 0; + // Unlike Profile::GetPath(), incognito BrowserState do not share their path + // with their original BrowserState. + virtual base::FilePath GetStatePath() const = 0; // Returns the request context information associated with this // BrowserState.
diff --git a/ios/web/public/test/test_browser_state.cc b/ios/web/public/test/test_browser_state.cc index f9d428c..a5af592 100644 --- a/ios/web/public/test/test_browser_state.cc +++ b/ios/web/public/test/test_browser_state.cc
@@ -17,7 +17,7 @@ return false; } -base::FilePath TestBrowserState::GetPath() const { +base::FilePath TestBrowserState::GetStatePath() const { return base::FilePath(); }
diff --git a/ios/web/public/test/test_browser_state.h b/ios/web/public/test/test_browser_state.h index 320ba00..7544548 100644 --- a/ios/web/public/test/test_browser_state.h +++ b/ios/web/public/test/test_browser_state.h
@@ -15,7 +15,7 @@ // BrowserState: bool IsOffTheRecord() const override; - base::FilePath GetPath() const override; + base::FilePath GetStatePath() const override; net::URLRequestContextGetter* GetRequestContext() override; }; } // namespace web
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h index b5c003a..e934c98d 100644 --- a/ipc/ipc_message_start.h +++ b/ipc/ipc_message_start.h
@@ -118,6 +118,7 @@ // Note: CastCryptoMsgStart reserved for Chromecast internal code. // Contact gunsch@ before changing/removing. CastCryptoMsgStart, + DataReductionProxyStart, LastIPCMsgStart // Must come last. };
diff --git a/ipc/ipc_test_base.cc b/ipc/ipc_test_base.cc index 745d0b4a..e8fa6a47 100644 --- a/ipc/ipc_test_base.cc +++ b/ipc/ipc_test_base.cc
@@ -153,7 +153,7 @@ return GetChannelName(test_client_name_); } -scoped_refptr<base::TaskRunner> IPCTestBase::task_runner() { +scoped_refptr<base::SequencedTaskRunner> IPCTestBase::task_runner() { return message_loop_->message_loop_proxy(); }
diff --git a/ipc/ipc_test_base.h b/ipc/ipc_test_base.h index 5ed7dd5..b3c6bf9e 100644 --- a/ipc/ipc_test_base.h +++ b/ipc/ipc_test_base.h
@@ -101,7 +101,7 @@ IPC::ChannelProxy* channel_proxy() { return channel_proxy_.get(); } const base::Process& client_process() const { return client_process_; } - scoped_refptr<base::TaskRunner> task_runner(); + scoped_refptr<base::SequencedTaskRunner> task_runner(); virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory( const IPC::ChannelHandle& handle, base::TaskRunner* runner);
diff --git a/ipc/mojo/BUILD.gn b/ipc/mojo/BUILD.gn index 39855c4..6d2a9f8 100644 --- a/ipc/mojo/BUILD.gn +++ b/ipc/mojo/BUILD.gn
@@ -28,6 +28,8 @@ "ipc_mojo_handle_attachment.h", "ipc_mojo_message_helper.cc", "ipc_mojo_message_helper.h", + "scoped_ipc_support.cc", + "scoped_ipc_support.h", ] defines = [ "IPC_MOJO_IMPLEMENTATION" ]
diff --git a/ipc/mojo/async_handle_waiter.cc b/ipc/mojo/async_handle_waiter.cc index 7b199ed..b9e68d7 100644 --- a/ipc/mojo/async_handle_waiter.cc +++ b/ipc/mojo/async_handle_waiter.cc
@@ -9,7 +9,6 @@ #include "base/bind_helpers.h" #include "base/location.h" #include "base/logging.h" -#include "base/message_loop/message_loop.h" #include "third_party/mojo/src/mojo/edk/embedder/embedder.h" namespace IPC { @@ -32,7 +31,7 @@ : io_runner_(base::MessageLoopForIO::current()->task_runner()), waiter_(waiter), last_result_(MOJO_RESULT_INTERNAL), - processing_(false), + io_loop_level_(0), should_invoke_callback_(false) { base::MessageLoopForIO::current()->AddIOObserver(this); } @@ -67,7 +66,7 @@ return false; if (loop->task_runner() != io_runner_) return false; - return processing_; + return io_loop_level_ > 0; } // Called from |io_runner_| thus safe to touch |waiter_|. @@ -81,19 +80,25 @@ // IOObserver implementation: void WillProcessIOEvent() override { - DCHECK(!should_invoke_callback_); - DCHECK(!processing_); - processing_ = true; + DCHECK(io_loop_level_ != 0 || !should_invoke_callback_); + DCHECK_GE(io_loop_level_, 0); + io_loop_level_++; } void DidProcessIOEvent() override { - DCHECK(processing_); + DCHECK_GE(io_loop_level_, 1); + + // Leaving a nested loop. + if (io_loop_level_ > 1) { + io_loop_level_--; + return; + } // The zero |waiter_| indicates that |this| have lost the owner and can be // under destruction. So we cannot wrap it with a |scoped_refptr| anymore. if (!waiter_) { should_invoke_callback_ = false; - processing_ = false; + io_loop_level_--; return; } @@ -105,7 +110,7 @@ InvokeWaiterCallback(); } - processing_ = false; + io_loop_level_--; } // Only |io_runner_| is accessed from arbitrary threads. Others are touched @@ -114,7 +119,7 @@ const base::WeakPtr<AsyncHandleWaiter> waiter_; MojoResult last_result_; - bool processing_; + int io_loop_level_; bool should_invoke_callback_; DISALLOW_COPY_AND_ASSIGN(Context); @@ -139,6 +144,14 @@ callback_.Run(result); } +base::MessageLoopForIO::IOObserver* AsyncHandleWaiter::GetIOObserverForTest() { + return context_.get(); +} + +base::Callback<void(MojoResult)> AsyncHandleWaiter::GetWaitCallbackForTest() { + return base::Bind(&Context::HandleIsReady, context_); +} + // static void AsyncHandleWaiterContextTraits::Destruct( const AsyncHandleWaiter::Context* context) {
diff --git a/ipc/mojo/async_handle_waiter.h b/ipc/mojo/async_handle_waiter.h index 55acb3e..d6cc745 100644 --- a/ipc/mojo/async_handle_waiter.h +++ b/ipc/mojo/async_handle_waiter.h
@@ -8,6 +8,7 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "base/message_loop/message_loop.h" #include "ipc/ipc_export.h" #include "third_party/mojo/src/mojo/public/c/system/types.h" @@ -32,6 +33,9 @@ MojoResult Wait(MojoHandle handle, MojoHandleSignals signals); + base::MessageLoopForIO::IOObserver* GetIOObserverForTest(); + base::Callback<void(MojoResult)> GetWaitCallbackForTest(); + private: void InvokeCallback(MojoResult result);
diff --git a/ipc/mojo/async_handle_waiter_unittest.cc b/ipc/mojo/async_handle_waiter_unittest.cc index fbaf3ca..38f3bd6 100644 --- a/ipc/mojo/async_handle_waiter_unittest.cc +++ b/ipc/mojo/async_handle_waiter_unittest.cc
@@ -204,6 +204,53 @@ ignore_result(pipe_to_read_.release()); } +class AsyncHandleWaiterIOObserverTest : public testing::Test { + public: + void SetUp() override { + message_loop_.reset(new base::MessageLoopForIO()); + target_.reset(new AsyncHandleWaiter( + base::Bind(&AsyncHandleWaiterIOObserverTest::HandleIsReady, + base::Unretained(this)))); + invocation_count_ = 0; + } + + void HandleIsReady(MojoResult result) { invocation_count_++; } + + scoped_ptr<base::MessageLoop> message_loop_; + scoped_ptr<AsyncHandleWaiter> target_; + size_t invocation_count_; +}; + +TEST_F(AsyncHandleWaiterIOObserverTest, OutsideIOEvnet) { + target_->GetWaitCallbackForTest().Run(MOJO_RESULT_OK); + EXPECT_EQ(0U, invocation_count_); + message_loop_->RunUntilIdle(); + EXPECT_EQ(1U, invocation_count_); +} + +TEST_F(AsyncHandleWaiterIOObserverTest, InsideIOEvnet) { + target_->GetIOObserverForTest()->WillProcessIOEvent(); + target_->GetWaitCallbackForTest().Run(MOJO_RESULT_OK); + EXPECT_EQ(0U, invocation_count_); + target_->GetIOObserverForTest()->DidProcessIOEvent(); + EXPECT_EQ(1U, invocation_count_); +} + +TEST_F(AsyncHandleWaiterIOObserverTest, Reenter) { + target_->GetIOObserverForTest()->WillProcessIOEvent(); + target_->GetWaitCallbackForTest().Run(MOJO_RESULT_OK); + EXPECT_EQ(0U, invocation_count_); + + // As if some other io handler start nested loop. + target_->GetIOObserverForTest()->WillProcessIOEvent(); + target_->GetWaitCallbackForTest().Run(MOJO_RESULT_OK); + target_->GetIOObserverForTest()->DidProcessIOEvent(); + EXPECT_EQ(0U, invocation_count_); + + target_->GetIOObserverForTest()->DidProcessIOEvent(); + EXPECT_EQ(1U, invocation_count_); +} + } // namespace } // namespace internal } // namespace IPC
diff --git a/ipc/mojo/ipc_channel_mojo.cc b/ipc/mojo/ipc_channel_mojo.cc index 0c6c994..6cf8130 100644 --- a/ipc/mojo/ipc_channel_mojo.cc +++ b/ipc/mojo/ipc_channel_mojo.cc
@@ -48,9 +48,9 @@ //------------------------------------------------------------------------------ -class ClientChannelMojo - : public ChannelMojo, - public NON_EXPORTED_BASE(mojo::InterfaceImpl<ClientChannel>) { +class ClientChannelMojo : public ChannelMojo, + public ClientChannel, + public mojo::ErrorHandler { public: ClientChannelMojo(ChannelMojo::Delegate* delegate, const ChannelHandle& handle, @@ -58,7 +58,7 @@ ~ClientChannelMojo() override; // MojoBootstrap::Delegate implementation void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle) override; - // InterfaceImpl implementation + // mojo::ErrorHandler implementation void OnConnectionError() override; // ClientChannel implementation void Init( @@ -66,13 +66,17 @@ int32_t peer_pid, const mojo::Callback<void(int32_t)>& callback) override; + private: + mojo::Binding<ClientChannel> binding_; + DISALLOW_COPY_AND_ASSIGN(ClientChannelMojo); }; ClientChannelMojo::ClientChannelMojo(ChannelMojo::Delegate* delegate, const ChannelHandle& handle, Listener* listener) - : ChannelMojo(delegate, handle, Channel::MODE_CLIENT, listener) { + : ChannelMojo(delegate, handle, Channel::MODE_CLIENT, listener), + binding_(this) { } ClientChannelMojo::~ClientChannelMojo() { @@ -80,7 +84,7 @@ void ClientChannelMojo::OnPipeAvailable( mojo::embedder::ScopedPlatformHandle handle) { - mojo::WeakBindToPipe(this, CreateMessagingPipe(handle.Pass())); + binding_.Bind(CreateMessagingPipe(handle.Pass())); } void ClientChannelMojo::OnConnectionError() { @@ -106,7 +110,7 @@ // MojoBootstrap::Delegate implementation void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle) override; - // ErrorHandler implementation + // mojo::ErrorHandler implementation void OnConnectionError() override; // Channel override void Close() override; @@ -180,7 +184,7 @@ void ChannelMojo::ChannelInfoDeleter::operator()( mojo::embedder::ChannelInfo* ptr) const { - mojo::embedder::DestroyChannel(ptr); + mojo::embedder::DestroyChannel(ptr, base::Bind(&base::DoNothing), nullptr); } //------------------------------------------------------------------------------ @@ -219,9 +223,10 @@ // static scoped_ptr<ChannelFactory> ChannelMojo::CreateClientFactory( + ChannelMojo::Delegate* delegate, const ChannelHandle& channel_handle) { return make_scoped_ptr( - new MojoChannelFactory(NULL, channel_handle, Channel::MODE_CLIENT)); + new MojoChannelFactory(delegate, channel_handle, Channel::MODE_CLIENT)); } ChannelMojo::ChannelMojo(ChannelMojo::Delegate* delegate, @@ -253,6 +258,8 @@ } void ChannelMojo::InitDelegate(ChannelMojo::Delegate* delegate) { + ipc_support_.reset( + new ScopedIPCSupport(base::MessageLoop::current()->task_runner())); delegate_ = delegate->ToWeakPtr(); delegate_->OnChannelCreated(weak_factory_.GetWeakPtr()); } @@ -275,6 +282,7 @@ void ChannelMojo::Close() { message_reader_.reset(); channel_info_.reset(); + ipc_support_.reset(); } void ChannelMojo::OnBootstrapError() { @@ -288,7 +296,7 @@ for (size_t i = 0; i < pending_messages_.size(); ++i) { bool sent = message_reader_->Send(make_scoped_ptr(pending_messages_[i])); - pending_messages_[i] = NULL; + pending_messages_[i] = nullptr; if (!sent) { pending_messages_.clear(); listener_->OnChannelError();
diff --git a/ipc/mojo/ipc_channel_mojo.h b/ipc/mojo/ipc_channel_mojo.h index 71d1d10..1959e0f 100644 --- a/ipc/mojo/ipc_channel_mojo.h +++ b/ipc/mojo/ipc_channel_mojo.h
@@ -15,6 +15,7 @@ #include "ipc/ipc_export.h" #include "ipc/mojo/ipc_message_pipe_reader.h" #include "ipc/mojo/ipc_mojo_bootstrap.h" +#include "ipc/mojo/scoped_ipc_support.h" #include "third_party/mojo/src/mojo/edk/embedder/channel_info_forward.h" #include "third_party/mojo/src/mojo/public/cpp/system/core.h" @@ -75,6 +76,7 @@ const ChannelHandle& channel_handle); static scoped_ptr<ChannelFactory> CreateClientFactory( + Delegate* delegate, const ChannelHandle& channel_handle); ~ChannelMojo() override; @@ -147,6 +149,8 @@ scoped_ptr<internal::MessagePipeReader, ReaderDeleter> message_reader_; ScopedVector<Message> pending_messages_; + scoped_ptr<ScopedIPCSupport> ipc_support_; + base::WeakPtrFactory<ChannelMojo> weak_factory_; DISALLOW_COPY_AND_ASSIGN(ChannelMojo);
diff --git a/ipc/mojo/ipc_channel_mojo_host.cc b/ipc/mojo/ipc_channel_mojo_host.cc index beb18ee..7e1bff9 100644 --- a/ipc/mojo/ipc_channel_mojo_host.cc +++ b/ipc/mojo/ipc_channel_mojo_host.cc
@@ -10,14 +10,22 @@ namespace IPC { +class ChannelMojoHost::ChannelDelegateTraits { + public: + static void Destruct(const ChannelMojoHost::ChannelDelegate* ptr); +}; + // The delete class lives on the IO thread to talk to ChannelMojo on // behalf of ChannelMojoHost. // // The object must be touched only on the IO thread. -class ChannelMojoHost::ChannelDelegate : public ChannelMojo::Delegate { +class ChannelMojoHost::ChannelDelegate + : public base::RefCountedThreadSafe<ChannelMojoHost::ChannelDelegate, + ChannelMojoHost::ChannelDelegateTraits>, + public ChannelMojo::Delegate { public: - explicit ChannelDelegate(scoped_refptr<base::TaskRunner> io_task_runner); - ~ChannelDelegate() override; + explicit ChannelDelegate( + scoped_refptr<base::SequencedTaskRunner> io_task_runner); // ChannelMojo::Delegate base::WeakPtr<Delegate> ToWeakPtr() override; @@ -27,10 +35,14 @@ // Returns an weak ptr of ChannelDelegate instead of Delegate base::WeakPtr<ChannelDelegate> GetWeakPtr(); void OnClientLaunched(base::ProcessHandle process); - void DeleteThisSoon(); + void DeleteThisSoon() const; private: - scoped_refptr<base::TaskRunner> io_task_runner_; + friend class base::DeleteHelper<ChannelDelegate>; + + ~ChannelDelegate() override; + + scoped_refptr<base::SequencedTaskRunner> io_task_runner_; base::WeakPtr<ChannelMojo> channel_; base::WeakPtrFactory<ChannelDelegate> weak_factory_; @@ -38,7 +50,7 @@ }; ChannelMojoHost::ChannelDelegate::ChannelDelegate( - scoped_refptr<base::TaskRunner> io_task_runner) + scoped_refptr<base::SequencedTaskRunner> io_task_runner) : io_task_runner_(io_task_runner), weak_factory_(this) { } @@ -72,18 +84,16 @@ channel_->OnClientLaunched(process); } -void ChannelMojoHost::ChannelDelegate::DeleteThisSoon() { - io_task_runner_->PostTask( - FROM_HERE, - base::Bind(&base::DeletePointer<ChannelMojoHost::ChannelDelegate>, - base::Unretained(this))); +void ChannelMojoHost::ChannelDelegate::DeleteThisSoon() const { + io_task_runner_->DeleteSoon(FROM_HERE, this); } // // ChannelMojoHost // -ChannelMojoHost::ChannelMojoHost(scoped_refptr<base::TaskRunner> io_task_runner) +ChannelMojoHost::ChannelMojoHost( + scoped_refptr<base::SequencedTaskRunner> io_task_runner) : io_task_runner_(io_task_runner), channel_delegate_(new ChannelDelegate(io_task_runner)), weak_factory_(this) { @@ -98,8 +108,7 @@ } else { io_task_runner_->PostTask(FROM_HERE, base::Bind(&ChannelDelegate::OnClientLaunched, - channel_delegate_->GetWeakPtr(), - process)); + channel_delegate_, process)); } } @@ -107,8 +116,9 @@ return channel_delegate_.get(); } -void ChannelMojoHost::DelegateDeleter::operator()( - ChannelMojoHost::ChannelDelegate* ptr) const { +// static +void ChannelMojoHost::ChannelDelegateTraits::Destruct( + const ChannelMojoHost::ChannelDelegate* ptr) { ptr->DeleteThisSoon(); }
diff --git a/ipc/mojo/ipc_channel_mojo_host.h b/ipc/mojo/ipc_channel_mojo_host.h index 8289515..db60b12 100644 --- a/ipc/mojo/ipc_channel_mojo_host.h +++ b/ipc/mojo/ipc_channel_mojo_host.h
@@ -12,7 +12,7 @@ #include "ipc/mojo/ipc_channel_mojo.h" namespace base { -class TaskRunner; +class SequencedTaskRunner; } namespace IPC { @@ -23,7 +23,8 @@ // instance and call OnClientLaunched(). class IPC_MOJO_EXPORT ChannelMojoHost { public: - explicit ChannelMojoHost(scoped_refptr<base::TaskRunner> io_task_runner); + explicit ChannelMojoHost( + scoped_refptr<base::SequencedTaskRunner> io_task_runner); ~ChannelMojoHost(); void OnClientLaunched(base::ProcessHandle process); @@ -31,16 +32,10 @@ private: class ChannelDelegate; + class ChannelDelegateTraits; - // Delegate talks to ChannelMojo, whch lives in IO thread, thus - // the Delegate should also live and dies in the IO thread as well. - class DelegateDeleter { - public: - void operator()(ChannelDelegate* ptr) const; - }; - - const scoped_refptr<base::TaskRunner> io_task_runner_; - scoped_ptr<ChannelDelegate, DelegateDeleter> channel_delegate_; + const scoped_refptr<base::SequencedTaskRunner> io_task_runner_; + scoped_refptr<ChannelDelegate> channel_delegate_; base::WeakPtrFactory<ChannelMojoHost> weak_factory_; DISALLOW_COPY_AND_ASSIGN(ChannelMojoHost);
diff --git a/ipc/mojo/ipc_channel_mojo_unittest.cc b/ipc/mojo/ipc_channel_mojo_unittest.cc index d0ab5d6..8817445 100644 --- a/ipc/mojo/ipc_channel_mojo_unittest.cc +++ b/ipc/mojo/ipc_channel_mojo_unittest.cc
@@ -9,6 +9,7 @@ #include "base/message_loop/message_loop.h" #include "base/path_service.h" #include "base/pickle.h" +#include "base/run_loop.h" #include "base/test/test_timeouts.h" #include "base/threading/thread.h" #include "ipc/ipc_message.h" @@ -17,6 +18,7 @@ #include "ipc/mojo/ipc_channel_mojo_host.h" #include "ipc/mojo/ipc_mojo_handle_attachment.h" #include "ipc/mojo/ipc_mojo_message_helper.h" +#include "ipc/mojo/scoped_ipc_support.h" #if defined(OS_POSIX) #include "base/file_descriptor_posix.h" @@ -63,6 +65,8 @@ class ChannelClient { public: explicit ChannelClient(IPC::Listener* listener, const char* name) { + ipc_support_.reset( + new IPC::ScopedIPCSupport(main_message_loop_.task_runner())); channel_ = IPC::ChannelMojo::Create(NULL, IPCTestBase::GetChannelName(name), IPC::Channel::MODE_CLIENT, @@ -73,14 +77,45 @@ CHECK(channel_->Connect()); } + void Close() { + channel_->Close(); + + base::RunLoop run_loop; + base::MessageLoop::current()->PostTask(FROM_HERE, run_loop.QuitClosure()); + run_loop.Run(); + } + IPC::ChannelMojo* channel() const { return channel_.get(); } private: base::MessageLoopForIO main_message_loop_; + scoped_ptr<IPC::ScopedIPCSupport> ipc_support_; scoped_ptr<IPC::ChannelMojo> channel_; }; -class IPCChannelMojoTest : public IPCTestBase { +class IPCChannelMojoTestBase : public IPCTestBase { + public: + void InitWithMojo(const std::string& test_client_name) { + Init(test_client_name); + ipc_support_.reset(new IPC::ScopedIPCSupport(task_runner())); + } + + void TearDown() override { + // Make sure Mojo IPC support is properly shutdown on the I/O loop before + // TearDown continues. + ipc_support_.reset(); + base::RunLoop run_loop; + task_runner()->PostTask(FROM_HERE, run_loop.QuitClosure()); + run_loop.Run(); + + IPCTestBase::TearDown(); + } + + private: + scoped_ptr<IPC::ScopedIPCSupport> ipc_support_; +}; + +class IPCChannelMojoTest : public IPCChannelMojoTestBase { protected: scoped_ptr<IPC::ChannelFactory> CreateChannelFactory( const IPC::ChannelHandle& handle, @@ -122,7 +157,7 @@ }; TEST_F(IPCChannelMojoTest, ConnectedFromClient) { - Init("IPCChannelMojoTestClient"); + InitWithMojo("IPCChannelMojoTestClient"); // Set up IPC channel and start client. TestChannelListenerWithExtraExpectations listener; @@ -159,6 +194,8 @@ EXPECT_TRUE(listener.is_connected_called()); EXPECT_TRUE(listener.HasSentAll()); + client.Close(); + return 0; } @@ -186,7 +223,7 @@ }; -class IPCChannelMojoErrorTest : public IPCTestBase { +class IPCChannelMojoErrorTest : public IPCChannelMojoTestBase { protected: scoped_ptr<IPC::ChannelFactory> CreateChannelFactory( const IPC::ChannelHandle& handle, @@ -229,11 +266,13 @@ base::MessageLoop::current()->Run(); + client.Close(); + return 0; } TEST_F(IPCChannelMojoErrorTest, SendFailWithPendingMessages) { - Init("IPCChannelMojoErraticTestClient"); + InitWithMojo("IPCChannelMojoErraticTestClient"); // Set up IPC channel and start client. ListenerExpectingErrors listener; @@ -373,7 +412,7 @@ }; TEST_F(IPCChannelMojoTest, SendMessagePipe) { - Init("IPCChannelMojoTestSendMessagePipeClient"); + InitWithMojo("IPCChannelMojoTestSendMessagePipeClient"); ListenerThatExpectsOK listener; CreateChannel(&listener); @@ -392,17 +431,19 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendMessagePipeClient) { ListenerThatExpectsMessagePipe listener; - ChannelClient client(&listener, "IPCChannelMojoTestSendPlatformHandleClient"); + ChannelClient client(&listener, "IPCChannelMojoTestSendMessagePipeClient"); client.Connect(); listener.set_sender(client.channel()); base::MessageLoop::current()->Run(); + client.Close(); + return 0; } #if defined(OS_WIN) -class IPCChannelMojoDeadHandleTest : public IPCTestBase { +class IPCChannelMojoDeadHandleTest : public IPCChannelMojoTestBase { protected: virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory( const IPC::ChannelHandle& handle, @@ -417,7 +458,7 @@ const base::ProcessHandle client = client_process().Handle(); // Forces GetFileHandleForProcess() fail. It happens occasionally // in production, so we should exercise it somehow. - // TODO(morrita): figure out how to safely test this. + // TODO(morrita): figure out how to safely test this. See crbug.com/464109. // ::CloseHandle(client); host_->OnClientLaunched(client); return true; @@ -429,7 +470,7 @@ TEST_F(IPCChannelMojoDeadHandleTest, InvalidClientHandle) { // Any client type is fine as it is going to be killed anyway. - Init("IPCChannelMojoTestDoNothingClient"); + InitWithMojo("IPCChannelMojoTestDoNothingClient"); // Set up IPC channel and start client. ListenerExpectingErrors listener; @@ -441,9 +482,11 @@ this->channel()->Close(); - // WaitForClientShutdown() fails as client_hanadle() is already - // closed. - EXPECT_FALSE(WaitForClientShutdown()); + // TODO(morrita): We need CloseHandle() call in DidStartClient(), + // which has been disabled since crrev.com/843113003, to + // make this fail. See crbug.com/464109. + // EXPECT_FALSE(WaitForClientShutdown()); + WaitForClientShutdown(); EXPECT_TRUE(listener.has_error()); DestroyChannel(); @@ -489,7 +532,7 @@ TEST_F(IPCChannelMojoTest, SendPlatformHandle) { - Init("IPCChannelMojoTestSendPlatformHandleClient"); + InitWithMojo("IPCChannelMojoTestSendPlatformHandleClient"); ListenerThatExpectsOK listener; CreateChannel(&listener); @@ -517,6 +560,8 @@ base::MessageLoop::current()->Run(); + client.Close(); + return 0; } @@ -544,7 +589,7 @@ }; TEST_F(IPCChannelMojoTest, SendPlatformHandleAndPipe) { - Init("IPCChannelMojoTestSendPlatformHandleAndPipeClient"); + InitWithMojo("IPCChannelMojoTestSendPlatformHandleAndPipeClient"); ListenerThatExpectsOK listener; CreateChannel(&listener); @@ -574,6 +619,8 @@ base::MessageLoop::current()->Run(); + client.Close(); + return 0; } @@ -597,7 +644,7 @@ }; TEST_F(IPCChannelMojoTest, VerifyGlobalPid) { - Init("IPCChannelMojoTestVerifyGlobalPidClient"); + InitWithMojo("IPCChannelMojoTestVerifyGlobalPidClient"); ListenerThatVerifiesPeerPid listener; CreateChannel(&listener); @@ -605,7 +652,7 @@ ASSERT_TRUE(StartClient()); base::MessageLoop::current()->Run(); - this->channel()->Close(); + channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); @@ -620,6 +667,8 @@ base::MessageLoop::current()->Run(); + client.Close(); + return 0; }
diff --git a/ipc/mojo/ipc_mojo.gyp b/ipc/mojo/ipc_mojo.gyp index 0f746fc8..44f18175 100644 --- a/ipc/mojo/ipc_mojo.gyp +++ b/ipc/mojo/ipc_mojo.gyp
@@ -42,6 +42,8 @@ 'ipc_mojo_message_helper.h', 'ipc_message_pipe_reader.cc', 'ipc_message_pipe_reader.h', + 'scoped_ipc_support.cc', + 'scoped_ipc_support.h', ], # TODO(gregoryd): direct_dependent_settings should be shared with the # 64-bit target, but it doesn't work due to a bug in gyp
diff --git a/ipc/mojo/scoped_ipc_support.cc b/ipc/mojo/scoped_ipc_support.cc new file mode 100644 index 0000000..fafc9c2 --- /dev/null +++ b/ipc/mojo/scoped_ipc_support.cc
@@ -0,0 +1,112 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ipc/mojo/scoped_ipc_support.h" + +#include "base/bind.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/synchronization/condition_variable.h" +#include "base/synchronization/lock.h" +#include "base/synchronization/waitable_event.h" +#include "third_party/mojo/src/mojo/edk/embedder/embedder.h" +#include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h" + +namespace IPC { + +namespace { + +class IPCSupportInitializer : public mojo::embedder::ProcessDelegate { + public: + IPCSupportInitializer() + : init_count_(0), + shutting_down_(false) { + } + + ~IPCSupportInitializer() override {} + + void Init(scoped_refptr<base::TaskRunner> io_thread_task_runner) { + base::AutoLock locker(lock_); + DCHECK((init_count_ == 0 && !io_thread_task_runner_) || + io_thread_task_runner_ == io_thread_task_runner); + + if (shutting_down_) { + // If reinitialized before a pending shutdown task is executed, we + // effectively cancel the shutdown task. + DCHECK(init_count_ == 1); + shutting_down_ = false; + return; + } + + init_count_++; + if (init_count_ == 1) { + io_thread_task_runner_ = io_thread_task_runner; + mojo::embedder::InitIPCSupport(mojo::embedder::ProcessType::NONE, + io_thread_task_runner_, + this, io_thread_task_runner_, + mojo::embedder::ScopedPlatformHandle()); + } + } + + void ShutDown() { + base::AutoLock locker(lock_); + DCHECK(init_count_ > 0); + DCHECK(!shutting_down_); + + if (init_count_ > 1) { + init_count_--; + return; + } + + shutting_down_ = true; + if (base::MessageLoop::current() && + base::MessageLoop::current()->task_runner() == io_thread_task_runner_) { + base::AutoUnlock unlocker_(lock_); + ShutDownOnIOThread(); + } else { + io_thread_task_runner_->PostTask( + FROM_HERE, + base::Bind(&IPCSupportInitializer::ShutDownOnIOThread, + base::Unretained(this))); + } + } + + private: + void ShutDownOnIOThread() { + base::AutoLock locker(lock_); + if (shutting_down_) { + DCHECK(init_count_ == 1); + mojo::embedder::ShutdownIPCSupportOnIOThread(); + init_count_ = 0; + shutting_down_ = false; + io_thread_task_runner_ = nullptr; + } + } + + void OnShutdownComplete() override {} + + base::Lock lock_; + size_t init_count_; + bool shutting_down_; + + scoped_refptr<base::TaskRunner> io_thread_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(IPCSupportInitializer); +}; + +base::LazyInstance<IPCSupportInitializer>::Leaky ipc_support_initializer; + +} // namespace + +ScopedIPCSupport::ScopedIPCSupport( + scoped_refptr<base::TaskRunner> io_thread_task_runner) { + ipc_support_initializer.Get().Init(io_thread_task_runner); +} + +ScopedIPCSupport::~ScopedIPCSupport() { + ipc_support_initializer.Get().ShutDown(); +} + +} // namespace IPC
diff --git a/ipc/mojo/scoped_ipc_support.h b/ipc/mojo/scoped_ipc_support.h new file mode 100644 index 0000000..21013fa --- /dev/null +++ b/ipc/mojo/scoped_ipc_support.h
@@ -0,0 +1,34 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IPC_MOJO_SCOPED_IPC_SUPPORT_H_ +#define IPC_MOJO_SCOPED_IPC_SUPPORT_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/task_runner.h" +#include "ipc/ipc_export.h" + +namespace IPC { + +// Perform any necessary Mojo IPC initialization. A ScopedIPCSupport object +// should be instantiated and retained by any component which makes direct calls +// to the Mojo EDK. This is used to ensure that the EDK is initialized within +// the current process and that it is shutdown cleanly when no longer in use. +// +// NOTE: Unless you are making explicit calls to functions in the +// mojo::embedder namespace, you almost definitely DO NOT need this and should +// not be using it. +class IPC_MOJO_EXPORT ScopedIPCSupport { + public: + ScopedIPCSupport(scoped_refptr<base::TaskRunner> io_thread_task_runner); + ~ScopedIPCSupport(); + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedIPCSupport); +}; + +} // namespace IPC + +#endif // IPC_MOJO_SCOPED_IPC_SUPPORT_H_
diff --git a/media/BUILD.gn b/media/BUILD.gn index 8b6cc692..31a6efd 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn
@@ -32,6 +32,9 @@ if (use_cras) { defines += [ "USE_CRAS" ] } + if (use_alsa) { + defines += [ "USE_ALSA" ] + } } config("media_dependent_config") { @@ -120,8 +123,6 @@ "filters/file_data_source.h", "filters/frame_processor.cc", "filters/frame_processor.h", - "filters/gpu_video_accelerator_factories.cc", - "filters/gpu_video_accelerator_factories.h", "filters/h264_bit_reader.cc", "filters/h264_bit_reader.h", "filters/h264_parser.cc", @@ -198,6 +199,8 @@ "midi/usb_midi_output_stream.h", "renderers/audio_renderer_impl.cc", "renderers/audio_renderer_impl.h", + "renderers/gpu_video_accelerator_factories.cc", + "renderers/gpu_video_accelerator_factories.h", "renderers/renderer_impl.cc", "renderers/renderer_impl.h", "renderers/video_renderer_impl.cc", @@ -352,7 +355,6 @@ if (use_alsa) { libs += [ "asound" ] - defines += [ "USE_ALSA" ] sources += [ "midi/midi_manager_alsa.cc", "midi/midi_manager_alsa.h", @@ -711,10 +713,10 @@ sources = [ "filters/clockless_video_frame_scheduler.cc", "filters/clockless_video_frame_scheduler.h", - "filters/mock_gpu_video_accelerator_factories.cc", - "filters/mock_gpu_video_accelerator_factories.h", "filters/test_video_frame_scheduler.cc", "filters/test_video_frame_scheduler.h", + "renderers/mock_gpu_video_accelerator_factories.cc", + "renderers/mock_gpu_video_accelerator_factories.h", "video/mock_video_decode_accelerator.cc", "video/mock_video_decode_accelerator.h", ]
diff --git a/media/audio/cras/audio_manager_cras.h b/media/audio/cras/audio_manager_cras.h index 0bceb456..4c8f992e 100644 --- a/media/audio/cras/audio_manager_cras.h +++ b/media/audio/cras/audio_manager_cras.h
@@ -20,34 +20,34 @@ AudioManagerCras(AudioLogFactory* audio_log_factory); // AudioManager implementation. - virtual bool HasAudioOutputDevices() override; - virtual bool HasAudioInputDevices() override; - virtual void ShowAudioInputSettings() override; - virtual void GetAudioInputDeviceNames( - AudioDeviceNames* device_names) override; - virtual void GetAudioOutputDeviceNames( - AudioDeviceNames* device_names) override; - virtual AudioParameters GetInputStreamParameters( + bool HasAudioOutputDevices() override; + bool HasAudioInputDevices() override; + void ShowAudioInputSettings() override; + void GetAudioInputDeviceNames(AudioDeviceNames* device_names) override; + void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override; + AudioParameters GetInputStreamParameters( const std::string& device_id) override; - virtual void SetHasKeyboardMic() override; + void SetHasKeyboardMic() override; // AudioManagerBase implementation. - virtual AudioOutputStream* MakeLinearOutputStream( + AudioOutputStream* MakeLinearOutputStream( const AudioParameters& params) override; - virtual AudioOutputStream* MakeLowLatencyOutputStream( + AudioOutputStream* MakeLowLatencyOutputStream( const AudioParameters& params, const std::string& device_id) override; - virtual AudioInputStream* MakeLinearInputStream( - const AudioParameters& params, const std::string& device_id) override; - virtual AudioInputStream* MakeLowLatencyInputStream( - const AudioParameters& params, const std::string& device_id) override; + AudioInputStream* MakeLinearInputStream( + const AudioParameters& params, + const std::string& device_id) override; + AudioInputStream* MakeLowLatencyInputStream( + const AudioParameters& params, + const std::string& device_id) override; static snd_pcm_format_t BitsToFormat(int bits_per_sample); protected: - virtual ~AudioManagerCras(); + ~AudioManagerCras() override; - virtual AudioParameters GetPreferredOutputStreamParameters( + AudioParameters GetPreferredOutputStreamParameters( const std::string& output_device_id, const AudioParameters& input_params) override;
diff --git a/media/audio/cras/cras_input.h b/media/audio/cras/cras_input.h index f290f1e..be50ac7 100644 --- a/media/audio/cras/cras_input.h +++ b/media/audio/cras/cras_input.h
@@ -25,22 +25,23 @@ public: // The ctor takes all the usual parameters, plus |manager| which is the // audio manager who is creating this object. - CrasInputStream(const AudioParameters& params, AudioManagerCras* manager, + CrasInputStream(const AudioParameters& params, + AudioManagerCras* manager, const std::string& device_id); // The dtor is typically called by the AudioManager only and it is usually // triggered by calling AudioOutputStream::Close(). - virtual ~CrasInputStream(); + ~CrasInputStream() override; // Implementation of AudioInputStream. - virtual bool Open() override; - virtual void Start(AudioInputCallback* callback) override; - virtual void Stop() override; - virtual void Close() override; - virtual double GetMaxVolume() override; - virtual void SetVolume(double volume) override; - virtual double GetVolume() override; - virtual bool IsMuted() override; + bool Open() override; + void Start(AudioInputCallback* callback) override; + void Stop() override; + void Close() override; + double GetMaxVolume() override; + void SetVolume(double volume) override; + double GetVolume() override; + bool IsMuted() override; private: // Handles requests to get samples from the provided buffer. This will be
diff --git a/media/audio/cras/cras_unified.h b/media/audio/cras/cras_unified.h index 464fee6..2326648 100644 --- a/media/audio/cras/cras_unified.h +++ b/media/audio/cras/cras_unified.h
@@ -33,15 +33,15 @@ // The dtor is typically called by the AudioManager only and it is usually // triggered by calling AudioUnifiedStream::Close(). - virtual ~CrasUnifiedStream(); + ~CrasUnifiedStream() override; // Implementation of AudioOutputStream. - virtual bool Open() override; - virtual void Close() override; - virtual void Start(AudioSourceCallback* callback) override; - virtual void Stop() override; - virtual void SetVolume(double volume) override; - virtual void GetVolume(double* volume) override; + bool Open() override; + void Close() override; + void Start(AudioSourceCallback* callback) override; + void Stop() override; + void SetVolume(double volume) override; + void GetVolume(double* volume) override; private: // Convert Latency in time to bytes.
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn index 11d87f2..235ef60 100644 --- a/media/base/BUILD.gn +++ b/media/base/BUILD.gn
@@ -172,6 +172,8 @@ "video_decoder_config.h", "video_frame.cc", "video_frame.h", + "video_frame_metadata.cc", + "video_frame_metadata.h", "video_frame_pool.cc", "video_frame_pool.h", "video_renderer.cc", @@ -272,6 +274,8 @@ sources = [ "video_frame.cc", "video_frame.h", + "video_frame_metadata.cc", + "video_frame_metadata.h", ] configs += [ "//build/config/compiler:no_size_t_to_int_warning",
diff --git a/media/base/android/media_player_android.cc b/media/base/android/media_player_android.cc index 954ba96c..eb52e3a5 100644 --- a/media/base/android/media_player_android.cc +++ b/media/base/android/media_player_android.cc
@@ -21,6 +21,7 @@ player_id_(player_id), manager_(manager), frame_url_(frame_url), + is_audible_(false), weak_factory_(this) { listener_.reset(new MediaPlayerListener(base::MessageLoopProxy::current(), weak_factory_.GetWeakPtr())); @@ -79,5 +80,11 @@ listener_->ReleaseMediaPlayerListenerResources(); } +void MediaPlayerAndroid::SetAudible(bool is_audible) { + if (is_audible_ != is_audible) { + is_audible_ = is_audible; + manager_->OnAudibleStateChanged(player_id(), is_audible_); + } +} } // namespace media
diff --git a/media/base/android/media_player_android.h b/media/base/android/media_player_android.h index cd5a92f1..d9091d4 100644 --- a/media/base/android/media_player_android.h +++ b/media/base/android/media_player_android.h
@@ -102,6 +102,7 @@ // events. Otherwise, it also listens to the events from |j_media_player|. void AttachListener(jobject j_media_player); void DetachListener(); + void SetAudible(bool is_audible); MediaPlayerManager* manager() { return manager_; } @@ -122,6 +123,9 @@ // Listener object that listens to all the media player events. scoped_ptr<MediaPlayerListener> listener_; + // Maintains the audible state of the player, true if it is playing sound. + bool is_audible_; + // Weak pointer passed to |listener_| for callbacks. // NOTE: Weak pointers must be invalidated before all other member variables. base::WeakPtrFactory<MediaPlayerAndroid> weak_factory_;
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc index a9bf7e4..ed8854f 100644 --- a/media/base/android/media_player_bridge.cc +++ b/media/base/android/media_player_bridge.cc
@@ -355,6 +355,8 @@ if (j_media_player_bridge_.is_null()) return; + SetAudible(false); + time_update_timer_.Stop(); if (prepared_) { pending_seek_ = GetCurrentTime(); @@ -371,15 +373,22 @@ } void MediaPlayerBridge::SetVolume(double volume) { - if (j_media_player_bridge_.is_null()) { - volume_ = volume; + volume_ = volume; + + if (j_media_player_bridge_.is_null()) return; - } JNIEnv* env = base::android::AttachCurrentThread(); CHECK(env); + + // Update the audible state if we are playing. + jboolean is_playing = Java_MediaPlayerBridge_isPlaying( + env, j_media_player_bridge_.obj()); + if (is_playing) + SetAudible(volume_ > 0); + Java_MediaPlayerBridge_setVolume( - env, j_media_player_bridge_.obj(), volume); + env, j_media_player_bridge_.obj(), volume_); } void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) { @@ -389,11 +398,13 @@ } void MediaPlayerBridge::OnPlaybackComplete() { + SetAudible(false); time_update_timer_.Stop(); MediaPlayerAndroid::OnPlaybackComplete(); } void MediaPlayerBridge::OnMediaInterrupted() { + SetAudible(false); time_update_timer_.Stop(); MediaPlayerAndroid::OnMediaInterrupted(); } @@ -453,9 +464,13 @@ base::TimeDelta::FromMilliseconds(kTimeUpdateInterval), this, &MediaPlayerBridge::OnTimeUpdateTimerFired); } + + SetAudible(volume_ > 0); } void MediaPlayerBridge::PauseInternal() { + SetAudible(false); + JNIEnv* env = base::android::AttachCurrentThread(); Java_MediaPlayerBridge_pause(env, j_media_player_bridge_.obj()); time_update_timer_.Stop();
diff --git a/media/base/android/media_player_manager.h b/media/base/android/media_player_manager.h index 58a712f..de23d4f 100644 --- a/media/base/android/media_player_manager.h +++ b/media/base/android/media_player_manager.h
@@ -63,6 +63,9 @@ // Called when video size has changed. Args: player ID, width, height. virtual void OnVideoSizeChanged(int player_id, int width, int height) = 0; + // Called when the player thinks it stopped or started making sound. + virtual void OnAudibleStateChanged(int player_id, bool is_audible_now) = 0; + // Returns the player that's in the fullscreen mode currently. virtual MediaPlayerAndroid* GetFullscreenPlayer() = 0;
diff --git a/media/base/android/media_source_player_unittest.cc b/media/base/android/media_source_player_unittest.cc index 9ac934e..6750537 100644 --- a/media/base/android/media_source_player_unittest.cc +++ b/media/base/android/media_source_player_unittest.cc
@@ -75,6 +75,7 @@ const base::TimeDelta& current_time) override {} void OnError(int player_id, int error) override {} void OnVideoSizeChanged(int player_id, int width, int height) override {} + void OnAudibleStateChanged(int player_id, bool is_audible_now) override {} MediaPlayerAndroid* GetFullscreenPlayer() override { return NULL; } MediaPlayerAndroid* GetPlayer(int player_id) override { return NULL; } void RequestFullScreen(int player_id) override {}
diff --git a/media/base/audio_renderer.h b/media/base/audio_renderer.h index 7d0e3d76..586936a 100644 --- a/media/base/audio_renderer.h +++ b/media/base/audio_renderer.h
@@ -39,13 +39,18 @@ // |ended_cb| is executed when audio rendering has reached the end of stream. // // |error_cb| is executed if an error was encountered after initialization. - virtual void Initialize(DemuxerStream* stream, - const PipelineStatusCB& init_cb, - const SetDecryptorReadyCB& set_decryptor_ready_cb, - const StatisticsCB& statistics_cb, - const BufferingStateCB& buffering_state_cb, - const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) = 0; + // + // |waiting_for_decryption_key_cb| is called whenever the key needed to + // decrypt the stream is not available. + virtual void Initialize( + DemuxerStream* stream, + const PipelineStatusCB& init_cb, + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const StatisticsCB& statistics_cb, + const BufferingStateCB& buffering_state_cb, + const base::Closure& ended_cb, + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) = 0; // Returns the TimeSource associated with audio rendering. virtual TimeSource* GetTimeSource() = 0;
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index c8d1c822..9731fd0f 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h
@@ -121,16 +121,17 @@ virtual ~MockVideoRenderer(); // VideoRenderer implementation. - MOCK_METHOD9(Initialize, - void(DemuxerStream* stream, - const PipelineStatusCB& init_cb, - const SetDecryptorReadyCB& set_decryptor_ready_cb, - const StatisticsCB& statistics_cb, - const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, - const base::Closure& ended_cb, - const PipelineStatusCB& error_cb, - const TimeDeltaCB& get_time_cb)); + MOCK_METHOD10(Initialize, + void(DemuxerStream* stream, + const PipelineStatusCB& init_cb, + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const StatisticsCB& statistics_cb, + const BufferingStateCB& buffering_state_cb, + const PaintCB& paint_cb, + const base::Closure& ended_cb, + const PipelineStatusCB& error_cb, + const TimeDeltaCB& get_time_cb, + const base::Closure& waiting_for_decryption_key_cb)); MOCK_METHOD1(Flush, void(const base::Closure& callback)); MOCK_METHOD1(StartPlayingFrom, void(base::TimeDelta)); @@ -144,14 +145,15 @@ virtual ~MockAudioRenderer(); // AudioRenderer implementation. - MOCK_METHOD7(Initialize, + MOCK_METHOD8(Initialize, void(DemuxerStream* stream, const PipelineStatusCB& init_cb, const SetDecryptorReadyCB& set_decryptor_ready_cb, const StatisticsCB& statistics_cb, const BufferingStateCB& buffering_state_cb, const base::Closure& ended_cb, - const PipelineStatusCB& error_cb)); + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb)); MOCK_METHOD0(GetTimeSource, TimeSource*()); MOCK_METHOD1(Flush, void(const base::Closure& callback)); MOCK_METHOD0(StartPlaying, void()); @@ -167,13 +169,15 @@ virtual ~MockRenderer(); // Renderer implementation. - MOCK_METHOD7(Initialize, void(DemuxerStreamProvider* demuxer_stream_provider, - const PipelineStatusCB& init_cb, - const StatisticsCB& statistics_cb, - const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, - const base::Closure& ended_cb, - const PipelineStatusCB& error_cb)); + MOCK_METHOD8(Initialize, + void(DemuxerStreamProvider* demuxer_stream_provider, + const PipelineStatusCB& init_cb, + const StatisticsCB& statistics_cb, + const BufferingStateCB& buffering_state_cb, + const PaintCB& paint_cb, + const base::Closure& ended_cb, + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb)); MOCK_METHOD1(Flush, void(const base::Closure& flush_cb)); MOCK_METHOD1(StartPlayingFrom, void(base::TimeDelta timestamp)); MOCK_METHOD1(SetPlaybackRate, void(float playback_rate));
diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc index e9c52d66..d1fae01 100644 --- a/media/base/pipeline.cc +++ b/media/base/pipeline.cc
@@ -70,7 +70,8 @@ const BufferingStateCB& buffering_state_cb, const PaintCB& paint_cb, const base::Closure& duration_change_cb, - const AddTextTrackCB& add_text_track_cb) { + const AddTextTrackCB& add_text_track_cb, + const base::Closure& waiting_for_decryption_key_cb) { DCHECK(!ended_cb.is_null()); DCHECK(!error_cb.is_null()); DCHECK(!seek_cb.is_null()); @@ -92,6 +93,7 @@ paint_cb_ = paint_cb; duration_change_cb_ = duration_change_cb; add_text_track_cb_ = add_text_track_cb; + waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; task_runner_->PostTask( FROM_HERE, base::Bind(&Pipeline::StartTask, weak_factory_.GetWeakPtr())); @@ -724,7 +726,8 @@ base::Bind(&Pipeline::BufferingStateChanged, weak_this), base::ResetAndReturn(&paint_cb_), base::Bind(&Pipeline::OnRendererEnded, weak_this), - base::Bind(&Pipeline::OnError, weak_this)); + base::Bind(&Pipeline::OnError, weak_this), + waiting_for_decryption_key_cb_); } void Pipeline::ReportMetadata() {
diff --git a/media/base/pipeline.h b/media/base/pipeline.h index 6bca477..30707b3 100644 --- a/media/base/pipeline.h +++ b/media/base/pipeline.h
@@ -105,6 +105,8 @@ // |duration_change_cb| optional callback that will be executed whenever the // presentation duration changes. // |add_text_track_cb| will be executed whenever a text track is added. + // |waiting_for_decryption_key_cb| will be executed whenever the key needed + // to decrypt the stream is not available. // It is an error to call this method after the pipeline has already started. void Start(Demuxer* demuxer, scoped_ptr<Renderer> renderer, @@ -115,7 +117,8 @@ const BufferingStateCB& buffering_state_cb, const PaintCB& paint_cb, const base::Closure& duration_change_cb, - const AddTextTrackCB& add_text_track_cb); + const AddTextTrackCB& add_text_track_cb, + const base::Closure& waiting_for_decryption_key_cb); // Asynchronously stops the pipeline, executing |stop_cb| when the pipeline // teardown has completed. @@ -360,6 +363,7 @@ PaintCB paint_cb_; base::Closure duration_change_cb_; AddTextTrackCB add_text_track_cb_; + base::Closure waiting_for_decryption_key_cb_; // Holds the initialized demuxer. Used for seeking. Owned by client. Demuxer* demuxer_;
diff --git a/media/base/pipeline_unittest.cc b/media/base/pipeline_unittest.cc index affb643..147e744 100644 --- a/media/base/pipeline_unittest.cc +++ b/media/base/pipeline_unittest.cc
@@ -170,7 +170,7 @@ // Sets up expectations to allow the video renderer to initialize. void SetRendererExpectations() { - EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _)) + EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _)) .WillOnce(DoAll(SaveArg<3>(&buffering_state_cb_), SaveArg<5>(&ended_cb_), PostCallback<1>(PIPELINE_OK))); @@ -187,6 +187,7 @@ } void StartPipeline() { + EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); pipeline_->Start( demuxer_.get(), scoped_renderer_.Pass(), base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)), @@ -199,7 +200,9 @@ base::Unretained(&callbacks_)), base::Bind(&CallbackHelper::OnDurationChange, base::Unretained(&callbacks_)), - base::Bind(&PipelineTest::OnAddTextTrack, base::Unretained(this))); + base::Bind(&PipelineTest::OnAddTextTrack, base::Unretained(this)), + base::Bind(&PipelineTest::OnWaitingForDecryptionKey, + base::Unretained(this))); } // Sets up expectations on the callback and initializes the pipeline. Called @@ -296,6 +299,7 @@ MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig&, const AddTextTrackDoneCB&)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); void DoOnAddTextTrack(const TextTrackConfig& config, const AddTextTrackDoneCB& done_cb) { @@ -857,13 +861,13 @@ if (state == kInitRenderer) { if (stop_or_error == kStop) { - EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _)) + EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _)) .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb), PostCallback<1>(PIPELINE_OK))); ExpectPipelineStopAndDestroyPipeline(); } else { status = PIPELINE_ERROR_INITIALIZATION_FAILED; - EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _)) + EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _)) .WillOnce(PostCallback<1>(status)); } @@ -872,7 +876,7 @@ return status; } - EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _)) + EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _)) .WillOnce(DoAll(SaveArg<3>(&buffering_state_cb_), PostCallback<1>(PIPELINE_OK)));
diff --git a/media/base/renderer.h b/media/base/renderer.h index 1c7afbd98..e3647f7 100644 --- a/media/base/renderer.h +++ b/media/base/renderer.h
@@ -43,13 +43,17 @@ // be called from any thread. // - |ended_cb|: Executed when rendering has reached the end of stream. // - |error_cb|: Executed if any error was encountered after initialization. - virtual void Initialize(DemuxerStreamProvider* demuxer_stream_provider, - const PipelineStatusCB& init_cb, - const StatisticsCB& statistics_cb, - const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, - const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) = 0; + // - |waiting_for_decryption_key_cb|: Executed whenever the key needed to + // decrypt the stream is not available. + virtual void Initialize( + DemuxerStreamProvider* demuxer_stream_provider, + const PipelineStatusCB& init_cb, + const StatisticsCB& statistics_cb, + const BufferingStateCB& buffering_state_cb, + const PaintCB& paint_cb, + const base::Closure& ended_cb, + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) = 0; // Associates the |cdm_context| with this Renderer for decryption (and // decoding) of media data, then fires |cdm_attached_cb| with the result.
diff --git a/media/base/video_capturer_source.h b/media/base/video_capturer_source.h index 56ec729..774f28d 100644 --- a/media/base/video_capturer_source.h +++ b/media/base/video_capturer_source.h
@@ -42,7 +42,6 @@ // the first video frame delivered may not have timestamp equal to 0. typedef base::Callback< void(const scoped_refptr<media::VideoFrame>& video_frame, - const media::VideoCaptureFormat& format, const base::TimeTicks& estimated_capture_time)> VideoCaptureDeliverFrameCB;
diff --git a/media/base/video_frame.h b/media/base/video_frame.h index 366a356..cebed0af 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h
@@ -12,6 +12,7 @@ #include "base/memory/shared_memory.h" #include "base/synchronization/lock.h" #include "media/base/buffers.h" +#include "media/base/video_frame_metadata.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -288,6 +289,15 @@ // Returns the offset into the shared memory where the frame data begins. size_t shared_memory_offset() const; + // Returns a dictionary of optional metadata. This contains information + // associated with the frame that downstream clients might use for frame-level + // logging, quality/performance optimizations, signaling, etc. + // + // TODO(miu): Move some of the "extra" members of VideoFrame (below) into + // here as a later clean-up step. + const VideoFrameMetadata* metadata() const { return &metadata_; } + VideoFrameMetadata* metadata() { return &metadata_; } + bool allow_overlay() const { return allow_overlay_; } #if defined(OS_POSIX) @@ -403,6 +413,8 @@ const bool end_of_stream_; + VideoFrameMetadata metadata_; + bool allow_overlay_; DISALLOW_IMPLICIT_CONSTRUCTORS(VideoFrame);
diff --git a/media/base/video_frame_metadata.cc b/media/base/video_frame_metadata.cc new file mode 100644 index 0000000..d14bbe9 --- /dev/null +++ b/media/base/video_frame_metadata.cc
@@ -0,0 +1,125 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "media/base/video_frame_metadata.h" + +namespace media { + +namespace { + +// Map enum key to internal std::string key used by base::DictionaryValue. +inline std::string ToInternalKey(VideoFrameMetadata::Key key) { + DCHECK_LT(key, VideoFrameMetadata::NUM_KEYS); + return base::IntToString(static_cast<int>(key)); +} + +} // namespace + +VideoFrameMetadata::VideoFrameMetadata() {} + +VideoFrameMetadata::~VideoFrameMetadata() {} + +bool VideoFrameMetadata::HasKey(Key key) const { + return dictionary_.HasKey(ToInternalKey(key)); +} + +void VideoFrameMetadata::SetBoolean(Key key, bool value) { + dictionary_.SetBooleanWithoutPathExpansion(ToInternalKey(key), value); +} + +void VideoFrameMetadata::SetInteger(Key key, int value) { + dictionary_.SetIntegerWithoutPathExpansion(ToInternalKey(key), value); +} + +void VideoFrameMetadata::SetDouble(Key key, double value) { + dictionary_.SetDoubleWithoutPathExpansion(ToInternalKey(key), value); +} + +void VideoFrameMetadata::SetString(Key key, const std::string& value) { + dictionary_.SetWithoutPathExpansion( + ToInternalKey(key), + // Using BinaryValue since we don't want the |value| interpreted as having + // any particular character encoding (e.g., UTF-8) by + // base::DictionaryValue. + base::BinaryValue::CreateWithCopiedBuffer(value.data(), value.size())); +} + +void VideoFrameMetadata::SetTimeTicks(Key key, const base::TimeTicks& value) { + const int64 internal_value = value.ToInternalValue(); + dictionary_.SetWithoutPathExpansion( + ToInternalKey(key), + base::BinaryValue::CreateWithCopiedBuffer( + reinterpret_cast<const char*>(&internal_value), + sizeof(internal_value))); +} + +void VideoFrameMetadata::SetValue(Key key, scoped_ptr<base::Value> value) { + dictionary_.SetWithoutPathExpansion(ToInternalKey(key), value.Pass()); +} + +bool VideoFrameMetadata::GetBoolean(Key key, bool* value) const { + DCHECK(value); + return dictionary_.GetBooleanWithoutPathExpansion(ToInternalKey(key), value); +} + +bool VideoFrameMetadata::GetInteger(Key key, int* value) const { + DCHECK(value); + return dictionary_.GetIntegerWithoutPathExpansion(ToInternalKey(key), value); +} + +bool VideoFrameMetadata::GetDouble(Key key, double* value) const { + DCHECK(value); + return dictionary_.GetDoubleWithoutPathExpansion(ToInternalKey(key), value); +} + +bool VideoFrameMetadata::GetString(Key key, std::string* value) const { + DCHECK(value); + const base::BinaryValue* const binary_value = GetBinaryValue(key); + if (binary_value) + value->assign(binary_value->GetBuffer(), binary_value->GetSize()); + return !!binary_value; +} + +bool VideoFrameMetadata::GetTimeTicks(Key key, base::TimeTicks* value) const { + DCHECK(value); + const base::BinaryValue* const binary_value = GetBinaryValue(key); + if (binary_value && binary_value->GetSize() == sizeof(int64)) { + int64 internal_value; + memcpy(&internal_value, binary_value->GetBuffer(), sizeof(internal_value)); + *value = base::TimeTicks::FromInternalValue(internal_value); + return true; + } + return false; +} + +const base::Value* VideoFrameMetadata::GetValue(Key key) const { + const base::Value* result = nullptr; + if (!dictionary_.GetWithoutPathExpansion(ToInternalKey(key), &result)) + return nullptr; + return result; +} + +void VideoFrameMetadata::MergeInternalValuesInto( + base::DictionaryValue* out) const { + out->MergeDictionary(&dictionary_); +} + +void VideoFrameMetadata::MergeInternalValuesFrom( + const base::DictionaryValue& in) { + dictionary_.MergeDictionary(&in); +} + +const base::BinaryValue* VideoFrameMetadata::GetBinaryValue(Key key) const { + const base::Value* internal_value = nullptr; + if (dictionary_.GetWithoutPathExpansion(ToInternalKey(key), + &internal_value) && + internal_value->GetType() == base::Value::TYPE_BINARY) { + return static_cast<const base::BinaryValue*>(internal_value); + } + return nullptr; +} + +} // namespace media
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h new file mode 100644 index 0000000..31fbe74 --- /dev/null +++ b/media/base/video_frame_metadata.h
@@ -0,0 +1,70 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_VIDEO_FRAME_METADATA_H_ +#define MEDIA_BASE_VIDEO_FRAME_METADATA_H_ + +#include "base/compiler_specific.h" +#include "base/time/time.h" +#include "base/values.h" +#include "media/base/media_export.h" + +namespace media { + +class MEDIA_EXPORT VideoFrameMetadata { + public: + enum Key { + // Video capture begin/end timestamps. Consumers can use these values for + // dynamic optimizations, logging stats, etc. Use Get/SetTimeTicks() for + // these keys. + CAPTURE_BEGIN_TIME, + CAPTURE_END_TIME, + + // Represents either the fixed frame rate, or the maximum frame rate to + // expect from a variable-rate source. Use Get/SetDouble() for this key. + FRAME_RATE, + + NUM_KEYS + }; + + VideoFrameMetadata(); + ~VideoFrameMetadata(); + + bool HasKey(Key key) const; + + void Clear() { dictionary_.Clear(); } + + // Setters. Overwrites existing value, if present. + void SetBoolean(Key key, bool value); + void SetInteger(Key key, int value); + void SetDouble(Key key, double value); + void SetString(Key key, const std::string& value); + void SetTimeTicks(Key key, const base::TimeTicks& value); + void SetValue(Key key, scoped_ptr<base::Value> value); + + // Getters. Returns true if |key| was present and has the value has been set. + bool GetBoolean(Key key, bool* value) const WARN_UNUSED_RESULT; + bool GetInteger(Key key, int* value) const WARN_UNUSED_RESULT; + bool GetDouble(Key key, double* value) const WARN_UNUSED_RESULT; + bool GetString(Key key, std::string* value) const WARN_UNUSED_RESULT; + bool GetTimeTicks(Key key, base::TimeTicks* value) const WARN_UNUSED_RESULT; + + // Returns null if |key| was not present. + const base::Value* GetValue(Key key) const WARN_UNUSED_RESULT; + + // For serialization. + void MergeInternalValuesInto(base::DictionaryValue* out) const; + void MergeInternalValuesFrom(const base::DictionaryValue& in); + + private: + const base::BinaryValue* GetBinaryValue(Key key) const; + + base::DictionaryValue dictionary_; + + DISALLOW_COPY_AND_ASSIGN(VideoFrameMetadata); +}; + +} // namespace media + +#endif // MEDIA_BASE_VIDEO_FRAME_METADATA_H_
diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc index f2635f96..5c2159f 100644 --- a/media/base/video_frame_unittest.cc +++ b/media/base/video_frame_unittest.cc
@@ -328,4 +328,83 @@ EXPECT_EQ(0, frame->data(i)[0]); } +TEST(VideoFrameMetadata, SetAndThenGetAllKeysForAllTypes) { + VideoFrameMetadata metadata; + + for (int i = 0; i < VideoFrameMetadata::NUM_KEYS; ++i) { + const VideoFrameMetadata::Key key = static_cast<VideoFrameMetadata::Key>(i); + + EXPECT_FALSE(metadata.HasKey(key)); + metadata.SetBoolean(key, true); + EXPECT_TRUE(metadata.HasKey(key)); + bool bool_value = false; + EXPECT_TRUE(metadata.GetBoolean(key, &bool_value)); + EXPECT_EQ(true, bool_value); + metadata.Clear(); + + EXPECT_FALSE(metadata.HasKey(key)); + metadata.SetInteger(key, i); + EXPECT_TRUE(metadata.HasKey(key)); + int int_value = -999; + EXPECT_TRUE(metadata.GetInteger(key, &int_value)); + EXPECT_EQ(i, int_value); + metadata.Clear(); + + EXPECT_FALSE(metadata.HasKey(key)); + metadata.SetDouble(key, 3.14 * i); + EXPECT_TRUE(metadata.HasKey(key)); + double double_value = -999.99; + EXPECT_TRUE(metadata.GetDouble(key, &double_value)); + EXPECT_EQ(3.14 * i, double_value); + metadata.Clear(); + + EXPECT_FALSE(metadata.HasKey(key)); + metadata.SetString(key, base::StringPrintf("\xfe%d\xff", i)); + EXPECT_TRUE(metadata.HasKey(key)); + std::string string_value; + EXPECT_TRUE(metadata.GetString(key, &string_value)); + EXPECT_EQ(base::StringPrintf("\xfe%d\xff", i), string_value); + metadata.Clear(); + + EXPECT_FALSE(metadata.HasKey(key)); + metadata.SetTimeTicks(key, base::TimeTicks::FromInternalValue(~(0LL) + i)); + EXPECT_TRUE(metadata.HasKey(key)); + base::TimeTicks ticks_value; + EXPECT_TRUE(metadata.GetTimeTicks(key, &ticks_value)); + EXPECT_EQ(base::TimeTicks::FromInternalValue(~(0LL) + i), ticks_value); + metadata.Clear(); + + EXPECT_FALSE(metadata.HasKey(key)); + metadata.SetValue(key, + scoped_ptr<base::Value>(base::Value::CreateNullValue())); + EXPECT_TRUE(metadata.HasKey(key)); + const base::Value* const null_value = metadata.GetValue(key); + EXPECT_TRUE(null_value); + EXPECT_EQ(base::Value::TYPE_NULL, null_value->GetType()); + metadata.Clear(); + } +} + +TEST(VideoFrameMetadata, PassMetadataViaIntermediary) { + VideoFrameMetadata expected; + for (int i = 0; i < VideoFrameMetadata::NUM_KEYS; ++i) { + const VideoFrameMetadata::Key key = static_cast<VideoFrameMetadata::Key>(i); + expected.SetInteger(key, i); + } + + base::DictionaryValue tmp; + expected.MergeInternalValuesInto(&tmp); + EXPECT_EQ(static_cast<size_t>(VideoFrameMetadata::NUM_KEYS), tmp.size()); + + VideoFrameMetadata result; + result.MergeInternalValuesFrom(tmp); + + for (int i = 0; i < VideoFrameMetadata::NUM_KEYS; ++i) { + const VideoFrameMetadata::Key key = static_cast<VideoFrameMetadata::Key>(i); + int value = -1; + EXPECT_TRUE(result.GetInteger(key, &value)); + EXPECT_EQ(i, value); + } +} + } // namespace media
diff --git a/media/base/video_renderer.h b/media/base/video_renderer.h index 1e44333..7a764b3 100644 --- a/media/base/video_renderer.h +++ b/media/base/video_renderer.h
@@ -53,15 +53,20 @@ // |error_cb| is executed if an error was encountered after initialization. // // |get_time_cb| is used to query the current media playback time. - virtual void Initialize(DemuxerStream* stream, - const PipelineStatusCB& init_cb, - const SetDecryptorReadyCB& set_decryptor_ready_cb, - const StatisticsCB& statistics_cb, - const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, - const base::Closure& ended_cb, - const PipelineStatusCB& error_cb, - const TimeDeltaCB& get_time_cb) = 0; + // + // |waiting_for_decryption_key_cb| is executed whenever the key needed to + // decrypt the stream is not available. + virtual void Initialize( + DemuxerStream* stream, + const PipelineStatusCB& init_cb, + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const StatisticsCB& statistics_cb, + const BufferingStateCB& buffering_state_cb, + const PaintCB& paint_cb, + const base::Closure& ended_cb, + const PipelineStatusCB& error_cb, + const TimeDeltaCB& get_time_cb, + const base::Closure& waiting_for_decryption_key_cb) = 0; // Discards any video data and stops reading from |stream|, executing // |callback| when completed.
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn index bb52f5e..33d26d5 100644 --- a/media/blink/BUILD.gn +++ b/media/blink/BUILD.gn
@@ -83,7 +83,7 @@ } } -if (!is_mac && (!is_win || link_chrome_on_windows)) { +if (!is_mac) { # TODO(GYP): Make linking this work on the mac. test("media_blink_unittests") { deps = [
diff --git a/media/blink/webencryptedmediaclient_impl.cc b/media/blink/webencryptedmediaclient_impl.cc index 2dd051e..b1bd0d7 100644 --- a/media/blink/webencryptedmediaclient_impl.cc +++ b/media/blink/webencryptedmediaclient_impl.cc
@@ -25,12 +25,6 @@ const char kKeySystemSupportUMAPrefix[] = "Media.EME.RequestMediaKeySystemAccess."; -// TODO(jrummell): Convert to an enum. http://crbug.com/418239 -const char kTemporarySessionType[] = "temporary"; -const char kPersistentLicenseSessionType[] = "persistent-license"; -const char kPersistentReleaseMessageSessionType[] = - "persistent-release-message"; - enum ConfigurationSupport { CONFIGURATION_NOT_SUPPORTED, CONFIGURATION_REQUIRES_PERMISSION, @@ -151,23 +145,41 @@ // 1. Let accumulated configuration be empty. (Done by caller.) // 2. If candidate configuration's initDataTypes attribute is not empty, run // the following steps: - if (!candidate.initDataTypes.isEmpty()) { + blink::WebVector<blink::WebEncryptedMediaInitDataType> init_data_types = + candidate.getInitDataTypes(); + if (!init_data_types.isEmpty()) { // 2.1. Let supported types be empty. - std::vector<blink::WebString> supported_types; + std::vector<blink::WebEncryptedMediaInitDataType> supported_types; // 2.2. For each value in candidate configuration's initDataTypes attribute: - for (size_t i = 0; i < candidate.initDataTypes.size(); i++) { + for (size_t i = 0; i < init_data_types.size(); i++) { // 2.2.1. Let initDataType be the value. - const blink::WebString& init_data_type = candidate.initDataTypes[i]; + blink::WebEncryptedMediaInitDataType init_data_type = init_data_types[i]; // 2.2.2. If initDataType is the empty string, return null. - if (init_data_type.isEmpty()) - return CONFIGURATION_NOT_SUPPORTED; + if (init_data_type == blink::WebEncryptedMediaInitDataType::Unknown) + continue; // 2.2.3. If the implementation supports generating requests based on // initDataType, add initDataType to supported types. String // comparison is case-sensitive. - if (base::IsStringASCII(init_data_type) && - IsSupportedKeySystemWithInitDataType( - key_system, base::UTF16ToASCII(init_data_type))) { + // TODO(jrummell): |init_data_type| should be an enum all the way through + // Chromium. http://crbug.com/417440 + std::string init_data_type_as_ascii = "unknown"; + switch (init_data_type) { + case blink::WebEncryptedMediaInitDataType::Cenc: + init_data_type_as_ascii = "cenc"; + break; + case blink::WebEncryptedMediaInitDataType::Keyids: + init_data_type_as_ascii = "keyids"; + break; + case blink::WebEncryptedMediaInitDataType::Webm: + init_data_type_as_ascii = "webm"; + break; + case blink::WebEncryptedMediaInitDataType::Unknown: + NOTREACHED(); + break; + } + if (IsSupportedKeySystemWithInitDataType(key_system, + init_data_type_as_ascii)) { supported_types.push_back(init_data_type); } } @@ -177,7 +189,7 @@ return CONFIGURATION_NOT_SUPPORTED; // 2.4. Add supported types to accumulated configuration. - accumulated_configuration->initDataTypes = supported_types; + accumulated_configuration->setInitDataTypes(supported_types); } // 3. Follow the steps for the value of candidate configuration's @@ -329,20 +341,22 @@ // 12. Return accumulated configuration. // (As an extra step, we record the available session types so that // createSession() can be synchronous.) - std::vector<blink::WebString> session_types; - session_types.push_back(kTemporarySessionType); + std::vector<blink::WebEncryptedMediaSessionType> session_types; + session_types.push_back(blink::WebEncryptedMediaSessionType::Temporary); if (accumulated_configuration->persistentState == blink::WebMediaKeySystemConfiguration::Requirement::Required) { if (IsPersistentLicenseSessionSupported(key_system, is_permission_granted)) { - session_types.push_back(kPersistentLicenseSessionType); + session_types.push_back( + blink::WebEncryptedMediaSessionType::PersistentLicense); } if (IsPersistentReleaseMessageSessionSupported(key_system, is_permission_granted)) { - session_types.push_back(kPersistentReleaseMessageSessionType); + session_types.push_back( + blink::WebEncryptedMediaSessionType::PersistentReleaseMessage); } } - accumulated_configuration->sessionTypes = session_types; + accumulated_configuration->setSessionTypes(session_types); return CONFIGURATION_SUPPORTED; }
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index a7a7201..148daf61 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -692,6 +692,15 @@ base::saturated_cast<unsigned int>(init_data.size())); } +void WebMediaPlayerImpl::OnWaitingForDecryptionKey() { + client_->didBlockPlaybackWaitingForKey(); + + // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called + // when a key has been successfully added (e.g. OnSessionKeysChange() with + // |has_additional_usable_key| = true). http://crbug.com/461903 + client_->didResumePlaybackBlockedForKey(); +} + void WebMediaPlayerImpl::SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb) { pipeline_.SetCdm(cdm_context, cdm_attached_cb); @@ -903,7 +912,8 @@ BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged), base::Bind(&WebMediaPlayerImpl::FrameReady, base::Unretained(this)), BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged), - BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack)); + BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack), + BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey)); } void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h index acfdf97..0dc60db 100644 --- a/media/blink/webmediaplayer_impl.h +++ b/media/blink/webmediaplayer_impl.h
@@ -212,6 +212,10 @@ void OnEncryptedMediaInitData(const std::string& init_data_type, const std::vector<uint8>& init_data); + // Called when a decoder detects that the key needed to decrypt the stream + // is not available. + void OnWaitingForDecryptionKey(); + void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb); // Called when a CDM has been attached to the |pipeline_|.
diff --git a/media/cast/sender/video_encoder.cc b/media/cast/sender/video_encoder.cc index d65bf3c..d23496b 100644 --- a/media/cast/sender/video_encoder.cc +++ b/media/cast/sender/video_encoder.cc
@@ -34,8 +34,8 @@ } #endif // defined(OS_MACOSX) - // If the system provides a hardware-accelerated encoder, use it. #if !defined(OS_IOS) + // If the system provides a hardware-accelerated encoder, use it. if (ExternalVideoEncoder::IsSupported(video_config)) { return scoped_ptr<VideoEncoder>(new SizeAdaptableExternalVideoEncoder( cast_environment, @@ -44,7 +44,6 @@ create_vea_cb, create_video_encode_memory_cb)); } -#endif // !defined(OS_IOS) // Attempt to use the software encoder implementation. if (VideoEncoderImpl::IsSupported(video_config)) { @@ -53,6 +52,7 @@ video_config, status_change_cb)); } +#endif // !defined(OS_IOS) // No encoder implementation will suffice. return nullptr;
diff --git a/media/cast/sender/video_sender.cc b/media/cast/sender/video_sender.cc index 2389e9f..e4e3a45 100644 --- a/media/cast/sender/video_sender.cc +++ b/media/cast/sender/video_sender.cc
@@ -30,6 +30,30 @@ // time). const int kConstantTimeMs = 75; +// Extract capture begin/end timestamps from |video_frame|'s metadata and log +// it. +void LogVideoCaptureTimestamps(const CastEnvironment& cast_environment, + const media::VideoFrame& video_frame, + RtpTimestamp rtp_timestamp) { + base::TimeTicks capture_begin_time; + base::TimeTicks capture_end_time; + if (!video_frame.metadata()->GetTimeTicks( + media::VideoFrameMetadata::CAPTURE_BEGIN_TIME, &capture_begin_time) || + !video_frame.metadata()->GetTimeTicks( + media::VideoFrameMetadata::CAPTURE_END_TIME, &capture_end_time)) { + // The frame capture timestamps were not provided by the video capture + // source. Simply log the events as happening right now. + capture_begin_time = capture_end_time = + cast_environment.Clock()->NowTicks(); + } + cast_environment.Logging()->InsertFrameEvent( + capture_begin_time, FRAME_CAPTURE_BEGIN, VIDEO_EVENT, rtp_timestamp, + kFrameIdUnknown); + cast_environment.Logging()->InsertFrameEvent( + capture_end_time, FRAME_CAPTURE_END, VIDEO_EVENT, rtp_timestamp, + kFrameIdUnknown); +} + } // namespace // Note, we use a fixed bitrate value when external video encoder is used. @@ -108,15 +132,7 @@ const RtpTimestamp rtp_timestamp = TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency); - const base::TimeTicks insertion_time = cast_environment_->Clock()->NowTicks(); - // TODO(miu): Plumb in capture timestamps. For now, make it look like capture - // took zero time by setting the BEGIN and END event to the same timestamp. - cast_environment_->Logging()->InsertFrameEvent( - insertion_time, FRAME_CAPTURE_BEGIN, VIDEO_EVENT, rtp_timestamp, - kFrameIdUnknown); - cast_environment_->Logging()->InsertFrameEvent( - insertion_time, FRAME_CAPTURE_END, VIDEO_EVENT, rtp_timestamp, - kFrameIdUnknown); + LogVideoCaptureTimestamps(*cast_environment_, *video_frame, rtp_timestamp); // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc TRACE_EVENT_INSTANT2(
diff --git a/media/cast/sender/vp8_encoder.cc b/media/cast/sender/vp8_encoder.cc index fae960e..4d397b6 100644 --- a/media/cast/sender/vp8_encoder.cc +++ b/media/cast/sender/vp8_encoder.cc
@@ -80,9 +80,10 @@ << frame_size.ToString(); config_.g_w = frame_size.width(); config_.g_h = frame_size.height(); - CHECK_EQ(vpx_codec_enc_config_set(&encoder_, &config_), VPX_CODEC_OK) - << "Failed to update frame size in encoder config."; - return; + if (vpx_codec_enc_config_set(&encoder_, &config_) == VPX_CODEC_OK) + return; + DVLOG(1) << "libvpx rejected the attempt to use a smaller frame size in " + "the current instance."; } DVLOG(1) << "Destroying/Re-Creating encoder for larger frame size: "
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc index 1bf574d..1506f7f 100644 --- a/media/cdm/aes_decryptor.cc +++ b/media/cdm/aes_decryptor.cc
@@ -273,8 +273,15 @@ promise->reject(NOT_SUPPORTED_ERROR, 0, "No supported PSSH box found."); return; } + } else if (init_data_type == "keyids") { + std::string init_data_string(init_data, init_data + init_data_length); + std::string error_message; + if (!ExtractKeyIdsFromKeyIdsInitData(init_data_string, &keys, + &error_message)) { + promise->reject(NOT_SUPPORTED_ERROR, 0, error_message); + return; + } } else { - // TODO(jrummell): Support init_data_type == "keyids". promise->reject(NOT_SUPPORTED_ERROR, 0, "init_data_type not supported."); return; }
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc index ce06fe2..8ca3940851 100644 --- a/media/cdm/aes_decryptor_unittest.cc +++ b/media/cdm/aes_decryptor_unittest.cc
@@ -252,7 +252,8 @@ MediaKeys::Exception exception_code, uint32 system_code, const std::string& error_message) { - EXPECT_EQ(expected_result, REJECTED) << "Unexpectedly rejected."; + EXPECT_EQ(expected_result, REJECTED) + << "Unexpectedly rejected with message: " << error_message; } scoped_ptr<SimpleCdmPromise> CreatePromise(PromiseResult expected_result) { @@ -454,6 +455,40 @@ CreateSessionPromise(RESOLVED)); } +TEST_F(AesDecryptorTest, CreateSessionWithCencInitData) { + const uint8 init_data[] = { + 0x00, 0x00, 0x00, 0x44, // size = 68 + 0x70, 0x73, 0x73, 0x68, // 'pssh' + 0x01, // version + 0x00, 0x00, 0x00, // flags + 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02, // SystemID + 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B, + 0x00, 0x00, 0x00, 0x02, // key count + 0x7E, 0x57, 0x1D, 0x03, 0x7E, 0x57, 0x1D, 0x03, // key1 + 0x7E, 0x57, 0x1D, 0x03, 0x7E, 0x57, 0x1D, 0x03, + 0x7E, 0x57, 0x1D, 0x04, 0x7E, 0x57, 0x1D, 0x04, // key2 + 0x7E, 0x57, 0x1D, 0x04, 0x7E, 0x57, 0x1D, 0x04, + 0x00, 0x00, 0x00, 0x00 // datasize + }; + EXPECT_CALL(*this, OnSessionMessage(IsNotEmpty(), _, IsJSONDictionary(), + GURL::EmptyGURL())); + decryptor_.CreateSessionAndGenerateRequest( + MediaKeys::TEMPORARY_SESSION, "cenc", init_data, arraysize(init_data), + CreateSessionPromise(RESOLVED)); +} + +TEST_F(AesDecryptorTest, CreateSessionWithKeyIdsInitData) { + const char init_data[] = + "{\"kids\":[\"AQI\",\"AQIDBA\",\"AQIDBAUGBwgJCgsMDQ4PEA\"]}"; + + EXPECT_CALL(*this, OnSessionMessage(IsNotEmpty(), _, IsJSONDictionary(), + GURL::EmptyGURL())); + decryptor_.CreateSessionAndGenerateRequest( + MediaKeys::TEMPORARY_SESSION, "keyids", + reinterpret_cast<const uint8*>(init_data), arraysize(init_data) - 1, + CreateSessionPromise(RESOLVED)); +} + TEST_F(AesDecryptorTest, NormalDecryption) { std::string session_id = CreateSession(key_id_); UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
diff --git a/media/cdm/json_web_key.cc b/media/cdm/json_web_key.cc index cd50a8c..21df8377 100644 --- a/media/cdm/json_web_key.cc +++ b/media/cdm/json_web_key.cc
@@ -10,6 +10,7 @@ #include "base/json/string_escape.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/values.h" @@ -88,6 +89,21 @@ return decoded_text; } +static std::string ShortenTo64Characters(const std::string& input) { + // Convert |input| into a string with escaped characters replacing any + // non-ASCII characters. Limiting |input| to the first 65 characters so + // we don't waste time converting a potentially long string and then + // throwing away the excess. + std::string escaped_str = + base::EscapeBytesAsInvalidJSONString(input.substr(0, 65), false); + if (escaped_str.length() <= 64u) + return escaped_str; + + // This may end up truncating an escaped character, but the first part of + // the string should provide enough information. + return escaped_str.substr(0, 61).append("..."); +} + std::string GenerateJWKSet(const uint8* key, int key_length, const uint8* key_id, int key_id_length) { // Both |key| and |key_id| need to be base64 encoded strings in the JWK. @@ -226,6 +242,70 @@ return true; } +bool ExtractKeyIdsFromKeyIdsInitData(const std::string& input, + KeyIdList* key_ids, + std::string* error_message) { + if (!base::IsStringASCII(input)) { + error_message->assign("Non ASCII: "); + error_message->append(ShortenTo64Characters(input)); + return false; + } + + scoped_ptr<base::Value> root(base::JSONReader().ReadToValue(input)); + if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY) { + error_message->assign("Not valid JSON: "); + error_message->append(ShortenTo64Characters(input)); + return false; + } + + // Locate the set from the dictionary. + base::DictionaryValue* dictionary = + static_cast<base::DictionaryValue*>(root.get()); + base::ListValue* list_val = NULL; + if (!dictionary->GetList(kKeyIdsTag, &list_val)) { + error_message->assign("Missing '"); + error_message->append(kKeyIdsTag); + error_message->append("' parameter or not a list"); + return false; + } + + // Create a local list of key ids, so that |key_ids| only gets updated on + // success. + KeyIdList local_key_ids; + for (size_t i = 0; i < list_val->GetSize(); ++i) { + std::string encoded_key_id; + if (!list_val->GetString(i, &encoded_key_id)) { + error_message->assign("'"); + error_message->append(kKeyIdsTag); + error_message->append("'["); + error_message->append(base::UintToString(i)); + error_message->append("] is not string."); + return false; + } + + // Key ID is a base64-encoded string, so decode it. + std::string raw_key_id = DecodeBase64Url(encoded_key_id); + if (raw_key_id.empty()) { + error_message->assign("'"); + error_message->append(kKeyIdsTag); + error_message->append("'["); + error_message->append(base::UintToString(i)); + error_message->append("] is not valid base64url encoded. Value: "); + error_message->append(ShortenTo64Characters(encoded_key_id)); + return false; + } + + // Add the decoded key ID to the list. + local_key_ids.push_back(std::vector<uint8>( + raw_key_id.data(), raw_key_id.data() + raw_key_id.length())); + } + + // All done. + key_ids->swap(local_key_ids); + error_message->clear(); + return true; +} + void CreateLicenseRequest(const KeyIdList& key_ids, MediaKeys::SessionType session_type, std::vector<uint8>* license) {
diff --git a/media/cdm/json_web_key.h b/media/cdm/json_web_key.h index 2691b43e..7be4473 100644 --- a/media/cdm/json_web_key.h +++ b/media/cdm/json_web_key.h
@@ -67,6 +67,14 @@ KeyIdAndKeyPairs* keys, MediaKeys::SessionType* session_type); +// Extracts the Key Ids from a Key IDs Initialization Data +// (https://w3c.github.io/encrypted-media/keyids-format.html). If |input| looks +// valid, then true is returned and |key_ids| is updated to contain the values +// found. Otherwise return false and |error_message| contains the reason. +MEDIA_EXPORT bool ExtractKeyIdsFromKeyIdsInitData(const std::string& input, + KeyIdList* key_ids, + std::string* error_message); + // Creates a license request message for the |key_ids| and |session_type| // specified. |license| is updated to contain the resulting JSON string. MEDIA_EXPORT void CreateLicenseRequest(const KeyIdList& key_ids,
diff --git a/media/cdm/json_web_key_unittest.cc b/media/cdm/json_web_key_unittest.cc index 07d28c0..0cb251c 100644 --- a/media/cdm/json_web_key_unittest.cc +++ b/media/cdm/json_web_key_unittest.cc
@@ -60,11 +60,16 @@ std::vector<uint8> key; EXPECT_EQ(expected_result, ExtractFirstKeyIdFromLicenseRequest(license_vector, &key)); - if (expected_result) { - std::vector<uint8> key_result(expected_key, - expected_key + expected_key_length); - EXPECT_EQ(key_result, key); - } + if (expected_result) + VerifyKeyId(key, expected_key, expected_key_length); + } + + void VerifyKeyId(std::vector<uint8> key, + const uint8* expected_key, + int expected_key_length) { + std::vector<uint8> key_result(expected_key, + expected_key + expected_key_length); + EXPECT_EQ(key_result, key); } }; @@ -519,5 +524,83 @@ s); } +TEST_F(JSONWebKeyTest, ExtractKeyIds) { + const uint8 data1[] = { 0x01, 0x02 }; + const uint8 data2[] = { 0x01, 0x02, 0x03, 0x04 }; + const uint8 data3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }; + + KeyIdList key_ids; + std::string error_message; + + EXPECT_TRUE(ExtractKeyIdsFromKeyIdsInitData("{\"kids\":[\"AQI\"]}", &key_ids, + &error_message)); + EXPECT_EQ(1u, key_ids.size()); + EXPECT_EQ(0u, error_message.length()); + VerifyKeyId(key_ids[0], data1, arraysize(data1)); + + EXPECT_TRUE(ExtractKeyIdsFromKeyIdsInitData( + "{\"kids\":[\"AQI\",\"AQIDBA\",\"AQIDBAUGBwgJCgsMDQ4PEA\"]}", &key_ids, + &error_message)); + EXPECT_EQ(3u, key_ids.size()); + EXPECT_EQ(0u, error_message.length()); + VerifyKeyId(key_ids[0], data1, arraysize(data1)); + VerifyKeyId(key_ids[1], data2, arraysize(data2)); + VerifyKeyId(key_ids[2], data3, arraysize(data3)); + + // Expect failure when non-ascii. + EXPECT_FALSE(ExtractKeyIdsFromKeyIdsInitData( + "This is not ASCII due to \xff\xfe\x0a in it.", &key_ids, + &error_message)); + EXPECT_EQ(3u, key_ids.size()); // |key_ids| should be unchanged. + EXPECT_EQ(error_message, + "Non ASCII: This is not ASCII due to \\u00FF\\u00FE\\n in it."); + + // Expect failure when not JSON or not a dictionary. + EXPECT_FALSE(ExtractKeyIdsFromKeyIdsInitData("This is invalid.", &key_ids, + &error_message)); + EXPECT_EQ(3u, key_ids.size()); // |key_ids| should be unchanged. + EXPECT_EQ(error_message, "Not valid JSON: This is invalid."); + EXPECT_FALSE(ExtractKeyIdsFromKeyIdsInitData("6", &key_ids, &error_message)); + EXPECT_EQ(3u, key_ids.size()); // |key_ids| should be unchanged. + EXPECT_EQ(error_message, "Not valid JSON: 6"); + EXPECT_FALSE(ExtractKeyIdsFromKeyIdsInitData( + "This is a very long string that is longer than 64 characters and is " + "invalid.", + &key_ids, &error_message)); + EXPECT_EQ(3u, key_ids.size()); // |key_ids| should be unchanged. + EXPECT_EQ(error_message, + "Not valid JSON: This is a very long string that is longer than 64 " + "characters ..."); + + // Expect failure when "kids" not specified. + EXPECT_FALSE(ExtractKeyIdsFromKeyIdsInitData("{\"keys\":[\"AQI\"]}", &key_ids, + &error_message)); + EXPECT_EQ(3u, key_ids.size()); // |key_ids| should be unchanged. + EXPECT_EQ(error_message, "Missing 'kids' parameter or not a list"); + + // Expect failure when invalid key_ids specified. + EXPECT_FALSE(ExtractKeyIdsFromKeyIdsInitData("{\"kids\":[1]}", &key_ids, + &error_message)); + EXPECT_EQ(3u, key_ids.size()); // |key_ids| should be unchanged. + EXPECT_EQ(error_message, "'kids'[0] is not string."); + EXPECT_FALSE(ExtractKeyIdsFromKeyIdsInitData("{\"kids\": {\"id\":\"AQI\" }}", + &key_ids, &error_message)); + EXPECT_EQ(3u, key_ids.size()); // |key_ids| should be unchanged. + EXPECT_EQ(error_message, "Missing 'kids' parameter or not a list"); + + // Expect failure when non-base64 key_ids specified. + EXPECT_FALSE(ExtractKeyIdsFromKeyIdsInitData("{\"kids\":[\"AQI+\"]}", + &key_ids, &error_message)); + EXPECT_EQ(3u, key_ids.size()); // |key_ids| should be unchanged. + EXPECT_EQ(error_message, + "'kids'[0] is not valid base64url encoded. Value: AQI+"); + EXPECT_FALSE(ExtractKeyIdsFromKeyIdsInitData("{\"kids\":[\"AQI\",\"AQI/\"]}", + &key_ids, &error_message)); + EXPECT_EQ(3u, key_ids.size()); // |key_ids| should be unchanged. + EXPECT_EQ(error_message, + "'kids'[1] is not valid base64url encoded. Value: AQI/"); +} + } // namespace media
diff --git a/media/filters/audio_decoder_selector_unittest.cc b/media/filters/audio_decoder_selector_unittest.cc index 36f7ca64..2bb1f6d2 100644 --- a/media/filters/audio_decoder_selector_unittest.cc +++ b/media/filters/audio_decoder_selector_unittest.cc
@@ -135,7 +135,8 @@ base::Unretained(this)), base::Bind(&AudioDecoderSelectorTest::MockOnDecoderSelected, base::Unretained(this)), - base::Bind(&AudioDecoderSelectorTest::OnDecoderOutput)); + base::Bind(&AudioDecoderSelectorTest::OnDecoderOutput), + base::Bind(&AudioDecoderSelectorTest::OnWaitingForDecryptionKey)); message_loop_.RunUntilIdle(); } @@ -151,6 +152,10 @@ NOTREACHED(); } + static void OnWaitingForDecryptionKey() { + NOTREACHED(); + } + // Declare |decoder_selector_| after |demuxer_stream_| and |decryptor_| since // |demuxer_stream_| and |decryptor_| should outlive |decoder_selector_|. scoped_ptr<StrictMock<MockDemuxerStream> > demuxer_stream_;
diff --git a/media/filters/decoder_selector.cc b/media/filters/decoder_selector.cc index f026acd..555a411 100644 --- a/media/filters/decoder_selector.cc +++ b/media/filters/decoder_selector.cc
@@ -75,13 +75,15 @@ DemuxerStream* stream, const SetDecryptorReadyCB& set_decryptor_ready_cb, const SelectDecoderCB& select_decoder_cb, - const typename Decoder::OutputCB& output_cb) { + const typename Decoder::OutputCB& output_cb, + const base::Closure& waiting_for_decryption_key_cb) { DVLOG(2) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(stream); DCHECK(select_decoder_cb_.is_null()); set_decryptor_ready_cb_ = set_decryptor_ready_cb; + waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; // Make sure |select_decoder_cb| runs on a different execution stack. select_decoder_cb_ = BindToCurrentLoop(select_decoder_cb); @@ -107,7 +109,7 @@ } decoder_.reset(new typename StreamTraits::DecryptingDecoderType( - task_runner_, set_decryptor_ready_cb_)); + task_runner_, set_decryptor_ready_cb_, waiting_for_decryption_key_cb_)); DecoderStreamTraits<StreamType>::InitializeDecoder( decoder_.get(), input_stream_, @@ -130,8 +132,8 @@ decoder_.reset(); - decrypted_stream_.reset( - new DecryptingDemuxerStream(task_runner_, set_decryptor_ready_cb_)); + decrypted_stream_.reset(new DecryptingDemuxerStream( + task_runner_, set_decryptor_ready_cb_, waiting_for_decryption_key_cb_)); decrypted_stream_->Initialize( input_stream_,
diff --git a/media/filters/decoder_selector.h b/media/filters/decoder_selector.h index d13eb9b..59c90f57 100644 --- a/media/filters/decoder_selector.h +++ b/media/filters/decoder_selector.h
@@ -70,7 +70,8 @@ void SelectDecoder(DemuxerStream* stream, const SetDecryptorReadyCB& set_decryptor_ready_cb, const SelectDecoderCB& select_decoder_cb, - const typename Decoder::OutputCB& output_cb); + const typename Decoder::OutputCB& output_cb, + const base::Closure& waiting_for_decryption_key_cb); private: void DecryptingDecoderInitDone(PipelineStatus status); @@ -86,6 +87,7 @@ SetDecryptorReadyCB set_decryptor_ready_cb_; SelectDecoderCB select_decoder_cb_; typename Decoder::OutputCB output_cb_; + base::Closure waiting_for_decryption_key_cb_; scoped_ptr<Decoder> decoder_; scoped_ptr<DecryptingDemuxerStream> decrypted_stream_;
diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc index f9fa8b2..3a366d8 100644 --- a/media/filters/decoder_stream.cc +++ b/media/filters/decoder_stream.cc
@@ -83,7 +83,8 @@ DemuxerStream* stream, const InitCB& init_cb, const SetDecryptorReadyCB& set_decryptor_ready_cb, - const StatisticsCB& statistics_cb) { + const StatisticsCB& statistics_cb, + const base::Closure& waiting_for_decryption_key_cb) { FUNCTION_DVLOG(2); DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK_EQ(state_, STATE_UNINITIALIZED); @@ -92,6 +93,7 @@ statistics_cb_ = statistics_cb; init_cb_ = init_cb; + waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; stream_ = stream; state_ = STATE_INITIALIZING; @@ -212,7 +214,8 @@ base::Bind(&DecoderStream<StreamType>::OnDecoderSelected, weak_factory_.GetWeakPtr()), base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady, - weak_factory_.GetWeakPtr())); + weak_factory_.GetWeakPtr()), + waiting_for_decryption_key_cb_); } template <DemuxerStream::Type StreamType>
diff --git a/media/filters/decoder_stream.h b/media/filters/decoder_stream.h index b8a0d04..3c0e23ef 100644 --- a/media/filters/decoder_stream.h +++ b/media/filters/decoder_stream.h
@@ -61,7 +61,8 @@ void Initialize(DemuxerStream* stream, const InitCB& init_cb, const SetDecryptorReadyCB& set_decryptor_ready_cb, - const StatisticsCB& statistics_cb); + const StatisticsCB& statistics_cb, + const base::Closure& waiting_for_decryption_key_cb); // Reads a decoded Output and returns it via the |read_cb|. Note that // |read_cb| is always called asynchronously. This method should only be @@ -170,6 +171,7 @@ StatisticsCB statistics_cb_; InitCB init_cb_; + base::Closure waiting_for_decryption_key_cb_; ReadCB read_cb_; base::Closure reset_cb_;
diff --git a/media/filters/decrypting_audio_decoder.cc b/media/filters/decrypting_audio_decoder.cc index 0ca20f7..3425d0c2 100644 --- a/media/filters/decrypting_audio_decoder.cc +++ b/media/filters/decrypting_audio_decoder.cc
@@ -34,13 +34,16 @@ DecryptingAudioDecoder::DecryptingAudioDecoder( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - const SetDecryptorReadyCB& set_decryptor_ready_cb) + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const base::Closure& waiting_for_decryption_key_cb) : task_runner_(task_runner), state_(kUninitialized), + waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb), set_decryptor_ready_cb_(set_decryptor_ready_cb), decryptor_(NULL), key_added_while_decode_pending_(false), - weak_factory_(this) {} + weak_factory_(this) { +} std::string DecryptingAudioDecoder::GetDisplayName() const { return "DecryptingAudioDecoder"; @@ -288,6 +291,7 @@ } state_ = kWaitingForKey; + waiting_for_decryption_key_cb_.Run(); return; }
diff --git a/media/filters/decrypting_audio_decoder.h b/media/filters/decrypting_audio_decoder.h index 67da6c0..30b0a63 100644 --- a/media/filters/decrypting_audio_decoder.h +++ b/media/filters/decrypting_audio_decoder.h
@@ -32,7 +32,8 @@ public: DecryptingAudioDecoder( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - const SetDecryptorReadyCB& set_decryptor_ready_cb); + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const base::Closure& waiting_for_decryption_key_cb); ~DecryptingAudioDecoder() override; // AudioDecoder implementation. @@ -96,6 +97,7 @@ OutputCB output_cb_; DecodeCB decode_cb_; base::Closure reset_cb_; + base::Closure waiting_for_decryption_key_cb_; // The current decoder configuration. AudioDecoderConfig config_;
diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc index 49df3ce..1f8395bf 100644 --- a/media/filters/decrypting_audio_decoder_unittest.cc +++ b/media/filters/decrypting_audio_decoder_unittest.cc
@@ -63,7 +63,9 @@ message_loop_.message_loop_proxy(), base::Bind( &DecryptingAudioDecoderTest::RequestDecryptorNotification, - base::Unretained(this)))), + base::Unretained(this)), + base::Bind(&DecryptingAudioDecoderTest::OnWaitingForDecryptionKey, + base::Unretained(this)))), decryptor_(new StrictMock<MockDecryptor>()), num_decrypt_and_decode_calls_(0), num_frames_in_decryptor_(0), @@ -204,6 +206,7 @@ EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(encrypted_buffer_, _)) .WillRepeatedly(RunCallback<1>(Decryptor::kNoKey, Decryptor::AudioFrames())); + EXPECT_CALL(*this, OnWaitingForDecryptionKey()); decoder_->Decode(encrypted_buffer_, base::Bind(&DecryptingAudioDecoderTest::DecodeDone, base::Unretained(this))); @@ -252,6 +255,8 @@ MOCK_METHOD1(DecryptorSet, void(bool)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); + base::MessageLoop message_loop_; scoped_ptr<DecryptingAudioDecoder> decoder_; scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc index 601fd46..7a6f43c 100644 --- a/media/filters/decrypting_demuxer_stream.cc +++ b/media/filters/decrypting_demuxer_stream.cc
@@ -30,14 +30,17 @@ DecryptingDemuxerStream::DecryptingDemuxerStream( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - const SetDecryptorReadyCB& set_decryptor_ready_cb) + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const base::Closure& waiting_for_decryption_key_cb) : task_runner_(task_runner), state_(kUninitialized), + waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb), demuxer_stream_(NULL), set_decryptor_ready_cb_(set_decryptor_ready_cb), decryptor_(NULL), key_added_while_decrypt_pending_(false), - weak_factory_(this) {} + weak_factory_(this) { +} void DecryptingDemuxerStream::Initialize(DemuxerStream* stream, const PipelineStatusCB& status_cb) { @@ -311,6 +314,7 @@ } state_ = kWaitingForKey; + waiting_for_decryption_key_cb_.Run(); return; }
diff --git a/media/filters/decrypting_demuxer_stream.h b/media/filters/decrypting_demuxer_stream.h index f66f9ab7..e8d82224 100644 --- a/media/filters/decrypting_demuxer_stream.h +++ b/media/filters/decrypting_demuxer_stream.h
@@ -30,7 +30,8 @@ public: DecryptingDemuxerStream( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - const SetDecryptorReadyCB& set_decryptor_ready_cb); + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const base::Closure& waiting_for_decryption_key_cb); // Cancels all pending operations immediately and fires all pending callbacks. ~DecryptingDemuxerStream() override; @@ -104,6 +105,7 @@ PipelineStatusCB init_cb_; ReadCB read_cb_; base::Closure reset_cb_; + base::Closure waiting_for_decryption_key_cb_; // Pointer to the input demuxer stream that will feed us encrypted buffers. DemuxerStream* demuxer_stream_;
diff --git a/media/filters/decrypting_demuxer_stream_unittest.cc b/media/filters/decrypting_demuxer_stream_unittest.cc index fa2a36c..3cba1f7 100644 --- a/media/filters/decrypting_demuxer_stream_unittest.cc +++ b/media/filters/decrypting_demuxer_stream_unittest.cc
@@ -77,7 +77,9 @@ message_loop_.message_loop_proxy(), base::Bind( &DecryptingDemuxerStreamTest::RequestDecryptorNotification, - base::Unretained(this)))), + base::Unretained(this)), + base::Bind(&DecryptingDemuxerStreamTest::OnWaitingForDecryptionKey, + base::Unretained(this)))), decryptor_(new StrictMock<MockDecryptor>()), is_decryptor_set_(false), input_audio_stream_( @@ -225,6 +227,7 @@ EXPECT_CALL(*decryptor_, Decrypt(_, encrypted_buffer_, _)) .WillRepeatedly(RunCallback<2>(Decryptor::kNoKey, scoped_refptr<DecoderBuffer>())); + EXPECT_CALL(*this, OnWaitingForDecryptionKey()); demuxer_stream_->Read(base::Bind(&DecryptingDemuxerStreamTest::BufferReady, base::Unretained(this))); message_loop_.RunUntilIdle(); @@ -260,6 +263,8 @@ MOCK_METHOD1(DecryptorSet, void(bool)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); + base::MessageLoop message_loop_; scoped_ptr<DecryptingDemuxerStream> demuxer_stream_; scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
diff --git a/media/filters/decrypting_video_decoder.cc b/media/filters/decrypting_video_decoder.cc index f4aa375..d9bba50 100644 --- a/media/filters/decrypting_video_decoder.cc +++ b/media/filters/decrypting_video_decoder.cc
@@ -23,14 +23,17 @@ DecryptingVideoDecoder::DecryptingVideoDecoder( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - const SetDecryptorReadyCB& set_decryptor_ready_cb) + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const base::Closure& waiting_for_decryption_key_cb) : task_runner_(task_runner), state_(kUninitialized), + waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb), set_decryptor_ready_cb_(set_decryptor_ready_cb), decryptor_(NULL), key_added_while_decode_pending_(false), trace_id_(0), - weak_factory_(this) {} + weak_factory_(this) { +} std::string DecryptingVideoDecoder::GetDisplayName() const { return kDecoderName; @@ -270,6 +273,7 @@ } state_ = kWaitingForKey; + waiting_for_decryption_key_cb_.Run(); return; }
diff --git a/media/filters/decrypting_video_decoder.h b/media/filters/decrypting_video_decoder.h index 8e40502..a2a9528 100644 --- a/media/filters/decrypting_video_decoder.h +++ b/media/filters/decrypting_video_decoder.h
@@ -28,7 +28,8 @@ public: DecryptingVideoDecoder( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - const SetDecryptorReadyCB& set_decryptor_ready_cb); + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const base::Closure& waiting_for_decryption_key_cb); ~DecryptingVideoDecoder() override; // VideoDecoder implementation. @@ -88,6 +89,7 @@ OutputCB output_cb_; DecodeCB decode_cb_; base::Closure reset_cb_; + base::Closure waiting_for_decryption_key_cb_; VideoDecoderConfig config_;
diff --git a/media/filters/decrypting_video_decoder_unittest.cc b/media/filters/decrypting_video_decoder_unittest.cc index 11dc52a..285bab67 100644 --- a/media/filters/decrypting_video_decoder_unittest.cc +++ b/media/filters/decrypting_video_decoder_unittest.cc
@@ -57,7 +57,9 @@ message_loop_.message_loop_proxy(), base::Bind( &DecryptingVideoDecoderTest::RequestDecryptorNotification, - base::Unretained(this)))), + base::Unretained(this)), + base::Bind(&DecryptingVideoDecoderTest::OnWaitingForDecryptionKey, + base::Unretained(this)))), decryptor_(new StrictMock<MockDecryptor>()), num_decrypt_and_decode_calls_(0), num_frames_in_decryptor_(0), @@ -179,6 +181,7 @@ void EnterWaitingForKeyState() { EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(_, _)) .WillRepeatedly(RunCallback<1>(Decryptor::kNoKey, null_video_frame_)); + EXPECT_CALL(*this, OnWaitingForDecryptionKey()); decoder_->Decode(encrypted_buffer_, base::Bind(&DecryptingVideoDecoderTest::DecodeDone, base::Unretained(this))); @@ -227,6 +230,8 @@ MOCK_METHOD1(DecryptorSet, void(bool)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); + base::MessageLoop message_loop_; scoped_ptr<DecryptingVideoDecoder> decoder_; scoped_ptr<StrictMock<MockDecryptor> > decryptor_; @@ -263,6 +268,7 @@ .WillRepeatedly(RunCallback<1>(false)); EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kVideo, _)) .WillRepeatedly(SaveArg<1>(&key_added_cb_)); + EXPECT_CALL(*this, RequestDecryptorNotification(_)).Times(2); InitializeAndExpectStatus(TestVideoConfig::NormalEncrypted(), DECODER_ERROR_NOT_SUPPORTED); @@ -333,7 +339,7 @@ // Test the case where the a key is added when the decryptor is in // kPendingDecode state. -TEST_F(DecryptingVideoDecoderTest, KeyAdded_DruingPendingDecode) { +TEST_F(DecryptingVideoDecoderTest, KeyAdded_DuringPendingDecode) { Initialize(); EnterPendingDecodeState();
diff --git a/media/filters/gpu_video_accelerator_factories.cc b/media/filters/gpu_video_accelerator_factories.cc deleted file mode 100644 index f9f5660..0000000 --- a/media/filters/gpu_video_accelerator_factories.cc +++ /dev/null
@@ -1,11 +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. - -#include "media/filters/gpu_video_accelerator_factories.h" - -namespace media { - -GpuVideoAcceleratorFactories::~GpuVideoAcceleratorFactories() {} - -} // namespace media
diff --git a/media/filters/gpu_video_accelerator_factories.h b/media/filters/gpu_video_accelerator_factories.h deleted file mode 100644 index 03494d0..0000000 --- a/media/filters/gpu_video_accelerator_factories.h +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_FILTERS_GPU_VIDEO_ACCELERATOR_FACTORIES_H_ -#define MEDIA_FILTERS_GPU_VIDEO_ACCELERATOR_FACTORIES_H_ - -#include <vector> - -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "gpu/command_buffer/common/mailbox.h" -#include "media/base/media_export.h" -#include "media/video/video_encode_accelerator.h" - -namespace base { -class SingleThreadTaskRunner; -class SharedMemory; -} - -namespace gfx { -class Rect; -class Size; -} - -namespace media { - -class VideoDecodeAccelerator; - -// Helper interface for specifying factories needed to instantiate a hardware -// video accelerator. -// Threading model: -// * The GpuVideoAcceleratorFactories may be constructed on any thread. -// * The GpuVideoAcceleratorFactories has an associated message loop, which may -// be retrieved as |GetMessageLoop()|. -// * All calls to the Factories after construction must be made on its message -// loop. -class MEDIA_EXPORT GpuVideoAcceleratorFactories - : public base::RefCountedThreadSafe<GpuVideoAcceleratorFactories> { - public: - // Caller owns returned pointer, but should call Destroy() on it (instead of - // directly deleting) for proper destruction, as per the - // VideoDecodeAccelerator interface. - virtual scoped_ptr<VideoDecodeAccelerator> CreateVideoDecodeAccelerator() = 0; - - // Caller owns returned pointer, but should call Destroy() on it (instead of - // directly deleting) for proper destruction, as per the - // VideoEncodeAccelerator interface. - virtual scoped_ptr<VideoEncodeAccelerator> CreateVideoEncodeAccelerator() = 0; - - // Allocate & delete native textures. - virtual bool CreateTextures(int32 count, - const gfx::Size& size, - std::vector<uint32>* texture_ids, - std::vector<gpu::Mailbox>* texture_mailboxes, - uint32 texture_target) = 0; - virtual void DeleteTexture(uint32 texture_id) = 0; - - virtual void WaitSyncPoint(uint32 sync_point) = 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; - - // Returns the supported codec profiles of video encode accelerator. - virtual std::vector<VideoEncodeAccelerator::SupportedProfile> - GetVideoEncodeAcceleratorSupportedProfiles() = 0; - - protected: - friend class base::RefCountedThreadSafe<GpuVideoAcceleratorFactories>; - virtual ~GpuVideoAcceleratorFactories(); -}; - -} // namespace media - -#endif // MEDIA_FILTERS_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc index b634a5c..703cb20 100644 --- a/media/filters/gpu_video_decoder.cc +++ b/media/filters/gpu_video_decoder.cc
@@ -21,7 +21,7 @@ #include "media/base/pipeline.h" #include "media/base/pipeline_status.h" #include "media/base/video_decoder_config.h" -#include "media/filters/gpu_video_accelerator_factories.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "third_party/skia/include/core/SkBitmap.h" namespace media {
diff --git a/media/filters/mock_gpu_video_accelerator_factories.cc b/media/filters/mock_gpu_video_accelerator_factories.cc deleted file mode 100644 index 1c4465a..0000000 --- a/media/filters/mock_gpu_video_accelerator_factories.cc +++ /dev/null
@@ -1,28 +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. - -#include "media/filters/mock_gpu_video_accelerator_factories.h" - -namespace media { - -MockGpuVideoAcceleratorFactories::MockGpuVideoAcceleratorFactories() {} - -MockGpuVideoAcceleratorFactories::~MockGpuVideoAcceleratorFactories() {} - -scoped_ptr<base::SharedMemory> -MockGpuVideoAcceleratorFactories::CreateSharedMemory(size_t size) { - return nullptr; -} - -scoped_ptr<VideoDecodeAccelerator> -MockGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator() { - return scoped_ptr<VideoDecodeAccelerator>(DoCreateVideoDecodeAccelerator()); -} - -scoped_ptr<VideoEncodeAccelerator> -MockGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator() { - return scoped_ptr<VideoEncodeAccelerator>(DoCreateVideoEncodeAccelerator()); -} - -} // namespace media
diff --git a/media/filters/mock_gpu_video_accelerator_factories.h b/media/filters/mock_gpu_video_accelerator_factories.h deleted file mode 100644 index 7e14939..0000000 --- a/media/filters/mock_gpu_video_accelerator_factories.h +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_FILTERS_MOCK_GPU_VIDEO_ACCELERATOR_FACTORIES_H_ -#define MEDIA_FILTERS_MOCK_GPU_VIDEO_ACCELERATOR_FACTORIES_H_ - -#include "base/memory/scoped_ptr.h" -#include "base/single_thread_task_runner.h" -#include "media/filters/gpu_video_accelerator_factories.h" -#include "media/video/video_decode_accelerator.h" -#include "media/video/video_encode_accelerator.h" -#include "testing/gmock/include/gmock/gmock.h" - -template <class T> -class scoped_refptr; - -namespace base { -class SharedMemory; -} - -namespace media { - -class MockGpuVideoAcceleratorFactories : public GpuVideoAcceleratorFactories { - public: - MockGpuVideoAcceleratorFactories(); - - // CreateVideo{Decode,Encode}Accelerator returns scoped_ptr, which the mocking - // framework does not want. Trampoline them. - MOCK_METHOD0(DoCreateVideoDecodeAccelerator, VideoDecodeAccelerator*()); - MOCK_METHOD0(DoCreateVideoEncodeAccelerator, VideoEncodeAccelerator*()); - - MOCK_METHOD5(CreateTextures, - bool(int32 count, - const gfx::Size& size, - std::vector<uint32>* texture_ids, - std::vector<gpu::Mailbox>* texture_mailboxes, - uint32 texture_target)); - MOCK_METHOD1(DeleteTexture, void(uint32 texture_id)); - MOCK_METHOD1(WaitSyncPoint, void(uint32 sync_point)); - 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; - - virtual scoped_ptr<VideoEncodeAccelerator> CreateVideoEncodeAccelerator() - override; - - private: - virtual ~MockGpuVideoAcceleratorFactories(); - - DISALLOW_COPY_AND_ASSIGN(MockGpuVideoAcceleratorFactories); -}; - -} // namespace media - -#endif // MEDIA_FILTERS_MOCK_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
diff --git a/media/filters/video_decoder_selector_unittest.cc b/media/filters/video_decoder_selector_unittest.cc index f2dabdf..86f4c0ec 100644 --- a/media/filters/video_decoder_selector_unittest.cc +++ b/media/filters/video_decoder_selector_unittest.cc
@@ -131,6 +131,8 @@ base::Bind(&VideoDecoderSelectorTest::MockOnDecoderSelected, base::Unretained(this)), base::Bind(&VideoDecoderSelectorTest::FrameReady, + base::Unretained(this)), + base::Bind(&VideoDecoderSelectorTest::OnWaitingForDecryptionKey, base::Unretained(this))); message_loop_.RunUntilIdle(); } @@ -147,6 +149,10 @@ NOTREACHED(); } + void OnWaitingForDecryptionKey() { + NOTREACHED(); + } + // Declare |decoder_selector_| after |demuxer_stream_| and |decryptor_| since // |demuxer_stream_| and |decryptor_| should outlive |decoder_selector_|. scoped_ptr<StrictMock<MockDemuxerStream> > demuxer_stream_;
diff --git a/media/filters/video_frame_stream_unittest.cc b/media/filters/video_frame_stream_unittest.cc index f71c07f..a9f3b60 100644 --- a/media/filters/video_frame_stream_unittest.cc +++ b/media/filters/video_frame_stream_unittest.cc
@@ -125,6 +125,7 @@ MOCK_METHOD1(OnNewSpliceBuffer, void(base::TimeDelta)); MOCK_METHOD1(SetDecryptorReadyCallback, void(const media::DecryptorReadyCB&)); MOCK_METHOD1(DecryptorSet, void(bool)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); void OnStatistics(const PipelineStatistics& statistics) { num_decoded_bytes_unreported_ -= statistics.video_bytes_decoded; @@ -155,7 +156,8 @@ base::Unretained(this)), base::Bind(&VideoFrameStreamTest::SetDecryptorReadyCallback, base::Unretained(this)), - base::Bind(&VideoFrameStreamTest::OnStatistics, + base::Bind(&VideoFrameStreamTest::OnStatistics, base::Unretained(this)), + base::Bind(&VideoFrameStreamTest::OnWaitingForDecryptionKey, base::Unretained(this))); message_loop_.RunUntilIdle(); } @@ -276,6 +278,8 @@ break; case DECRYPTOR_NO_KEY: + if (GetParam().is_encrypted) + EXPECT_CALL(*this, OnWaitingForDecryptionKey()); ExpectDecryptorNotification(); has_no_key_ = true; ReadOneFrame();
diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc index dd43679..fb9b0af 100644 --- a/media/filters/vpx_video_decoder.cc +++ b/media/filters/vpx_video_decoder.cc
@@ -465,7 +465,12 @@ codec_format = VideoFrame::YV24; uv_rows = vpx_image->d_h; } else if (vpx_codec_alpha_) { + // TODO(watk): A limitation of conflating color space with pixel format is + // that it's not possible to have BT709 with alpha. + // Until color space is separated from format, prefer YV12A over YV12HD. codec_format = VideoFrame::YV12A; + } else if (vpx_image->cs == VPX_CS_BT_709) { + codec_format = VideoFrame::YV12HD; } gfx::Size size(vpx_image->d_w, vpx_image->d_h);
diff --git a/media/media.gyp b/media/media.gyp index 69c0164..ea044b9 100644 --- a/media/media.gyp +++ b/media/media.gyp
@@ -388,6 +388,8 @@ 'base/video_decoder_config.h', 'base/video_frame.cc', 'base/video_frame.h', + 'base/video_frame_metadata.cc', + 'base/video_frame_metadata.h', 'base/video_frame_pool.cc', 'base/video_frame_pool.h', 'base/video_renderer.cc', @@ -456,8 +458,6 @@ 'filters/file_data_source.h', 'filters/frame_processor.cc', 'filters/frame_processor.h', - 'filters/gpu_video_accelerator_factories.cc', - 'filters/gpu_video_accelerator_factories.h', 'filters/gpu_video_decoder.cc', 'filters/gpu_video_decoder.h', 'filters/h264_bit_reader.cc', @@ -550,6 +550,8 @@ 'renderers/audio_renderer_impl.h', 'renderers/default_renderer_factory.cc', 'renderers/default_renderer_factory.h', + 'renderers/gpu_video_accelerator_factories.cc', + 'renderers/gpu_video_accelerator_factories.h', 'renderers/renderer_impl.cc', 'renderers/renderer_impl.h', 'renderers/video_renderer_impl.cc', @@ -1494,10 +1496,10 @@ 'base/test_helpers.h', 'filters/clockless_video_frame_scheduler.cc', 'filters/clockless_video_frame_scheduler.h', - 'filters/mock_gpu_video_accelerator_factories.cc', - 'filters/mock_gpu_video_accelerator_factories.h', 'filters/test_video_frame_scheduler.cc', 'filters/test_video_frame_scheduler.h', + 'renderers/mock_gpu_video_accelerator_factories.cc', + 'renderers/mock_gpu_video_accelerator_factories.h', 'video/mock_video_decode_accelerator.cc', 'video/mock_video_decode_accelerator.h', ], @@ -1889,6 +1891,8 @@ 'base/mac/videotoolbox_glue.mm', 'base/video_frame.cc', 'base/video_frame.h', + 'base/video_frame_metadata.cc', + 'base/video_frame_metadata.h', ], 'link_settings': { 'libraries': [
diff --git a/media/midi/midi_manager_mac_unittest.cc b/media/midi/midi_manager_mac_unittest.cc index e608d7c..a74ccad 100644 --- a/media/midi/midi_manager_mac_unittest.cc +++ b/media/midi/midi_manager_mac_unittest.cc
@@ -10,6 +10,7 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/synchronization/lock.h" #include "testing/gtest/include/gtest/gtest.h" namespace media { @@ -23,12 +24,24 @@ FakeMidiManagerClient() : result_(MIDI_NOT_SUPPORTED), wait_for_result_(true), - wait_for_port_(true) {} + wait_for_port_(true), + unexpected_callback_(false) {} // MidiManagerClient implementation. void AddInputPort(const MidiPortInfo& info) override {} void AddOutputPort(const MidiPortInfo& info) override { - CHECK(!wait_for_result_); + base::AutoLock lock(lock_); + // AddOutputPort may be called before CompleteStartSession() is invoked + // if one or more MIDI devices including virtual ports are connected. + // Just ignore in such cases. + if (wait_for_result_) + return; + + // Check if this is the first call after CompleteStartSession(), and + // the case should not happen twice. + if (!wait_for_port_) + unexpected_callback_ = true; + info_ = info; wait_for_port_ = false; } @@ -36,7 +49,10 @@ void SetOutputPortState(uint32 port_index, MidiPortState state) override {} void CompleteStartSession(MidiResult result) override { - EXPECT_TRUE(wait_for_result_); + base::AutoLock lock(lock_); + if (!wait_for_result_) + unexpected_callback_ = true; + result_ = result; wait_for_result_ = false; } @@ -45,26 +61,40 @@ double timestamp) override {} void AccumulateMidiBytesSent(size_t size) override {} + bool GetWaitForResult() { + base::AutoLock lock(lock_); + return wait_for_result_; + } + + bool GetWaitForPort() { + base::AutoLock lock(lock_); + return wait_for_port_; + } + MidiResult WaitForResult() { - while (wait_for_result_) { + while (GetWaitForResult()) { base::RunLoop run_loop; run_loop.RunUntilIdle(); } + EXPECT_FALSE(unexpected_callback_); return result_; } MidiPortInfo WaitForPort() { - while (wait_for_port_) { + while (GetWaitForPort()) { base::RunLoop run_loop; run_loop.RunUntilIdle(); } + EXPECT_FALSE(unexpected_callback_); return info_; } private: + base::Lock lock_; MidiResult result_; bool wait_for_result_; MidiPortInfo info_; bool wait_for_port_; + bool unexpected_callback_; DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient); };
diff --git a/media/midi/midi_manager_usb.cc b/media/midi/midi_manager_usb.cc index 8faba06..eab41dae 100644 --- a/media/midi/midi_manager_usb.cc +++ b/media/midi/midi_manager_usb.cc
@@ -46,8 +46,6 @@ if (port_index >= output_streams_.size()) { // |port_index| is provided by a renderer so we can't believe that it is // in the valid range. - // TODO(toyoshim): Move this check to MidiHost and kill the renderer when - // it fails. return; } output_streams_[port_index]->Send(data);
diff --git a/media/mojo/services/mojo_renderer_impl.cc b/media/mojo/services/mojo_renderer_impl.cc index 3bde3b25..e4a13326 100644 --- a/media/mojo/services/mojo_renderer_impl.cc +++ b/media/mojo/services/mojo_renderer_impl.cc
@@ -33,7 +33,8 @@ // Connection to |remote_media_renderer_| will error-out here. } -// TODO(xhwang): Support |paint_cb| if needed. +// TODO(xhwang): Support |paint_cb| and |waiting_for_decryption_key_cb|, +// if needed. void MojoRendererImpl::Initialize( DemuxerStreamProvider* demuxer_stream_provider, const PipelineStatusCB& init_cb, @@ -41,7 +42,8 @@ const BufferingStateCB& buffering_state_cb, const PaintCB& /* paint_cb */, const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) { + const PipelineStatusCB& error_cb, + const base::Closure& /* waiting_for_decryption_key_cb */) { DVLOG(1) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(demuxer_stream_provider);
diff --git a/media/mojo/services/mojo_renderer_impl.h b/media/mojo/services/mojo_renderer_impl.h index d1ddc31..338bcb8 100644 --- a/media/mojo/services/mojo_renderer_impl.h +++ b/media/mojo/services/mojo_renderer_impl.h
@@ -39,7 +39,8 @@ const BufferingStateCB& buffering_state_cb, const PaintCB& paint_cb, const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) override; + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) override; void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb) override; void Flush(const base::Closure& flush_cb) override;
diff --git a/media/mojo/services/mojo_renderer_service.cc b/media/mojo/services/mojo_renderer_service.cc index a737aa32..d4d2c9a 100644 --- a/media/mojo/services/mojo_renderer_service.cc +++ b/media/mojo/services/mojo_renderer_service.cc
@@ -120,7 +120,8 @@ base::Bind(&MojoRendererService::OnBufferingStateChanged, weak_this_), base::Bind(&PaintNothing), base::Bind(&MojoRendererService::OnRendererEnded, weak_this_), - base::Bind(&MojoRendererService::OnError, weak_this_)); + base::Bind(&MojoRendererService::OnError, weak_this_), + base::Bind(base::DoNothing)); } void MojoRendererService::OnRendererInitializeDone(
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc index 56f3da7..74ef1d2 100644 --- a/media/renderers/audio_renderer_impl.cc +++ b/media/renderers/audio_renderer_impl.cc
@@ -257,7 +257,8 @@ const StatisticsCB& statistics_cb, const BufferingStateCB& buffering_state_cb, const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) { + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) { DVLOG(1) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(stream); @@ -317,7 +318,7 @@ audio_buffer_stream_->Initialize( stream, base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized, weak_factory_.GetWeakPtr()), - set_decryptor_ready_cb, statistics_cb); + set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb); } void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) {
diff --git a/media/renderers/audio_renderer_impl.h b/media/renderers/audio_renderer_impl.h index af7251a..1972c872 100644 --- a/media/renderers/audio_renderer_impl.h +++ b/media/renderers/audio_renderer_impl.h
@@ -80,7 +80,8 @@ const StatisticsCB& statistics_cb, const BufferingStateCB& buffering_state_cb, const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) override; + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) override; TimeSource* GetTimeSource() override; void Flush(const base::Closure& callback) override; void StartPlaying() override;
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc index b5035c6..98782c93 100644 --- a/media/renderers/audio_renderer_impl_unittest.cc +++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -113,8 +113,10 @@ MOCK_METHOD1(OnStatistics, void(const PipelineStatistics&)); MOCK_METHOD1(OnBufferingStateChange, void(BufferingState)); MOCK_METHOD1(OnError, void(PipelineStatus)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); void InitializeRenderer(const PipelineStatusCB& pipeline_status_cb) { + EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); renderer_->Initialize( &demuxer_stream_, pipeline_status_cb, SetDecryptorReadyCB(), base::Bind(&AudioRendererImplTest::OnStatistics, @@ -122,7 +124,9 @@ base::Bind(&AudioRendererImplTest::OnBufferingStateChange, base::Unretained(this)), base::Bind(&AudioRendererImplTest::OnEnded, base::Unretained(this)), - base::Bind(&AudioRendererImplTest::OnError, base::Unretained(this))); + base::Bind(&AudioRendererImplTest::OnError, base::Unretained(this)), + base::Bind(&AudioRendererImplTest::OnWaitingForDecryptionKey, + base::Unretained(this))); } void Initialize() {
diff --git a/media/renderers/default_renderer_factory.cc b/media/renderers/default_renderer_factory.cc index 8f701b3..ba56001 100644 --- a/media/renderers/default_renderer_factory.cc +++ b/media/renderers/default_renderer_factory.cc
@@ -10,10 +10,10 @@ #include "media/filters/ffmpeg_audio_decoder.h" #include "media/filters/ffmpeg_video_decoder.h" #endif -#include "media/filters/gpu_video_accelerator_factories.h" #include "media/filters/gpu_video_decoder.h" #include "media/filters/opus_audio_decoder.h" #include "media/renderers/audio_renderer_impl.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "media/renderers/renderer_impl.h" #include "media/renderers/video_renderer_impl.h" #if !defined(MEDIA_DISABLE_LIBVPX)
diff --git a/media/renderers/gpu_video_accelerator_factories.cc b/media/renderers/gpu_video_accelerator_factories.cc new file mode 100644 index 0000000..caea121 --- /dev/null +++ b/media/renderers/gpu_video_accelerator_factories.cc
@@ -0,0 +1,11 @@ +// 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 "media/renderers/gpu_video_accelerator_factories.h" + +namespace media { + +GpuVideoAcceleratorFactories::~GpuVideoAcceleratorFactories() {} + +} // namespace media
diff --git a/media/renderers/gpu_video_accelerator_factories.h b/media/renderers/gpu_video_accelerator_factories.h new file mode 100644 index 0000000..0d99fd7 --- /dev/null +++ b/media/renderers/gpu_video_accelerator_factories.h
@@ -0,0 +1,78 @@ +// 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 MEDIA_RENDERERS_GPU_VIDEO_ACCELERATOR_FACTORIES_H_ +#define MEDIA_RENDERERS_GPU_VIDEO_ACCELERATOR_FACTORIES_H_ + +#include <vector> + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "gpu/command_buffer/common/mailbox.h" +#include "media/base/media_export.h" +#include "media/video/video_encode_accelerator.h" + +namespace base { +class SingleThreadTaskRunner; +class SharedMemory; +} + +namespace gfx { +class Rect; +class Size; +} + +namespace media { + +class VideoDecodeAccelerator; + +// Helper interface for specifying factories needed to instantiate a hardware +// video accelerator. +// Threading model: +// * The GpuVideoAcceleratorFactories may be constructed on any thread. +// * The GpuVideoAcceleratorFactories has an associated message loop, which may +// be retrieved as |GetMessageLoop()|. +// * All calls to the Factories after construction must be made on its message +// loop. +class MEDIA_EXPORT GpuVideoAcceleratorFactories + : public base::RefCountedThreadSafe<GpuVideoAcceleratorFactories> { + public: + // Caller owns returned pointer, but should call Destroy() on it (instead of + // directly deleting) for proper destruction, as per the + // VideoDecodeAccelerator interface. + virtual scoped_ptr<VideoDecodeAccelerator> CreateVideoDecodeAccelerator() = 0; + + // Caller owns returned pointer, but should call Destroy() on it (instead of + // directly deleting) for proper destruction, as per the + // VideoEncodeAccelerator interface. + virtual scoped_ptr<VideoEncodeAccelerator> CreateVideoEncodeAccelerator() = 0; + + // Allocate & delete native textures. + virtual bool CreateTextures(int32 count, + const gfx::Size& size, + std::vector<uint32>* texture_ids, + std::vector<gpu::Mailbox>* texture_mailboxes, + uint32 texture_target) = 0; + virtual void DeleteTexture(uint32 texture_id) = 0; + + virtual void WaitSyncPoint(uint32 sync_point) = 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; + + // Returns the supported codec profiles of video encode accelerator. + virtual std::vector<VideoEncodeAccelerator::SupportedProfile> + GetVideoEncodeAcceleratorSupportedProfiles() = 0; + + protected: + friend class base::RefCountedThreadSafe<GpuVideoAcceleratorFactories>; + virtual ~GpuVideoAcceleratorFactories(); +}; + +} // namespace media + +#endif // MEDIA_RENDERERS_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
diff --git a/media/renderers/mock_gpu_video_accelerator_factories.cc b/media/renderers/mock_gpu_video_accelerator_factories.cc new file mode 100644 index 0000000..c9f78244 --- /dev/null +++ b/media/renderers/mock_gpu_video_accelerator_factories.cc
@@ -0,0 +1,28 @@ +// 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 "media/renderers/mock_gpu_video_accelerator_factories.h" + +namespace media { + +MockGpuVideoAcceleratorFactories::MockGpuVideoAcceleratorFactories() {} + +MockGpuVideoAcceleratorFactories::~MockGpuVideoAcceleratorFactories() {} + +scoped_ptr<base::SharedMemory> +MockGpuVideoAcceleratorFactories::CreateSharedMemory(size_t size) { + return nullptr; +} + +scoped_ptr<VideoDecodeAccelerator> +MockGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator() { + return scoped_ptr<VideoDecodeAccelerator>(DoCreateVideoDecodeAccelerator()); +} + +scoped_ptr<VideoEncodeAccelerator> +MockGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator() { + return scoped_ptr<VideoEncodeAccelerator>(DoCreateVideoEncodeAccelerator()); +} + +} // namespace media
diff --git a/media/renderers/mock_gpu_video_accelerator_factories.h b/media/renderers/mock_gpu_video_accelerator_factories.h new file mode 100644 index 0000000..85b1b3d --- /dev/null +++ b/media/renderers/mock_gpu_video_accelerator_factories.h
@@ -0,0 +1,61 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_RENDERERS_MOCK_GPU_VIDEO_ACCELERATOR_FACTORIES_H_ +#define MEDIA_RENDERERS_MOCK_GPU_VIDEO_ACCELERATOR_FACTORIES_H_ + +#include "base/memory/scoped_ptr.h" +#include "base/single_thread_task_runner.h" +#include "media/renderers/gpu_video_accelerator_factories.h" +#include "media/video/video_decode_accelerator.h" +#include "media/video/video_encode_accelerator.h" +#include "testing/gmock/include/gmock/gmock.h" + +template <class T> +class scoped_refptr; + +namespace base { +class SharedMemory; +} + +namespace media { + +class MockGpuVideoAcceleratorFactories : public GpuVideoAcceleratorFactories { + public: + MockGpuVideoAcceleratorFactories(); + + // CreateVideo{Decode,Encode}Accelerator returns scoped_ptr, which the mocking + // framework does not want. Trampoline them. + MOCK_METHOD0(DoCreateVideoDecodeAccelerator, VideoDecodeAccelerator*()); + MOCK_METHOD0(DoCreateVideoEncodeAccelerator, VideoEncodeAccelerator*()); + + MOCK_METHOD5(CreateTextures, + bool(int32 count, + const gfx::Size& size, + std::vector<uint32>* texture_ids, + std::vector<gpu::Mailbox>* texture_mailboxes, + uint32 texture_target)); + MOCK_METHOD1(DeleteTexture, void(uint32 texture_id)); + MOCK_METHOD1(WaitSyncPoint, void(uint32 sync_point)); + 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; + + virtual scoped_ptr<VideoEncodeAccelerator> CreateVideoEncodeAccelerator() + override; + + private: + virtual ~MockGpuVideoAcceleratorFactories(); + + DISALLOW_COPY_AND_ASSIGN(MockGpuVideoAcceleratorFactories); +}; + +} // namespace media + +#endif // MEDIA_RENDERERS_MOCK_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc index 74e09d7..93671851 100644 --- a/media/renderers/renderer_impl.cc +++ b/media/renderers/renderer_impl.cc
@@ -56,13 +56,15 @@ base::ResetAndReturn(&flush_cb_).Run(); } -void RendererImpl::Initialize(DemuxerStreamProvider* demuxer_stream_provider, - const PipelineStatusCB& init_cb, - const StatisticsCB& statistics_cb, - const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, - const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) { +void RendererImpl::Initialize( + DemuxerStreamProvider* demuxer_stream_provider, + const PipelineStatusCB& init_cb, + const StatisticsCB& statistics_cb, + const BufferingStateCB& buffering_state_cb, + const PaintCB& paint_cb, + const base::Closure& ended_cb, + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) { DVLOG(1) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK_EQ(state_, STATE_UNINITIALIZED); @@ -82,6 +84,7 @@ ended_cb_ = ended_cb; error_cb_ = error_cb; init_cb_ = init_cb; + waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; state_ = STATE_INITIALIZING; InitializeAudioRenderer(); @@ -258,7 +261,8 @@ base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_, &audio_buffering_state_), base::Bind(&RendererImpl::OnAudioRendererEnded, weak_this_), - base::Bind(&RendererImpl::OnError, weak_this_)); + base::Bind(&RendererImpl::OnError, weak_this_), + waiting_for_decryption_key_cb_); } void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) { @@ -307,7 +311,8 @@ base::Bind(&RendererImpl::OnVideoRendererEnded, weak_this_), base::Bind(&RendererImpl::OnError, weak_this_), base::Bind(&RendererImpl::GetMediaTimeForSyncingVideo, - base::Unretained(this))); + base::Unretained(this)), + waiting_for_decryption_key_cb_); } void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) {
diff --git a/media/renderers/renderer_impl.h b/media/renderers/renderer_impl.h index 68a2f7e0..befa95c1 100644 --- a/media/renderers/renderer_impl.h +++ b/media/renderers/renderer_impl.h
@@ -49,7 +49,8 @@ const BufferingStateCB& buffering_state_cb, const PaintCB& paint_cb, const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) final; + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) final; void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb) final; void Flush(const base::Closure& flush_cb) final; @@ -133,6 +134,7 @@ PipelineStatusCB error_cb_; BufferingStateCB buffering_state_cb_; PaintCB paint_cb_; + base::Closure waiting_for_decryption_key_cb_; // Temporary callback used for Initialize() and Flush(). PipelineStatusCB init_cb_;
diff --git a/media/renderers/renderer_impl_unittest.cc b/media/renderers/renderer_impl_unittest.cc index 8f738b0..30bad2fe 100644 --- a/media/renderers/renderer_impl_unittest.cc +++ b/media/renderers/renderer_impl_unittest.cc
@@ -50,6 +50,7 @@ MOCK_METHOD1(OnUpdateStatistics, void(const PipelineStatistics&)); MOCK_METHOD1(OnBufferingStateChange, void(BufferingState)); MOCK_METHOD1(OnVideoFramePaint, void(const scoped_refptr<VideoFrame>&)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void()); private: DISALLOW_COPY_AND_ASSIGN(CallbackHelper); @@ -88,7 +89,7 @@ // Sets up expectations to allow the audio renderer to initialize. void SetAudioRendererInitializeExpectations(PipelineStatus status) { EXPECT_CALL(*audio_renderer_, - Initialize(audio_stream_.get(), _, _, _, _, _, _)) + Initialize(audio_stream_.get(), _, _, _, _, _, _, _)) .WillOnce(DoAll(SaveArg<4>(&audio_buffering_state_cb_), SaveArg<5>(&audio_ended_cb_), SaveArg<6>(&audio_error_cb_), RunCallback<1>(status))); @@ -97,13 +98,14 @@ // Sets up expectations to allow the video renderer to initialize. void SetVideoRendererInitializeExpectations(PipelineStatus status) { EXPECT_CALL(*video_renderer_, - Initialize(video_stream_.get(), _, _, _, _, _, _, _, _)) + Initialize(video_stream_.get(), _, _, _, _, _, _, _, _, _)) .WillOnce(DoAll(SaveArg<4>(&video_buffering_state_cb_), SaveArg<6>(&video_ended_cb_), RunCallback<1>(status))); } void InitializeAndExpect(PipelineStatus start_status) { EXPECT_CALL(callbacks_, OnInitialize(start_status)); + EXPECT_CALL(callbacks_, OnWaitingForDecryptionKey()).Times(0); if (start_status == PIPELINE_OK && audio_stream_) { EXPECT_CALL(*audio_renderer_, GetTimeSource()) @@ -121,7 +123,9 @@ base::Bind(&CallbackHelper::OnVideoFramePaint, base::Unretained(&callbacks_)), base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)), - base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_))); + base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)), + base::Bind(&CallbackHelper::OnWaitingForDecryptionKey, + base::Unretained(&callbacks_))); base::RunLoop().RunUntilIdle(); } @@ -433,7 +437,7 @@ // Force an audio error to occur during video renderer initialization. EXPECT_CALL(*video_renderer_, - Initialize(video_stream_.get(), _, _, _, _, _, _, _, _)) + Initialize(video_stream_.get(), _, _, _, _, _, _, _, _, _)) .WillOnce(DoAll(AudioError(&audio_error_cb_, PIPELINE_ERROR_DECODE), SaveArg<4>(&video_buffering_state_cb_), SaveArg<6>(&video_ended_cb_),
diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc index 5e2819d..0ad19e4 100644 --- a/media/renderers/video_renderer_impl.cc +++ b/media/renderers/video_renderer_impl.cc
@@ -109,7 +109,8 @@ const PaintCB& paint_cb, const base::Closure& ended_cb, const PipelineStatusCB& error_cb, - const TimeDeltaCB& get_time_cb) { + const TimeDeltaCB& get_time_cb, + const base::Closure& waiting_for_decryption_key_cb) { DCHECK(task_runner_->BelongsToCurrentThread()); base::AutoLock auto_lock(lock_); DCHECK(stream); @@ -139,7 +140,7 @@ video_frame_stream_->Initialize( stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized, weak_factory_.GetWeakPtr()), - set_decryptor_ready_cb, statistics_cb); + set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb); } void VideoRendererImpl::CreateVideoThread() {
diff --git a/media/renderers/video_renderer_impl.h b/media/renderers/video_renderer_impl.h index 69cf140..eec8b15 100644 --- a/media/renderers/video_renderer_impl.h +++ b/media/renderers/video_renderer_impl.h
@@ -60,7 +60,8 @@ const PaintCB& paint_cb, const base::Closure& ended_cb, const PipelineStatusCB& error_cb, - const TimeDeltaCB& get_time_cb) override; + const TimeDeltaCB& get_time_cb, + const base::Closure& waiting_for_decryption_key_cb) override; void Flush(const base::Closure& callback) override; void StartPlayingFrom(base::TimeDelta timestamp) override;
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc index c771ad4..d9cad51 100644 --- a/media/renderers/video_renderer_impl_unittest.cc +++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -94,6 +94,7 @@ demuxer_stream_.set_liveness(DemuxerStream::LIVENESS_LIVE); EXPECT_CALL(*decoder_, Initialize(_, _, _, _)).WillOnce( DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(decoder_status))); + EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); renderer_->Initialize( &demuxer_stream_, status_cb, media::SetDecryptorReadyCB(), base::Bind(&VideoRendererImplTest::OnStatisticsUpdate, @@ -102,7 +103,9 @@ base::Unretained(&mock_cb_)), base::Bind(&StrictMock<MockCB>::Display, base::Unretained(&mock_cb_)), ended_event_.GetClosure(), error_event_.GetPipelineStatusCB(), - base::Bind(&VideoRendererImplTest::GetTime, base::Unretained(this))); + base::Bind(&VideoRendererImplTest::GetTime, base::Unretained(this)), + base::Bind(&VideoRendererImplTest::OnWaitingForDecryptionKey, + base::Unretained(this))); } void StartPlayingFrom(int milliseconds) { @@ -289,6 +292,8 @@ void OnStatisticsUpdate(const PipelineStatistics& stats) {} + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); + base::MessageLoop message_loop_; // Used to protect |time_|.
diff --git a/media/test/data/bear-vp9-bt709.webm b/media/test/data/bear-vp9-bt709.webm new file mode 100644 index 0000000..23f9548 --- /dev/null +++ b/media/test/data/bear-vp9-bt709.webm Binary files differ
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc index c2e23f8f..bf502df8 100644 --- a/media/test/pipeline_integration_test.cc +++ b/media/test/pipeline_integration_test.cc
@@ -659,6 +659,10 @@ .WillRepeatedly(SaveArg<0>(&metadata_)); EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH)) .Times(AtMost(1)); + + // Encrypted content not used, so this is never called. + EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); + demuxer_ = source->GetDemuxer().Pass(); pipeline_->Start( demuxer_.get(), CreateRenderer(), @@ -673,7 +677,9 @@ base::Bind(&PipelineIntegrationTest::OnVideoFramePaint, base::Unretained(this)), base::Closure(), base::Bind(&PipelineIntegrationTest::OnAddTextTrack, - base::Unretained(this))); + base::Unretained(this)), + base::Bind(&PipelineIntegrationTest::OnWaitingForDecryptionKey, + base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(PIPELINE_OK, pipeline_status_); } @@ -694,6 +700,10 @@ .Times(AtMost(1)); EXPECT_CALL(*this, DecryptorAttached(true)); + // Encrypted content used but keys provided in advance, so this is + // never called. + EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); + demuxer_ = source->GetDemuxer().Pass(); pipeline_->SetCdm(encrypted_media->GetCdmContext(), @@ -713,7 +723,9 @@ base::Bind(&PipelineIntegrationTest::OnVideoFramePaint, base::Unretained(this)), base::Closure(), base::Bind(&PipelineIntegrationTest::OnAddTextTrack, - base::Unretained(this))); + base::Unretained(this)), + base::Bind(&PipelineIntegrationTest::OnWaitingForDecryptionKey, + base::Unretained(this))); source->set_encrypted_media_init_data_cb( base::Bind(&FakeEncryptedMedia::OnEncryptedMediaInitData, @@ -1639,6 +1651,15 @@ EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, VideoFrame::YV24); } +// Verify that frames of VP9 video in the BT.709 color space have the YV12HD +// format. +TEST_F(PipelineIntegrationTest, BT709_VP9_WebM) { + ASSERT_EQ(PIPELINE_OK, Start("bear-vp9-bt709.webm")); + Play(); + ASSERT_TRUE(WaitUntilOnEnded()); + EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, VideoFrame::YV12HD); +} + // Verify that videos with an odd frame size playback successfully. TEST_F(PipelineIntegrationTest, BasicPlayback_OddVideoSize) { ASSERT_EQ(PIPELINE_OK, Start("butterfly-853x480.webm"));
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc index d40b0dcb..e122d9a8 100644 --- a/media/test/pipeline_integration_test_base.cc +++ b/media/test/pipeline_integration_test_base.cc
@@ -121,6 +121,10 @@ base::Unretained(this))); } + // Should never be called as the required decryption keys for the encrypted + // media files are provided in advance. + EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); + pipeline_->Start( demuxer_.get(), CreateRenderer(), base::Bind(&PipelineIntegrationTestBase::OnEnded, base::Unretained(this)), @@ -134,7 +138,9 @@ base::Bind(&PipelineIntegrationTestBase::OnVideoFramePaint, base::Unretained(this)), base::Closure(), base::Bind(&PipelineIntegrationTestBase::OnAddTextTrack, - base::Unretained(this))); + base::Unretained(this)), + base::Bind(&PipelineIntegrationTestBase::OnWaitingForDecryptionKey, + base::Unretained(this))); message_loop_.Run(); return pipeline_status_; }
diff --git a/media/test/pipeline_integration_test_base.h b/media/test/pipeline_integration_test_base.h index de6c0e0..716e27cf 100644 --- a/media/test/pipeline_integration_test_base.h +++ b/media/test/pipeline_integration_test_base.h
@@ -140,6 +140,7 @@ MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig& config, const AddTextTrackDoneCB& done_cb)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); }; } // namespace media
diff --git a/media/tools/player_x11/player_x11.cc b/media/tools/player_x11/player_x11.cc index afd5d0b..60eb45c 100644 --- a/media/tools/player_x11/player_x11.cc +++ b/media/tools/player_x11/player_x11.cc
@@ -149,7 +149,8 @@ base::Bind(&OnBufferingStateChanged), paint_cb, base::Bind(&DoNothing), - base::Bind(&OnAddTextTrack)); + base::Bind(&OnAddTextTrack), + base::Bind(&DoNothing)); // Wait until the pipeline is fully initialized. event.Wait();
diff --git a/media/video/capture/fake_video_capture_device_unittest.cc b/media/video/capture/fake_video_capture_device_unittest.cc index ace1a28a..3ad349f 100644 --- a/media/video/capture/fake_video_capture_device_unittest.cc +++ b/media/video/capture/fake_video_capture_device_unittest.cc
@@ -26,9 +26,8 @@ MOCK_METHOD2(ReserveOutputBuffer, scoped_refptr<Buffer>(VideoFrame::Format format, const gfx::Size& dimensions)); - MOCK_METHOD4(OnIncomingCapturedVideoFrame, + MOCK_METHOD3(OnIncomingCapturedVideoFrame, void(const scoped_refptr<Buffer>& buffer, - const VideoCaptureFormat& buffer_format, const scoped_refptr<media::VideoFrame>& frame, const base::TimeTicks& timestamp)); MOCK_METHOD1(OnError, void(const std::string& reason)); @@ -82,7 +81,7 @@ void SetUp() override { EXPECT_CALL(*client_, ReserveOutputBuffer(_,_)).Times(0); - EXPECT_CALL(*client_, OnIncomingCapturedVideoFrame(_,_,_,_)).Times(0); + EXPECT_CALL(*client_, OnIncomingCapturedVideoFrame(_,_,_)).Times(0); } void OnFrameCaptured(const VideoCaptureFormat& format) {
diff --git a/media/video/capture/video_capture_device.h b/media/video/capture/video_capture_device.h index 87de975..747f1b0 100644 --- a/media/video/capture/video_capture_device.h +++ b/media/video/capture/video_capture_device.h
@@ -219,7 +219,6 @@ // additional copies in the browser process. virtual void OnIncomingCapturedVideoFrame( const scoped_refptr<Buffer>& buffer, - const VideoCaptureFormat& buffer_format, const scoped_refptr<media::VideoFrame>& frame, const base::TimeTicks& timestamp) = 0;
diff --git a/media/video/capture/video_capture_device_unittest.cc b/media/video/capture/video_capture_device_unittest.cc index c4e94a0..0c66c34 100644 --- a/media/video/capture/video_capture_device_unittest.cc +++ b/media/video/capture/video_capture_device_unittest.cc
@@ -67,9 +67,8 @@ MOCK_METHOD2(ReserveOutputBuffer, scoped_refptr<Buffer>(VideoFrame::Format format, const gfx::Size& dimensions)); - MOCK_METHOD4(OnIncomingCapturedVideoFrame, + MOCK_METHOD3(OnIncomingCapturedVideoFrame, void(const scoped_refptr<Buffer>& buffer, - const VideoCaptureFormat& buffer_format, const scoped_refptr<VideoFrame>& frame, const base::TimeTicks& timestamp)); MOCK_METHOD1(OnError, void(const std::string& reason)); @@ -129,7 +128,7 @@ base::android::AttachCurrentThread()); #endif EXPECT_CALL(*client_, ReserveOutputBuffer(_,_)).Times(0); - EXPECT_CALL(*client_, OnIncomingCapturedVideoFrame(_,_,_,_)).Times(0); + EXPECT_CALL(*client_, OnIncomingCapturedVideoFrame(_,_,_)).Times(0); } void ResetWithNewClient() {
diff --git a/mojo/android/BUILD.gn b/mojo/android/BUILD.gn index c21dc3f..d99e716 100644 --- a/mojo/android/BUILD.gn +++ b/mojo/android/BUILD.gn
@@ -85,7 +85,6 @@ "javatests/src/org/chromium/mojo/bindings/ValidationTest.java", "javatests/src/org/chromium/mojo/bindings/ValidationTestUtil.java", "javatests/src/org/chromium/mojo/bindings/ValidationTestUtilTest.java", - "javatests/src/org/chromium/mojo/bindings/test/mojom/mojo/IntegrationTestInterface2TestHelper.java", "javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java", ]
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java index 4744508c6..3b332e1 100644 --- a/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java +++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java
@@ -10,7 +10,6 @@ import org.chromium.mojo.bindings.BindingsTestUtils.CapturingErrorHandler; import org.chromium.mojo.bindings.test.mojom.imported.ImportedInterface; import org.chromium.mojo.bindings.test.mojom.sample.Factory; -import org.chromium.mojo.bindings.test.mojom.sample.FactoryClient; import org.chromium.mojo.bindings.test.mojom.sample.NamedObject; import org.chromium.mojo.bindings.test.mojom.sample.NamedObject.GetNameResponse; import org.chromium.mojo.bindings.test.mojom.sample.Request; @@ -101,18 +100,11 @@ public class MockFactoryImpl extends CapturingErrorHandler implements Factory { private boolean mClosed = false; - private FactoryClient mFactoryClient; public boolean isClosed() { return mClosed; } - @Override - public void setClient(FactoryClient client) { - mFactoryClient = client; - mCloseablesToClose.add(client); - } - /** * @see org.chromium.mojo.bindings.Interface#close() */ @@ -122,17 +114,18 @@ } @Override - public void doStuff(Request request, MessagePipeHandle pipe) { + public void doStuff(Request request, MessagePipeHandle pipe, DoStuffResponse callback) { if (pipe != null) { pipe.close(); } Response response = new Response(); response.x = 42; - mFactoryClient.didStuff(response, "Hello"); + + callback.call(response, "Hello"); } @Override - public void doStuff2(ConsumerHandle pipe) { + public void doStuff2(ConsumerHandle pipe, DoStuff2Response callback) { } @Override @@ -154,54 +147,6 @@ } /** - * Basic implementation of {@link FactoryClient}. - */ - public static class MockFactoryClientImpl implements FactoryClient { - - private boolean mClosed = false; - private boolean mDidStuffCalled = false; - - public boolean isClosed() { - return mClosed; - } - - public boolean wasDidStuffCalled() { - return mDidStuffCalled; - } - - /** - * @see org.chromium.mojo.bindings.Interface#close() - */ - @Override - public void close() { - mClosed = true; - } - - /** - * @see ConnectionErrorHandler#onConnectionError(MojoException) - */ - @Override - public void onConnectionError(MojoException e) { - } - - /** - * @see FactoryClient#didStuff(Response, java.lang.String) - */ - @Override - public void didStuff(Response response, String text) { - mDidStuffCalled = true; - } - - /** - * @see FactoryClient#didStuff2(String) - */ - @Override - public void didStuff2(String text) { - } - - } - - /** * @see MojoTestCase#tearDown() */ @Override @@ -225,17 +170,6 @@ return proxy; } - private <I extends InterfaceWithClient<C>, P extends InterfaceWithClient.Proxy<C>, - C extends Interface> P newProxyOverPipeWithClient( - InterfaceWithClient.Manager<I, P, C> manager, I impl, C client) { - Pair<MessagePipeHandle, MessagePipeHandle> handles = - CoreImpl.getInstance().createMessagePipe(null); - P proxy = manager.attachProxy(handles.first, client); - mCloseablesToClose.add(proxy); - manager.bind(impl, handles.second); - return proxy; - } - /** * Check that the given proxy receives the calls. If |impl| is not null, also check that the * calls are forwared to |impl|. @@ -311,34 +245,13 @@ @SmallTest public void testInterfaceClosing() { MockFactoryImpl impl = new MockFactoryImpl(); - MockFactoryClientImpl client = new MockFactoryClientImpl(); - Factory.Proxy proxy = newProxyOverPipeWithClient( - Factory.MANAGER, impl, client); + Factory.Proxy proxy = newProxyOverPipe(Factory.MANAGER, impl); assertFalse(impl.isClosed()); - assertFalse(client.isClosed()); proxy.close(); runLoopUntilIdle(); assertTrue(impl.isClosed()); - assertTrue(client.isClosed()); - } - - @SmallTest - public void testClient() { - MockFactoryImpl impl = new MockFactoryImpl(); - MockFactoryClientImpl client = new MockFactoryClientImpl(); - Factory.Proxy proxy = newProxyOverPipeWithClient( - Factory.MANAGER, impl, client); - Request request = new Request(); - request.x = 42; - proxy.doStuff(request, null); - - assertFalse(client.wasDidStuffCalled()); - - runLoopUntilIdle(); - - assertTrue(client.wasDidStuffCalled()); } }
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java index 076c94b..7942be6 100644 --- a/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java +++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java
@@ -11,8 +11,7 @@ import org.chromium.mojo.HandleMock; import org.chromium.mojo.MojoTestCase; import org.chromium.mojo.bindings.test.mojom.mojo.ConformanceTestInterface; -import org.chromium.mojo.bindings.test.mojom.mojo.IntegrationTestInterface1; -import org.chromium.mojo.bindings.test.mojom.mojo.IntegrationTestInterface2TestHelper; +import org.chromium.mojo.bindings.test.mojom.mojo.IntegrationTestInterface; import org.chromium.mojo.system.Handle; import java.io.File; @@ -119,41 +118,6 @@ } } - private static class RoutingMessageReceiver implements MessageReceiver { - private final MessageReceiver mRequest; - private final MessageReceiver mResponse; - - private RoutingMessageReceiver(MessageReceiver request, MessageReceiver response) { - this.mRequest = request; - this.mResponse = response; - } - - /** - * @see MessageReceiver#accept(Message) - */ - @Override - public boolean accept(Message message) { - try { - MessageHeader header = message.asServiceMessage().getHeader(); - if (header.hasFlag(MessageHeader.MESSAGE_IS_RESPONSE_FLAG)) { - return mResponse.accept(message); - } else { - return mRequest.accept(message); - } - } catch (DeserializationException e) { - return false; - } - } - - /** - * @see MessageReceiver#close() - */ - @Override - public void close() { - } - - } - /** * A trivial message receiver that refuses all messages it receives. */ @@ -188,11 +152,7 @@ */ @SmallTest public void testIntegration() throws FileNotFoundException { - runTest("integration_", - new RoutingMessageReceiver(IntegrationTestInterface1.MANAGER.buildStub(null, - IntegrationTestInterface1.MANAGER.buildProxy(null, - new SinkMessageReceiver())), - IntegrationTestInterface2TestHelper - .newIntegrationTestInterface2MethodCallback())); + runTest("integration_", IntegrationTestInterface.MANAGER.buildStub(null, + IntegrationTestInterface.MANAGER.buildProxy(null, new SinkMessageReceiver()))); } }
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/test/mojom/mojo/IntegrationTestInterface2TestHelper.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/test/mojom/mojo/IntegrationTestInterface2TestHelper.java deleted file mode 100644 index 2a2b6b8..0000000 --- a/mojo/android/javatests/src/org/chromium/mojo/bindings/test/mojom/mojo/IntegrationTestInterface2TestHelper.java +++ /dev/null
@@ -1,31 +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. - -package org.chromium.mojo.bindings.test.mojom.mojo; - -import org.chromium.mojo.bindings.MessageReceiver; -import org.chromium.mojo.bindings.test.mojom.mojo.IntegrationTestInterface2.Method0Response; -import org.chromium.mojo.bindings.test.mojom.mojo.IntegrationTestInterface2_Internal.IntegrationTestInterface2Method0ResponseParamsForwardToCallback; - -/** - * Helper class to access {@link IntegrationTestInterface2_Internal} package protected method for - * tests. - */ -public class IntegrationTestInterface2TestHelper { - - private static final class SinkMethod0Response implements Method0Response { - @Override - public void call(byte[] arg1) { - } - } - - /** - * Creates a new {@link MessageReceiver} to use for the callback of - * |IntegrationTestInterface2#method0(Method0Response)|. - */ - public static MessageReceiver newIntegrationTestInterface2MethodCallback() { - return new IntegrationTestInterface2Method0ResponseParamsForwardToCallback( - new SinkMethod0Response()); - } -}
diff --git a/mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java b/mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java index b35e119..525fc16 100644 --- a/mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java +++ b/mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java
@@ -404,7 +404,8 @@ options.setElementNumBytes(24); createAndCloseDataPipe(options); // Create datapipe with a flag set. - options.getFlags().setMayDiscard(true); + // TODO(aberent) fix or remove, this does not compile. See http://crbug/463852 + // options.getFlags().setMayDiscard(true); createAndCloseDataPipe(options); // Create datapipe with capacity set. options.setCapacityNumBytes(1024 * options.getElementNumBytes());
diff --git a/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java b/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java index 19b2d29f..aaa49f2d 100644 --- a/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java +++ b/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java
@@ -16,6 +16,7 @@ import org.chromium.mojo.system.MojoException; import org.chromium.mojo.system.MojoResult; import org.chromium.mojo.system.Pair; +import org.chromium.mojo.system.RunLoop; import org.chromium.mojo.system.SharedBufferHandle; import org.chromium.mojo.system.SharedBufferHandle.DuplicateOptions; import org.chromium.mojo.system.SharedBufferHandle.MapFlags; @@ -206,6 +207,22 @@ } /** + * @see Core#createDefaultRunLoop() + */ + @Override + public RunLoop createDefaultRunLoop() { + return null; + } + + /** + * @see Core#getCurrentRunLoop() + */ + @Override + public RunLoop getCurrentRunLoop() { + return null; + } + + /** * @see AsyncWaiter#asyncWait(Handle, Core.HandleSignals, long, Callback) */ @Override
diff --git a/mojo/services/html_viewer/html_viewer.cc b/mojo/services/html_viewer/html_viewer.cc index 1278a24..f69fcca 100644 --- a/mojo/services/html_viewer/html_viewer.cc +++ b/mojo/services/html_viewer/html_viewer.cc
@@ -75,7 +75,9 @@ web_media_player_factory_(web_media_player_factory), is_headless_(is_headless) {} - void Initialize(ShellPtr shell, Array<String> args) override { + void Initialize(ShellPtr shell, + Array<String> args, + const String& url) override { ServiceProviderPtr service_provider; shell_ = shell.Pass(); shell_->ConnectToApplication("mojo:network_service", @@ -85,7 +87,8 @@ void AcceptConnection(const String& requestor_url, InterfaceRequest<ServiceProvider> services, - ServiceProviderPtr exposed_services) override { + ServiceProviderPtr exposed_services, + const String& url) override { if (initial_response_) { OnResponseReceived(URLLoaderPtr(), services.Pass(), initial_response_.Pass());
diff --git a/mojo/services/html_viewer/view_url.py b/mojo/services/html_viewer/view_url.py new file mode 100755 index 0000000..a543385 --- /dev/null +++ b/mojo/services/html_viewer/view_url.py
@@ -0,0 +1,57 @@ +#!/usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import argparse +import os +import subprocess +import sys + +root_path = os.path.realpath( + os.path.join( + os.path.dirname( + os.path.realpath(__file__)), + os.pardir, + os.pardir, + os.pardir)) + +def _BuildShellCommand(args): + sdk_version = subprocess.check_output(["cat", + "third_party/mojo/src/mojo/public/VERSION"], cwd=root_path) + build_dir = os.path.join(root_path, args.build_dir) + + shell_command = [os.path.join(build_dir, "mojo_shell")] + + options = [] + options.append( + "--origin=https://storage.googleapis.com/mojo/services/linux-x64/%s" % + sdk_version) + options.append("--url-mappings=mojo:html_viewer=file://%s/html_viewer.mojo" % + build_dir) + options.append('--args-for=mojo:kiosk_wm %s' % args.url) + + app_to_run = "mojo:kiosk_wm" + + return shell_command + options + [app_to_run] + +def main(): + parser = argparse.ArgumentParser( + description="View a URL with HTMLViewer in the Kiosk window manager. " + "You must have built //mojo/services/html_viewer and " + "//mojo/services/network first. Note that this will " + "currently often fail spectacularly due to lack of binary " + "stability in Mojo.") + parser.add_argument( + "--build-dir", + help="Path to the dir containing the linux-x64 binaries relative to the " + "repo root (default: %(default)s)", + default="out/Release") + parser.add_argument("url", + help="The URL to be viewed") + + args = parser.parse_args() + return subprocess.call(_BuildShellCommand(args)) + +if __name__ == '__main__': + sys.exit(main())
diff --git a/mojo/services/html_viewer/weblayertreeview_impl.h b/mojo/services/html_viewer/weblayertreeview_impl.h index 9a6b07f..74120bde 100644 --- a/mojo/services/html_viewer/weblayertreeview_impl.h +++ b/mojo/services/html_viewer/weblayertreeview_impl.h
@@ -89,7 +89,6 @@ float new_page_scale, double duration_sec); virtual void heuristicsForGpuRasterizationUpdated(bool matches_heuristic) {} - virtual void setTopControlsContentOffset(float offset) {} virtual void setNeedsAnimate(); virtual bool commitRequested() const; virtual void didStopFlinging() {}
diff --git a/mojo/services/html_viewer/webmediaplayer_factory.cc b/mojo/services/html_viewer/webmediaplayer_factory.cc index a5729dd..0b73a985 100644 --- a/mojo/services/html_viewer/webmediaplayer_factory.cc +++ b/mojo/services/html_viewer/webmediaplayer_factory.cc
@@ -17,10 +17,10 @@ #include "media/blink/webmediaplayer_impl.h" #include "media/blink/webmediaplayer_params.h" #include "media/cdm/default_cdm_factory.h" -#include "media/filters/gpu_video_accelerator_factories.h" #include "media/mojo/interfaces/media_renderer.mojom.h" #include "media/mojo/services/mojo_renderer_factory.h" #include "media/renderers/default_renderer_factory.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "third_party/mojo/src/mojo/public/cpp/application/connect.h" #include "third_party/mojo/src/mojo/public/interfaces/application/shell.mojom.h"
diff --git a/mojo/services/network/android_hooks.cc b/mojo/services/network/android_hooks.cc index 190eef1..e822402 100644 --- a/mojo/services/network/android_hooks.cc +++ b/mojo/services/network/android_hooks.cc
@@ -2,19 +2,41 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/android/base_jni_registrar.h" +#include <vector> + +#include "base/android/base_jni_onload.h" #include "base/android/jni_android.h" +#include "base/android/library_loader/library_loader_hooks.h" +#include "base/bind.h" #include "net/android/net_jni_registrar.h" +namespace { +bool RegisterJNI(JNIEnv* env) { + return net::android::RegisterJni(env); +} + +bool Init() { + return true; +} +} // namespace + + +// This is called by the VM when the shared library is first loaded. JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - base::android::InitVM(vm); - JNIEnv* env = base::android::AttachCurrentThread(); + std::vector<base::android::RegisterCallback> register_callbacks; + register_callbacks.push_back(base::Bind(&RegisterJNI)); - if (!base::android::RegisterJni(env)) - return -1; + std::vector<base::android::InitCallback> init_callbacks; + init_callbacks.push_back(base::Bind(&Init)); - if (!net::android::RegisterJni(env)) + if (!base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || + !base::android::OnJNIOnLoadInit(init_callbacks)) { return -1; + } + + // There cannot be two AtExitManagers at the same time. Remove the one from + // LibraryLoader as ApplicationRunnerChromium also uses one. + base::android::LibraryLoaderExitHook(); return JNI_VERSION_1_4; }
diff --git a/mojo/services/upload_service.py b/mojo/services/upload_service.py index ea528b3a..ca8e6c3 100755 --- a/mojo/services/upload_service.py +++ b/mojo/services/upload_service.py
@@ -74,8 +74,19 @@ absolute_binary_path = os.path.join(root_path, binary_dir, binary_name) if not should_zip: + # Upload the binary. dest = dest_dir + binary_name gsutil_cp(absolute_binary_path, dest, dry_run) + + # Update the pointer to the service's location to point to the + # newly-uploaded binary. + service_location = dest.replace("gs://", "https://storage.googleapis.com/") + location_file = ("gs://mojo/services/" + platform + "/" + service + + "_location") + with tempfile.NamedTemporaryFile() as tmp: + tmp.write(service_location) + tmp.flush() + gsutil_cp(tmp.name, location_file, dry_run) return # Zip the binary before uploading it to the cloud.
diff --git a/native_client_sdk/doc_generated/reference/ideas.html b/native_client_sdk/doc_generated/reference/ideas.html index 863af86a..c611b5f2 100644 --- a/native_client_sdk/doc_generated/reference/ideas.html +++ b/native_client_sdk/doc_generated/reference/ideas.html
@@ -4,41 +4,43 @@ <span id="ideas"></span><h1 id="contributor-ideas"><span id="ideas"></span>Contributor Ideas</h1> <div class="contents local" id="contents" style="display: none"> <ul class="small-gap"> -<li><a class="reference internal" href="#contributing-me" id="id8">Contributing? Me‽</a></li> -<li><p class="first"><a class="reference internal" href="#id1" id="id9">Ideas</a></p> +<li><a class="reference internal" href="#contributing-me" id="id9">Contributing? Me‽</a></li> +<li><a class="reference internal" href="#google-summer-of-code" id="id10">Google Summer of Code</a></li> +<li><p class="first"><a class="reference internal" href="#id2" id="id11">Ideas</a></p> <ul class="small-gap"> -<li><p class="first"><a class="reference internal" href="#ports" id="id10">Ports</a></p> +<li><p class="first"><a class="reference internal" href="#ports" id="id12">Ports</a></p> <ul class="small-gap"> -<li><a class="reference internal" href="#new-filesystems" id="id11">New Filesystems</a></li> -<li><a class="reference internal" href="#open-source-porting" id="id12">Open Source Porting</a></li> +<li><a class="reference internal" href="#new-filesystems" id="id13">New Filesystems</a></li> +<li><a class="reference internal" href="#open-source-porting" id="id14">Open Source Porting</a></li> </ul> </li> -<li><p class="first"><a class="reference internal" href="#languages" id="id13">Languages</a></p> +<li><p class="first"><a class="reference internal" href="#languages" id="id15">Languages</a></p> <ul class="small-gap"> -<li><a class="reference internal" href="#rust" id="id14">Rust</a></li> -<li><a class="reference internal" href="#haskell" id="id15">Haskell</a></li> -<li><a class="reference internal" href="#julia" id="id16">Julia</a></li> -<li><a class="reference internal" href="#scala" id="id17">Scala</a></li> -<li><a class="reference internal" href="#elm" id="id18">Elm</a></li> -<li><a class="reference internal" href="#mono" id="id19">Mono</a></li> -<li><a class="reference internal" href="#perl" id="id20">Perl</a></li> +<li><a class="reference internal" href="#rust" id="id16">Rust</a></li> +<li><a class="reference internal" href="#haskell" id="id17">Haskell</a></li> +<li><a class="reference internal" href="#julia" id="id18">Julia</a></li> +<li><a class="reference internal" href="#scala" id="id19">Scala</a></li> +<li><a class="reference internal" href="#elm" id="id20">Elm</a></li> +<li><a class="reference internal" href="#mono" id="id21">Mono</a></li> +<li><a class="reference internal" href="#perl" id="id22">Perl</a></li> </ul> </li> -<li><a class="reference internal" href="#tcc" id="id21">TCC</a></li> -<li><p class="first"><a class="reference internal" href="#llvm-and-pnacl" id="id22">LLVM and PNaCl</a></p> +<li><a class="reference internal" href="#tcc" id="id23">TCC</a></li> +<li><p class="first"><a class="reference internal" href="#llvm-and-pnacl" id="id24">LLVM and PNaCl</a></p> <ul class="small-gap"> -<li><a class="reference internal" href="#sandboxing-optimizations" id="id23">Sandboxing Optimizations</a></li> -<li><a class="reference internal" href="#binary-size-reduction" id="id24">Binary Size Reduction</a></li> -<li><a class="reference internal" href="#vector-support" id="id25">Vector Support</a></li> -<li><a class="reference internal" href="#atomics" id="id26">Atomics</a></li> -<li><a class="reference internal" href="#security-enhanced-pnacl" id="id27">Security-enhanced PNaCl</a></li> +<li><a class="reference internal" href="#sandboxing-optimizations" id="id25">Sandboxing Optimizations</a></li> +<li><a class="reference internal" href="#binary-size-reduction" id="id26">Binary Size Reduction</a></li> +<li><a class="reference internal" href="#vector-support" id="id27">Vector Support</a></li> +<li><a class="reference internal" href="#atomics" id="id28">Atomics</a></li> +<li><a class="reference internal" href="#security-enhanced-pnacl" id="id29">Security-enhanced PNaCl</a></li> +<li><a class="reference internal" href="#sanitizer-support" id="id30">Sanitizer Support</a></li> </ul> </li> -<li><p class="first"><a class="reference internal" href="#nacl" id="id28">NaCl</a></p> +<li><p class="first"><a class="reference internal" href="#nacl" id="id31">NaCl</a></p> <ul class="small-gap"> -<li><a class="reference internal" href="#auto-sandboxing" id="id29">Auto-Sandboxing</a></li> -<li><a class="reference internal" href="#new-sandbox" id="id30">New Sandbox</a></li> -<li><a class="reference internal" href="#bit-sandbox" id="id31">64-bit Sandbox</a></li> +<li><a class="reference internal" href="#auto-sandboxing" id="id32">Auto-Sandboxing</a></li> +<li><a class="reference internal" href="#new-sandbox" id="id33">New Sandbox</a></li> +<li><a class="reference internal" href="#bit-sandbox" id="id34">64-bit Sandbox</a></li> </ul> </li> </ul> @@ -57,7 +59,12 @@ this page please contact the <a class="reference external" href="https://groups.google.com/group/native-client-discuss">native-client-discuss</a> mailing list.</p> <p>If you like an idea on this page and would like to get started, contact the <a class="reference external" href="https://groups.google.com/group/native-client-discuss">native-client-discuss</a> mailing list so that we can help you find a mentor.</p> -<h2 id="id1">Ideas</h2> +<h2 id="google-summer-of-code">Google Summer of Code</h2> +<p>PNaCl participates in the <a class="reference external" href="https://www.google-melange.com/gsoc/homepage/google/gsoc2015">2015 Google Summer of Code</a> (see the <a class="reference external" href="https://www.google-melange.com/gsoc/org2/google/gsoc2015/pnacl">PNaCl GSoC +page</a>). <a class="reference external" href="https://www.google-melange.com/gsoc/document/show/gsoc_program/google/gsoc2015/help_page#4._How_does_a_student_apply">Student applications</a> are open March 16–27. Discuss project ideas no +<a class="reference external" href="https://groups.google.com/group/native-client-discuss">native-client-discuss</a>, and submit your proposal on the GSoC page by the +deadline.</p> +<h2 id="id2">Ideas</h2> <p>We’ve separated contributor ideas into broad areas of interest:</p> <ul class="small-gap"> <li><strong>Ports</strong> encompass all the code that <em>uses</em> the PNaCl platform. Put simply, @@ -281,6 +288,20 @@ <li><strong>Knowledge Prerequisite:</strong> Security.</li> <li><strong>Mentor:</strong> JF Bastien.</li> </ul> +<h4 id="sanitizer-support">Sanitizer Support</h4> +<ul class="small-gap"> +<li><strong>Project:</strong> Sanitizer support for untrusted code.</li> +<li><strong>Brief explanation:</strong> LLVM supports many <a class="reference external" href="http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation">sanitizers</a> for C/C++ using the +<code>-fsanitize=<name></code>. Some of these sanitizers currently work, and some don’t +because they use clever tricks to perform their work, such as using <code>mmap</code> +to allocate a special shadow memory region with a specific address. This +project requires adding full support to all of LLVM’s sanitizers for untrusted +user code within PNaCl.</li> +<li><strong>Expected results:</strong> The sanitizer tests successfully run as untrusted code +within PNaCl.</li> +<li><strong>Knowledge Prerequisite:</strong> Compilers.</li> +<li><strong>Mentor:</strong> JF Bastien.</li> +</ul> <h3 id="nacl">NaCl</h3> <h4 id="auto-sandboxing">Auto-Sandboxing</h4> <ul class="small-gap">
diff --git a/native_client_sdk/doc_generated/sdk/release-notes.html b/native_client_sdk/doc_generated/sdk/release-notes.html index 7a81d94..798946f 100644 --- a/native_client_sdk/doc_generated/sdk/release-notes.html +++ b/native_client_sdk/doc_generated/sdk/release-notes.html
@@ -4,6 +4,13 @@ <span id="sdk-release-notes"></span><h1 id="release-notes"><span id="sdk-release-notes"></span>Release Notes</h1> <p>The dates in the following release notes denote when Chrome and the NaCl SDK reached canary status. The stable release is typically 6 weeks later.</p> +<h2 id="chrome-pepper-43-03-april-2015">Chrome/Pepper 43 (03 April 2015)</h2> +<h3 id="pnacl">PNaCl</h3> +<ul class="small-gap"> +<li>The C11/C++11 <code>acquire</code>, <code>release</code>, and <code>acq_rel</code> memory orders are now +generated by default. The in-browser Chrome 42 translator supports them, the +SDK can therefore generate them.</li> +</ul> <h2 id="chrome-pepper-42-20-february-2015">Chrome/Pepper 42 (20 February 2015)</h2> <h3 id="sdk">SDK</h3> <ul class="small-gap"> @@ -16,17 +23,17 @@ <h3 id="nacl">NaCl</h3> <ul class="small-gap"> <li>The x86 NaCl validators accept instructions from the FMA3 extensions, as well -as AVX2 instructions (except <cite>VGATHER</cite>).</li> +as AVX2 instructions (except <code>VGATHER</code>).</li> </ul> -<h3 id="pnacl">PNaCl</h3> +<h3 id="id1">PNaCl</h3> <ul class="small-gap"> -<li>PNaCl supports C11/C++11 memory orders <cite>acquire</cite>, <cite>release</cite>, and <cite>acq_rel</cite>. It -used to upgrade all accesses to <cite>seq_cst</cite>. It still upgrades <cite>consume</cite> to -<cite>acquire</cite> (no compiler currently implements <cite>consume</cite>), and <cite>relaxed</cite> to -<cite>seq_cst</cite> (to conservatively avoid platform differences due to out-of-thin-air -problems). This is currently disabled by default in the SDK so that the -in-browser translator installed on users’ machines has time to gain this -support. Developers can turn it on by passing the +<li>PNaCl supports C11/C++11 memory orders <code>acquire</code>, <code>release</code>, and +<code>acq_rel</code>. It used to upgrade all accesses to <code>seq_cst</code>. It still upgrades +<code>consume</code> to <code>acquire</code> (no compiler currently implements <code>consume</code>), and +<code>relaxed</code> to <code>seq_cst</code> (to conservatively avoid platform differences due +to out-of-thin-air problems). This is currently disabled by default in the SDK +so that the in-browser translator installed on users’ machines has time to +gain this support. Developers can turn it on by passing the <code>-pnacl-memory-order-seq-cst-only=false</code> flag to <code>opt</code>.</li> <li>PNaCl handles nested struct type expansion, which allows it to better support non-C languages such as Rust.</li> @@ -34,11 +41,11 @@ operations. This is often encountered when using large consecutive bitfields.</li> </ul> <h2 id="chrome-pepper-41-09-january-2015">Chrome/Pepper 41 (09 January 2015)</h2> -<h3 id="id1">NaCl</h3> +<h3 id="id2">NaCl</h3> <ul class="small-gap"> <li>The x86 NaCl validators accept instructions from the AVX1 extensions.</li> </ul> -<h3 id="id2">PNaCl</h3> +<h3 id="id3">PNaCl</h3> <ul class="small-gap"> <li>PNaCl is now based on LLVM 3.5.</li> </ul> @@ -57,31 +64,31 @@ embeds.</li> </ul> <h2 id="chrome-pepper-38-15-august-2014">Chrome/Pepper 38 (15 August 2014)</h2> -<h3 id="id3">PNaCl</h3> +<h3 id="id4">PNaCl</h3> <ul class="small-gap"> <li>Compilation speed improvements due to validation caching of the translator and linker.</li> <li>Performance improvement of SIMD vector shuffle.</li> </ul> <h2 id="chrome-pepper-37-20-june-2014">Chrome/Pepper 37 (20 June 2014)</h2> -<h3 id="id4">PNaCl</h3> +<h3 id="id5">PNaCl</h3> <ul class="small-gap"> <li>2–10% translation time improvement.</li> <li>Improved vector load/store and shuffle performance.</li> </ul> -<h3 id="id5">Pepper</h3> +<h3 id="id6">Pepper</h3> <ul class="small-gap"> <li>Media Streams Input support.</li> <li>Compositor API.</li> <li>Hardware Decode API in development preview.</li> <li>Sync API in development preview.</li> </ul> -<h3 id="id6">SDK</h3> +<h3 id="id7">SDK</h3> <ul class="small-gap"> <li>Demo of a <a class="reference internal" href="/native-client/io2014.html#io2014"><em>full development environment in the browser</em></a>.</li> </ul> <h2 id="chrome-pepper-36-09-may-2014">Chrome/Pepper 36 (09 May 2014)</h2> -<h3 id="id7">PNaCl</h3> +<h3 id="id8">PNaCl</h3> <ul class="small-gap"> <li>Support <a class="reference external" href="http://clang.llvm.org/docs/LanguageExtensions.html#vectors-and-extended-vectors">LLVM vectors</a> and <a class="reference external" href="http://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html">GCC vectors</a> for SIMD @@ -90,7 +97,7 @@ Chrome. More SIMD instructions will be added in later releases.</li> </ul> <h2 id="chrome-pepper-35-31-mar-2014">Chrome/Pepper 35 (31 Mar 2014)</h2> -<h3 id="id8">PNaCl</h3> +<h3 id="id9">PNaCl</h3> <ul class="small-gap"> <li>Upgraded LLVM to version 3.4.</li> <li>Translation now uses dynamic load balancing, making translation time faster.</li> @@ -98,7 +105,7 @@ Chrome, simplifying debugging with PNaCl. See <a class="reference internal" href="/native-client/devguide/devcycle/debugging.html#debugging-pnacl-pexes"><em>Debugging PNaCl pexes</em></a></li> </ul> <h2 id="chrome-pepper-34-20-feb-2014">Chrome/Pepper 34 (20 Feb 2014)</h2> -<h3 id="id9">Pepper</h3> +<h3 id="id10">Pepper</h3> <ul class="small-gap"> <li>Filesystems can now be passed from JavaScript to NaCl. The resulting <code>pp::Var</code> will contain a <code>pp::Resource</code> that can be given to the @@ -108,7 +115,7 @@ <a class="reference external" href="/native-client/pepper_dev/cpp/classpp_1_1_media_stream_video_track">pp::MediaStreamVideoTrack</a> for more details.</li> </ul> -<h3 id="id10">PNaCl</h3> +<h3 id="id11">PNaCl</h3> <ul class="small-gap"> <li>Parallel translation: at least 1.7x faster, even with older pexes.</li> <li>Intelligent abbreviations in the bitcode: 20% reduction in binary size using @@ -122,7 +129,7 @@ handling (see <a class="reference external" href="https://groups.google.com/forum/#!topic/native-client-discuss/0spfg6O04FM">announcement</a> for details).</li> </ul> -<h3 id="id11">SDK</h3> +<h3 id="id12">SDK</h3> <ul class="small-gap"> <li>The <code>nacl_io</code> library now includes a FUSE mount.</li> <li>In the SDK examples, <code>common.js</code> now loads the Release version of the @@ -236,7 +243,7 @@ <p>The Pepper 26 bundle includes a new HTTP filesystem type in the nacl_mounts library (which has been renamed nacl_io), changes to the example Makefiles, a simple new 3D example, and a threaded file IO example.</p> -<h3 id="id12">Build tools and toolchains</h3> +<h3 id="id13">Build tools and toolchains</h3> <ul class="small-gap"> <li><p class="first">Makefiles have been changed significantly:</p> <ul class="small-gap"> @@ -256,14 +263,14 @@ the same set of header files as host builds. Previously host and NaCl builds used different headers, which could cause build problems.</li> </ul> -<h3 id="id13">Libraries</h3> +<h3 id="id14">Libraries</h3> <ul class="small-gap"> <li>The nacl_mounts library has been renamed <strong>nacl_io</strong>, and has been expanded with a new type of mount, httpfs, which can be used to read URLs via HTTP. For details see <code>include/nacl_io/nacl_io.h</code>, as well as the <code>hello_nacl_io</code> example.</li> </ul> -<h3 id="id14">Examples</h3> +<h3 id="id15">Examples</h3> <ul class="small-gap"> <li>A new example, <strong>hello_world_instance3d</strong>, has been added to demonstrate a simplified 3D app.</li> @@ -285,7 +292,7 @@ operations, and ppapi_main, which lets you implement a Native Client module using a simple ppapi_main function), and two new examples that demonstrate how to use the nacl_mounts and ppapi_main libraries.</p> -<h3 id="id15">Build tools and toolchains</h3> +<h3 id="id16">Build tools and toolchains</h3> <ul class="small-gap"> <li><p class="first">The SDK includes a new toolchain to build Native Client executables (.nexe files) for <strong>ARM devices</strong>.</p> @@ -322,7 +329,7 @@ cannot make asynchronous PPAPI calls on a background thread without creating and using a message loop.</li> </ul> -<h3 id="id16">Libraries</h3> +<h3 id="id17">Libraries</h3> <p>The SDK includes two new libraries:</p> <ul class="small-gap"> <li><p class="first">The <strong>nacl_mounts</strong> library provides a virtual file system that your module @@ -356,7 +363,7 @@ <p>Header files for the new libraries are in the <code>include/</code> directory, source files are in the <code>src/</code> directory, and compiled libraries are in the <code>lib/</code> directory.</p> -<h3 id="id17">Examples</h3> +<h3 id="id18">Examples</h3> <ul class="small-gap"> <li><p class="first">The SDK includes two new examples:</p> <ul class="small-gap"> @@ -397,7 +404,7 @@ for “Portable Native Client”), a new library (pthreads-win32) for the Windows SDK, and an expanded list of attributes for Pepper 3D contexts that lets applications specify a GPU preference for low power or performance.</p> -<h3 id="id18">Build tools and toolchains</h3> +<h3 id="id19">Build tools and toolchains</h3> <ul class="small-gap"> <li>The SDK includes a new, experimental toolchain called <a class="reference external" href="http://nativeclient.googlecode.com/svn/data/site/pnacl.pdf">PNaCl</a> (pronounced “pinnacle”). The PNaCl toolchain produces architecture-independent executable @@ -413,7 +420,7 @@ names of your .nexe files and <code>create_nmf.py</code> will still be able to generate the appropriate Native Client manifest file for your application.</li> </ul> -<h3 id="id20">Examples</h3> +<h3 id="id21">Examples</h3> <ul class="small-gap"> <li>The SDK examples now build with four toolchains: the glibc and newlib toolchains, the experimental PNaCl toolchain, and the hosted toolchain on @@ -424,7 +431,7 @@ drawing function is now set up as the Flush() callback, which allows 2D drawing to occur as quickly as possible.</li> </ul> -<h3 id="id21">PPAPI</h3> +<h3 id="id22">PPAPI</h3> <ul class="small-gap"> <li>When creating a 3D rendering context, the <a class="reference external" href="/native-client/pepper_stable/c/group___enums#ga7df48e1c55f6401beea2a1b9c07967e8">attribute list</a> for the context can specify whether to prefer low power or performance for @@ -496,7 +503,7 @@ </ul> </li> </ul> -<h3 id="id22">Examples</h3> +<h3 id="id23">Examples</h3> <ul class="small-gap"> <li>On Linux and Windows systems, most of the examples now build with three toolchains: the Native Client glibc and newlib toolchains, and the native @@ -512,7 +519,7 @@ a list of changes between version 1 and version 2 of the manifest file format, and a support schedule for applications that use version 1.</li> </ul> -<h3 id="id23">PPAPI</h3> +<h3 id="id24">PPAPI</h3> <ul class="small-gap"> <li><a class="reference external" href="/native-client/pepper_stable/c/group___enums#ga21b811ac0484a214a8751aa3e1c959d9">PP_InputEvent_Modifier</a> has two new enum values (_ISLEFT and _ISRIGHT).</li> @@ -523,14 +530,14 @@ <p>The Pepper 22 bundle includes a <strong>command-line debugger</strong>, resources to enable <strong>hosted development on Windows</strong>, and changes to the example Makefiles (each example now builds both a debug and a release version).</p> -<h3 id="id24">Tools</h3> +<h3 id="id25">Tools</h3> <ul class="small-gap"> <li>The SDK now includes a <strong>command-line debugger</strong> that you can use to debug Native Client modules. See <a class="reference internal" href="/native-client/devguide/devcycle/debugging.html#devcycle-debugging"><em>Debugging with nacl-gdb</em></a> for instructions on how to use this debugger. For now, nacl-gdb only works on 64-bit Windows, 64-bit Linux, and 32-bit Linux systems. Support for Mac and 32-bit Windows systems will be added soon.</li> </ul> -<h3 id="id25">Windows SDK</h3> +<h3 id="id26">Windows SDK</h3> <ul class="small-gap"> <li><p class="first">Developers using the Windows SDK can now <strong>build a module as a Pepper plugin</strong> (sometimes called a “trusted” or “in-process” plugin) using the @@ -578,7 +585,7 @@ In the future, the SDK will include resources for hosted development on Mac and Linux as well as Windows. </aside> -<h3 id="id26">Examples</h3> +<h3 id="id27">Examples</h3> <ul class="small-gap"> <li>Each example in the SDK now builds both a debug and a release version. As before, most examples also build newlib and glibc versions, which means that @@ -592,7 +599,7 @@ of the module, and implements handleMessage() to respond to messages sent from the NaCl module to the JavaScript side of the application</li> </ul> -<h3 id="id27">PPAPI</h3> +<h3 id="id28">PPAPI</h3> <ul class="small-gap"> <li>The <code>CompletionCallbackFactory</code> class template now takes a thread traits class as its second parameter. For details see the <a class="reference external" href="/native-client/pepper_stable/cpp/classpp_1_1_completion_callback_factory#details">CompletionCallbackFactory
diff --git a/native_client_sdk/doc_generated/sitemap.html b/native_client_sdk/doc_generated/sitemap.html index f6cfcb25..53eba14 100644 --- a/native_client_sdk/doc_generated/sitemap.html +++ b/native_client_sdk/doc_generated/sitemap.html
@@ -42,6 +42,7 @@ </ul> </li> <li class="toctree-l1"><a class="reference internal" href="/native-client/sdk/release-notes.html">Release Notes</a><ul class="small-gap"> +<li class="toctree-l2"><a class="reference internal" href="/native-client/sdk/release-notes.html#chrome-pepper-43-03-april-2015">Chrome/Pepper 43 (03 April 2015)</a></li> <li class="toctree-l2"><a class="reference internal" href="/native-client/sdk/release-notes.html#chrome-pepper-42-20-february-2015">Chrome/Pepper 42 (20 February 2015)</a></li> <li class="toctree-l2"><a class="reference internal" href="/native-client/sdk/release-notes.html#chrome-pepper-41-09-january-2015">Chrome/Pepper 41 (09 January 2015)</a></li> <li class="toctree-l2"><a class="reference internal" href="/native-client/sdk/release-notes.html#chrome-pepper-40-november-07-2014">Chrome/Pepper 40 (November 07 2014)</a></li> @@ -384,7 +385,8 @@ <li class="toctree-l1"><a class="reference internal" href="/native-client/reference/index.html">Reference</a></li> <li class="toctree-l1"><a class="reference internal" href="/native-client/reference/ideas.html">Contributor Ideas</a><ul class="small-gap"> <li class="toctree-l2"><a class="reference internal" href="/native-client/reference/ideas.html#contributing-me">Contributing? Me‽</a></li> -<li class="toctree-l2"><a class="reference internal" href="/native-client/reference/ideas.html#id1">Ideas</a></li> +<li class="toctree-l2"><a class="reference internal" href="/native-client/reference/ideas.html#google-summer-of-code">Google Summer of Code</a></li> +<li class="toctree-l2"><a class="reference internal" href="/native-client/reference/ideas.html#id2">Ideas</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="/native-client/reference/pnacl-bitcode-abi.html">PNaCl Bitcode Reference Manual</a><ul class="small-gap">
diff --git a/native_client_sdk/src/build_tools/build_app.py b/native_client_sdk/src/build_tools/build_app.py index 0c406c0..e0def78 100755 --- a/native_client_sdk/src/build_tools/build_app.py +++ b/native_client_sdk/src/build_tools/build_app.py
@@ -132,14 +132,20 @@ return list1 + [x for x in list2 if x not in list1] all_permissions = [] all_socket_permissions = [] + all_filesystem_permissions = [] for _, project in parse_dsc.GenerateProjects(tree): permissions = project.get('PERMISSIONS', []) all_permissions = MergeLists(all_permissions, permissions) socket_permissions = project.get('SOCKET_PERMISSIONS', []) all_socket_permissions = MergeLists(all_socket_permissions, socket_permissions) + filesystem_permissions = project.get('FILESYSTEM_PERMISSIONS', []) + all_filesystem_permissions = MergeLists(all_filesystem_permissions, + filesystem_permissions) if all_socket_permissions: all_permissions.append({'socket': all_socket_permissions}) + if all_filesystem_permissions: + all_permissions.append({'fileSystem': all_filesystem_permissions}) pretty_permissions = json.dumps(all_permissions, sort_keys=True, indent=4) for filename in ['background.js', 'icon128.png']:
diff --git a/native_client_sdk/src/doc/reference/ideas.rst b/native_client_sdk/src/doc/reference/ideas.rst index 71d4360..5ce2ec4d 100644 --- a/native_client_sdk/src/doc/reference/ideas.rst +++ b/native_client_sdk/src/doc/reference/ideas.rst
@@ -28,6 +28,18 @@ .. _native-client-discuss: https://groups.google.com/group/native-client-discuss +Google Summer of Code +===================== + +PNaCl participates in the `2015 Google Summer of Code`_ (see the `PNaCl GSoC +page`_). `Student applications`_ are open March 16–27. Discuss project ideas no +native-client-discuss_, and submit your proposal on the GSoC page by the +deadline. + +.. _PNaCl GSoC page: https://www.google-melange.com/gsoc/org2/google/gsoc2015/pnacl +.. _2015 Google Summer of Code: https://www.google-melange.com/gsoc/homepage/google/gsoc2015 +.. _Student applications: https://www.google-melange.com/gsoc/document/show/gsoc_program/google/gsoc2015/help_page#4._How_does_a_student_apply + Ideas ===== @@ -311,6 +323,22 @@ * **Knowledge Prerequisite:** Security. * **Mentor:** JF Bastien. +Sanitizer Support +^^^^^^^^^^^^^^^^^ + +* **Project:** Sanitizer support for untrusted code. +* **Brief explanation:** LLVM supports many sanitizers_ for C/C++ using the + ``-fsanitize=<name>``. Some of these sanitizers currently work, and some don't + because they use clever tricks to perform their work, such as using ``mmap`` + to allocate a special shadow memory region with a specific address. This + project requires adding full support to all of LLVM's sanitizers for untrusted + user code within PNaCl. +* **Expected results:** The sanitizer tests successfully run as untrusted code + within PNaCl. +* **Knowledge Prerequisite:** Compilers. +* **Mentor:** JF Bastien. + +.. _sanitizers: http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation NaCl ----
diff --git a/native_client_sdk/src/doc/sdk/release-notes.rst b/native_client_sdk/src/doc/sdk/release-notes.rst index f3ccf1537..06eb85777 100644 --- a/native_client_sdk/src/doc/sdk/release-notes.rst +++ b/native_client_sdk/src/doc/sdk/release-notes.rst
@@ -8,15 +8,15 @@ reached canary status. The stable release is typically 6 weeks later. -.. Chrome/Pepper 43 (03 April 2015) -.. =================================== -.. -.. PNaCl -.. ----- -.. -.. * The C11/C++11 `acquire`, `release`, and `acq_rel` memory orders are now - generated by default. The in-browser Chrome 42 translator supports them, the - SDK can therefore generate them. +Chrome/Pepper 43 (03 April 2015) +================================ + +PNaCl +----- + +* The C11/C++11 ``acquire``, ``release``, and ``acq_rel`` memory orders are now + generated by default. The in-browser Chrome 42 translator supports them, the + SDK can therefore generate them. Chrome/Pepper 42 (20 February 2015) =================================== @@ -34,18 +34,18 @@ ---- * The x86 NaCl validators accept instructions from the FMA3 extensions, as well - as AVX2 instructions (except `VGATHER`). + as AVX2 instructions (except ``VGATHER``). PNaCl ----- -* PNaCl supports C11/C++11 memory orders `acquire`, `release`, and `acq_rel`. It - used to upgrade all accesses to `seq_cst`. It still upgrades `consume` to - `acquire` (no compiler currently implements `consume`), and `relaxed` to - `seq_cst` (to conservatively avoid platform differences due to out-of-thin-air - problems). This is currently disabled by default in the SDK so that the - in-browser translator installed on users' machines has time to gain this - support. Developers can turn it on by passing the +* PNaCl supports C11/C++11 memory orders ``acquire``, ``release``, and + ``acq_rel``. It used to upgrade all accesses to ``seq_cst``. It still upgrades + ``consume`` to ``acquire`` (no compiler currently implements ``consume``), and + ``relaxed`` to ``seq_cst`` (to conservatively avoid platform differences due + to out-of-thin-air problems). This is currently disabled by default in the SDK + so that the in-browser translator installed on users' machines has time to + gain this support. Developers can turn it on by passing the ``-pnacl-memory-order-seq-cst-only=false`` flag to ``opt``. * PNaCl handles nested struct type expansion, which allows it to better support non-C languages such as Rust.
diff --git a/native_client_sdk/src/libraries/gtest/library.dsc b/native_client_sdk/src/libraries/gtest/library.dsc index 82249ef8..2ca73ef 100644 --- a/native_client_sdk/src/libraries/gtest/library.dsc +++ b/native_client_sdk/src/libraries/gtest/library.dsc
@@ -13,7 +13,6 @@ 'gtest.cc', 'gtest-death-test.cc', 'gtest-filepath.cc', - 'gtest_main.cc', 'gtest-port.cc', 'gtest-printers.cc', 'gtest-test-part.cc',
diff --git a/net/BUILD.gn b/net/BUILD.gn index fd2772266..8ebaaa03 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -703,6 +703,10 @@ "//url", ] + if (!is_ios) { + public_deps += [ "//third_party/protobuf:py_proto" ] + } + if (!use_openssl && (use_nss_certs || is_ios)) { public_deps += [ "//crypto:platform" ] } @@ -942,7 +946,6 @@ deps = [ ":net", # TODO(brettw) bug 363749: this shouldn't be necessary. It's not # in the GYP build, and can be removed when the bug is fixed. - ":test_support", "//base", "//base/test:test_support", @@ -953,7 +956,7 @@ executable("stress_cache") { testonly = true sources = [ - "disk_cache/blockfile/stress_cache.cc", + "tools/stress_cache/stress_cache.cc", ] # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
diff --git a/net/cert/x509_certificate_unittest.cc b/net/cert/x509_certificate_unittest.cc index f77c46c6..74ded45 100644 --- a/net/cert/x509_certificate_unittest.cc +++ b/net/cert/x509_certificate_unittest.cc
@@ -1011,7 +1011,7 @@ // be present. { true, "www.test.example", "*.test.example" }, { true, "test.example.co.uk", "*.example.co.uk" }, - { false, "test.example", "*.exmaple" }, + { false, "test.example", "*.example" }, { false, "example.co.uk", "*.co.uk" }, { false, "foo.com", "*.com" }, { false, "foo.us", "*.us" },
diff --git a/net/disk_cache/blockfile/stats.cc b/net/disk_cache/blockfile/stats.cc index e6b10b8..bb319f5 100644 --- a/net/disk_cache/blockfile/stats.cc +++ b/net/disk_cache/blockfile/stats.cc
@@ -107,8 +107,18 @@ local_stats.size = sizeof(local_stats); } else if (num_bytes >= static_cast<int>(sizeof(*stats))) { stats = reinterpret_cast<OnDiskStats*>(data); - if (!VerifyStats(stats)) - return false; + if (!VerifyStats(stats)) { + memset(&local_stats, 0, sizeof(local_stats)); + if (memcmp(stats, &local_stats, sizeof(local_stats))) { + return false; + } else { + // The storage is empty which means that SerializeStats() was never + // called on the last run. Just re-initialize everything. + local_stats.signature = kDiskSignature; + local_stats.size = sizeof(local_stats); + stats = &local_stats; + } + } } else { return false; }
diff --git a/net/disk_cache/blockfile/stats.h b/net/disk_cache/blockfile/stats.h index 8e1293d6..769c171c 100644 --- a/net/disk_cache/blockfile/stats.h +++ b/net/disk_cache/blockfile/stats.h
@@ -9,6 +9,7 @@ #include <vector> #include "base/basictypes.h" +#include "net/base/net_export.h" #include "net/disk_cache/blockfile/addr.h" namespace base { @@ -20,7 +21,7 @@ typedef std::vector<std::pair<std::string, std::string> > StatsItems; // This class stores cache-specific usage information, for tunning purposes. -class Stats { +class NET_EXPORT_PRIVATE Stats { public: static const int kDataSizesLength = 28; enum Counters {
diff --git a/net/disk_cache/blockfile/stats_unittest.cc b/net/disk_cache/blockfile/stats_unittest.cc new file mode 100644 index 0000000..fe47bdd --- /dev/null +++ b/net/disk_cache/blockfile/stats_unittest.cc
@@ -0,0 +1,83 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/disk_cache/blockfile/stats.h" + +#include "base/memory/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(DiskCacheStatsTest, Init) { + disk_cache::Stats stats; + EXPECT_TRUE(stats.Init(nullptr, 0, disk_cache::Addr())); + EXPECT_EQ(0, stats.GetCounter(disk_cache::Stats::TRIM_ENTRY)); +} + +TEST(DiskCacheStatsTest, InitWithEmptyBuffer) { + disk_cache::Stats stats; + int required_len = stats.StorageSize(); + scoped_ptr<char[]> storage(new char[required_len]); + memset(storage.get(), 0, required_len); + + ASSERT_TRUE(stats.Init(storage.get(), required_len, disk_cache::Addr())); + EXPECT_EQ(0, stats.GetCounter(disk_cache::Stats::TRIM_ENTRY)); +} + +TEST(DiskCacheStatsTest, FailsInit) { + disk_cache::Stats stats; + int required_len = stats.StorageSize(); + scoped_ptr<char[]> storage(new char[required_len]); + memset(storage.get(), 0, required_len); + + // Try a small buffer. + EXPECT_LT(200, required_len); + disk_cache::Addr addr; + EXPECT_FALSE(stats.Init(storage.get(), 200, addr)); + + // Try a buffer with garbage. + memset(storage.get(), 'a', required_len); + EXPECT_FALSE(stats.Init(storage.get(), required_len, addr)); +} + +TEST(DiskCacheStatsTest, SaveRestore) { + scoped_ptr<disk_cache::Stats> stats(new disk_cache::Stats); + + disk_cache::Addr addr(5); + ASSERT_TRUE(stats->Init(nullptr, 0, addr)); + stats->SetCounter(disk_cache::Stats::CREATE_ERROR, 11); + stats->SetCounter(disk_cache::Stats::DOOM_ENTRY, 13); + stats->OnEvent(disk_cache::Stats::MIN_COUNTER); + stats->OnEvent(disk_cache::Stats::TRIM_ENTRY); + stats->OnEvent(disk_cache::Stats::DOOM_RECENT); + + int required_len = stats->StorageSize(); + scoped_ptr<char[]> storage(new char[required_len]); + disk_cache::Addr out_addr; + int real_len = stats->SerializeStats(storage.get(), required_len, &out_addr); + EXPECT_GE(required_len, real_len); + EXPECT_EQ(out_addr, addr); + + stats.reset(new disk_cache::Stats); + ASSERT_TRUE(stats->Init(storage.get(), real_len, addr)); + EXPECT_EQ(1, stats->GetCounter(disk_cache::Stats::MIN_COUNTER)); + EXPECT_EQ(1, stats->GetCounter(disk_cache::Stats::TRIM_ENTRY)); + EXPECT_EQ(1, stats->GetCounter(disk_cache::Stats::DOOM_RECENT)); + EXPECT_EQ(0, stats->GetCounter(disk_cache::Stats::OPEN_HIT)); + EXPECT_EQ(0, stats->GetCounter(disk_cache::Stats::READ_DATA)); + EXPECT_EQ(0, stats->GetCounter(disk_cache::Stats::LAST_REPORT_TIMER)); + EXPECT_EQ(11, stats->GetCounter(disk_cache::Stats::CREATE_ERROR)); + EXPECT_EQ(13, stats->GetCounter(disk_cache::Stats::DOOM_ENTRY)); + + // Now pass the whole buffer. It shoulod not matter that there is unused + // space at the end. + stats.reset(new disk_cache::Stats); + ASSERT_TRUE(stats->Init(storage.get(), required_len, addr)); + EXPECT_EQ(1, stats->GetCounter(disk_cache::Stats::MIN_COUNTER)); + EXPECT_EQ(1, stats->GetCounter(disk_cache::Stats::TRIM_ENTRY)); + EXPECT_EQ(1, stats->GetCounter(disk_cache::Stats::DOOM_RECENT)); + EXPECT_EQ(0, stats->GetCounter(disk_cache::Stats::OPEN_HIT)); + EXPECT_EQ(0, stats->GetCounter(disk_cache::Stats::READ_DATA)); + EXPECT_EQ(0, stats->GetCounter(disk_cache::Stats::LAST_REPORT_TIMER)); + EXPECT_EQ(11, stats->GetCounter(disk_cache::Stats::CREATE_ERROR)); + EXPECT_EQ(13, stats->GetCounter(disk_cache::Stats::DOOM_ENTRY)); +}
diff --git a/net/disk_cache/blockfile/stress_cache.cc b/net/disk_cache/blockfile/stress_cache.cc deleted file mode 100644 index d43cb74..0000000 --- a/net/disk_cache/blockfile/stress_cache.cc +++ /dev/null
@@ -1,293 +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. - -// This is a simple application that stress-tests the crash recovery of the disk -// cache. The main application starts a copy of itself on a loop, checking the -// exit code of the child process. When the child dies in an unexpected way, -// the main application quits. - -// The child application has two threads: one to exercise the cache in an -// infinite loop, and another one to asynchronously kill the process. - -// A regular build should never crash. -// To test that the disk cache doesn't generate critical errors with regular -// application level crashes, edit stress_support.h. - -#include <string> -#include <vector> - -#include "base/at_exit.h" -#include "base/bind.h" -#include "base/command_line.h" -#include "base/debug/debugger.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/path_service.h" -#include "base/process/kill.h" -#include "base/process/launch.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" -#include "net/base/test_completion_callback.h" -#include "net/disk_cache/blockfile/backend_impl.h" -#include "net/disk_cache/blockfile/stress_support.h" -#include "net/disk_cache/blockfile/trace.h" -#include "net/disk_cache/disk_cache.h" -#include "net/disk_cache/disk_cache_test_util.h" - -#if defined(OS_WIN) -#include "base/logging_win.h" -#endif - -using base::Time; - -const int kError = -1; -const int kExpectedCrash = 100; - -// Starts a new process. -int RunSlave(int iteration) { - base::FilePath exe; - PathService::Get(base::FILE_EXE, &exe); - - base::CommandLine cmdline(exe); - cmdline.AppendArg(base::IntToString(iteration)); - - base::Process process = base::LaunchProcess(cmdline, base::LaunchOptions()); - if (!process.IsValid()) { - printf("Unable to run test\n"); - return kError; - } - - int exit_code; - if (!process.WaitForExit(&exit_code)) { - printf("Unable to get return code\n"); - return kError; - } - return exit_code; -} - -// Main loop for the master process. -int MasterCode() { - for (int i = 0; i < 100000; i++) { - int ret = RunSlave(i); - if (kExpectedCrash != ret) - return ret; - } - - printf("More than enough...\n"); - - return 0; -} - -// ----------------------------------------------------------------------- - -std::string GenerateStressKey() { - char key[20 * 1024]; - size_t size = 50 + rand() % 20000; - CacheTestFillBuffer(key, size, true); - - key[size - 1] = '\0'; - return std::string(key); -} - -// This thread will loop forever, adding and removing entries from the cache. -// iteration is the current crash cycle, so the entries on the cache are marked -// to know which instance of the application wrote them. -void StressTheCache(int iteration) { - int cache_size = 0x2000000; // 32MB. - uint32 mask = 0xfff; // 4096 entries. - - base::FilePath path; - PathService::Get(base::DIR_TEMP, &path); - path = path.AppendASCII("cache_test_stress"); - - base::Thread cache_thread("CacheThread"); - if (!cache_thread.StartWithOptions( - base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) - return; - - disk_cache::BackendImpl* cache = - new disk_cache::BackendImpl(path, mask, - cache_thread.message_loop_proxy().get(), - NULL); - cache->SetMaxSize(cache_size); - cache->SetFlags(disk_cache::kNoLoadProtection); - - net::TestCompletionCallback cb; - int rv = cache->Init(cb.callback()); - - if (cb.GetResult(rv) != net::OK) { - printf("Unable to initialize cache.\n"); - return; - } - printf("Iteration %d, initial entries: %d\n", iteration, - cache->GetEntryCount()); - - int seed = static_cast<int>(Time::Now().ToInternalValue()); - srand(seed); - - // kNumKeys is meant to be enough to have about 3x or 4x iterations before - // the process crashes. -#ifdef NDEBUG - const int kNumKeys = 4000; -#else - const int kNumKeys = 1200; -#endif - const int kNumEntries = 30; - std::string keys[kNumKeys]; - disk_cache::Entry* entries[kNumEntries] = {0}; - - for (int i = 0; i < kNumKeys; i++) { - keys[i] = GenerateStressKey(); - } - - const int kSize = 20000; - scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); - memset(buffer->data(), 'k', kSize); - - for (int i = 0;; i++) { - int slot = rand() % kNumEntries; - int key = rand() % kNumKeys; - bool truncate = (rand() % 2 == 0); - int size = kSize - (rand() % 20) * kSize / 20; - - if (entries[slot]) - entries[slot]->Close(); - - net::TestCompletionCallback cb; - rv = cache->OpenEntry(keys[key], &entries[slot], cb.callback()); - if (cb.GetResult(rv) != net::OK) { - rv = cache->CreateEntry(keys[key], &entries[slot], cb.callback()); - CHECK_EQ(net::OK, cb.GetResult(rv)); - } - - base::snprintf(buffer->data(), kSize, - "i: %d iter: %d, size: %d, truncate: %d ", i, iteration, - size, truncate ? 1 : 0); - rv = entries[slot]->WriteData(0, 0, buffer.get(), size, cb.callback(), - truncate); - CHECK_EQ(size, cb.GetResult(rv)); - - if (rand() % 100 > 80) { - key = rand() % kNumKeys; - net::TestCompletionCallback cb2; - rv = cache->DoomEntry(keys[key], cb2.callback()); - cb2.GetResult(rv); - } - - if (!(i % 100)) - printf("Entries: %d \r", i); - } -} - -// We want to prevent the timer thread from killing the process while we are -// waiting for the debugger to attach. -bool g_crashing = false; - -// RunSoon() and CrashCallback() reference each other, unfortunately. -void RunSoon(base::MessageLoop* target_loop); - -void CrashCallback() { - // Keep trying to run. - RunSoon(base::MessageLoop::current()); - - if (g_crashing) - return; - - if (rand() % 100 > 30) { - printf("sweet death...\n"); -#if defined(OS_WIN) - // Windows does more work on _exit() that we would like, so we use Kill. - base::KillProcessById(base::GetCurrentProcId(), kExpectedCrash, false); -#elif defined(OS_POSIX) - // On POSIX, _exit() will terminate the process with minimal cleanup, - // and it is cleaner than killing. - _exit(kExpectedCrash); -#endif - } -} - -void RunSoon(base::MessageLoop* target_loop) { - const base::TimeDelta kTaskDelay = base::TimeDelta::FromSeconds(10); - target_loop->PostDelayedTask( - FROM_HERE, base::Bind(&CrashCallback), kTaskDelay); -} - -// We leak everything here :) -bool StartCrashThread() { - base::Thread* thread = new base::Thread("party_crasher"); - if (!thread->Start()) - return false; - - RunSoon(thread->message_loop()); - return true; -} - -void CrashHandler(const std::string& str) { - g_crashing = true; - base::debug::BreakDebugger(); -} - -bool MessageHandler(int severity, const char* file, int line, - size_t message_start, const std::string& str) { - const size_t kMaxMessageLen = 48; - char message[kMaxMessageLen]; - size_t len = std::min(str.length() - message_start, kMaxMessageLen - 1); - - memcpy(message, str.c_str() + message_start, len); - message[len] = '\0'; -#if !defined(DISK_CACHE_TRACE_TO_LOG) - disk_cache::Trace("%s", message); -#endif - return false; -} - -// ----------------------------------------------------------------------- - -#if defined(OS_WIN) -// {B9A153D4-31C3-48e4-9ABF-D54383F14A0D} -const GUID kStressCacheTraceProviderName = { - 0xb9a153d4, 0x31c3, 0x48e4, - { 0x9a, 0xbf, 0xd5, 0x43, 0x83, 0xf1, 0x4a, 0xd } }; -#endif - -int main(int argc, const char* argv[]) { - // Setup an AtExitManager so Singleton objects will be destructed. - base::AtExitManager at_exit_manager; - - if (argc < 2) - return MasterCode(); - - logging::SetLogAssertHandler(CrashHandler); - logging::SetLogMessageHandler(MessageHandler); - -#if defined(OS_WIN) - logging::LogEventProvider::Initialize(kStressCacheTraceProviderName); -#else - base::CommandLine::Init(argc, argv); - logging::LoggingSettings settings; - settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; - logging::InitLogging(settings); -#endif - - // Some time for the memory manager to flush stuff. - base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(3)); - base::MessageLoopForIO message_loop; - - char* end; - long int iteration = strtol(argv[1], &end, 0); - - if (!StartCrashThread()) { - printf("failed to start thread\n"); - return kError; - } - - StressTheCache(iteration); - return 0; -}
diff --git a/net/dns/mdns_client_impl.cc b/net/dns/mdns_client_impl.cc index 66873abc..3a594d5 100644 --- a/net/dns/mdns_client_impl.cc +++ b/net/dns/mdns_client_impl.cc
@@ -4,13 +4,16 @@ #include "net/dns/mdns_client_impl.h" +#include <algorithm> #include <queue> #include "base/bind.h" #include "base/message_loop/message_loop_proxy.h" #include "base/stl_util.h" +#include "base/time/clock.h" #include "base/time/default_clock.h" #include "base/time/time.h" +#include "base/timer/timer.h" #include "net/base/dns_util.h" #include "net/base/net_errors.h" #include "net/base/net_log.h" @@ -80,9 +83,7 @@ connection_->OnDatagramReceived(&response_, recv_addr_, rv); rv = socket_->RecvFrom( - response_.io_buffer(), - response_.io_buffer()->size(), - &recv_addr_, + response_.io_buffer(), response_.io_buffer()->size(), &recv_addr_, base::Bind(&MDnsConnection::SocketHandler::OnDatagramReceived, base::Unretained(this))); } while (rv > 0); @@ -195,7 +196,10 @@ delegate_->HandlePacket(response, bytes_read); } -MDnsClientImpl::Core::Core() : connection_(new MDnsConnection(this)) { +MDnsClientImpl::Core::Core(base::Clock* clock, base::Timer* timer) + : clock_(clock), + cleanup_timer_(timer), + connection_(new MDnsConnection(this)) { } MDnsClientImpl::Core::~Core() { @@ -241,8 +245,8 @@ for (unsigned i = 0; i < answer_count; i++) { offset = parser.GetOffset(); - scoped_ptr<const RecordParsed> record = RecordParsed::CreateFrom( - &parser, base::Time::Now()); + scoped_ptr<const RecordParsed> record = + RecordParsed::CreateFrom(&parser, clock_->Now()); if (!record) { DVLOG(1) << "Could not understand an mDNS record."; @@ -295,8 +299,7 @@ // Remove all cached records matching the nonexistent RR types. std::vector<const RecordParsed*> records_to_remove; - cache_.FindDnsRecords(0, record->name(), &records_to_remove, - base::Time::Now()); + cache_.FindDnsRecords(0, record->name(), &records_to_remove, clock_->Now()); for (std::vector<const RecordParsed*>::iterator i = records_to_remove.begin(); i != records_to_remove.end(); i++) { @@ -380,25 +383,26 @@ void MDnsClientImpl::Core::ScheduleCleanup(base::Time cleanup) { // Cleanup is already scheduled, no need to do anything. - if (cleanup == scheduled_cleanup_) return; + if (cleanup == scheduled_cleanup_) { + return; + } scheduled_cleanup_ = cleanup; // This cancels the previously scheduled cleanup. - cleanup_callback_.Reset(base::Bind( - &MDnsClientImpl::Core::DoCleanup, base::Unretained(this))); + cleanup_timer_->Stop(); // If |cleanup| is empty, then no cleanup necessary. if (cleanup != base::Time()) { - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - cleanup_callback_.callback(), - cleanup - base::Time::Now()); + cleanup_timer_->Start( + FROM_HERE, std::max(base::TimeDelta(), cleanup - clock_->Now()), + base::Bind(&MDnsClientImpl::Core::DoCleanup, base::Unretained(this))); } } void MDnsClientImpl::Core::DoCleanup() { - cache_.CleanupRecords(base::Time::Now(), base::Bind( - &MDnsClientImpl::Core::OnRecordRemoved, base::Unretained(this))); + cache_.CleanupRecords(clock_->Now(), + base::Bind(&MDnsClientImpl::Core::OnRecordRemoved, + base::Unretained(this))); ScheduleCleanup(cache_.next_expiration()); } @@ -412,10 +416,17 @@ void MDnsClientImpl::Core::QueryCache( uint16 rrtype, const std::string& name, std::vector<const RecordParsed*>* records) const { - cache_.FindDnsRecords(rrtype, name, records, base::Time::Now()); + cache_.FindDnsRecords(rrtype, name, records, clock_->Now()); } -MDnsClientImpl::MDnsClientImpl() { +MDnsClientImpl::MDnsClientImpl() + : clock_(new base::DefaultClock), + cleanup_timer_(new base::Timer(false, false)) { +} + +MDnsClientImpl::MDnsClientImpl(scoped_ptr<base::Clock> clock, + scoped_ptr<base::Timer> timer) + : clock_(clock.Pass()), cleanup_timer_(timer.Pass()) { } MDnsClientImpl::~MDnsClientImpl() { @@ -423,7 +434,7 @@ bool MDnsClientImpl::StartListening(MDnsSocketFactory* socket_factory) { DCHECK(!core_.get()); - core_.reset(new Core()); + core_.reset(new Core(clock_.get(), cleanup_timer_.get())); if (!core_->Init(socket_factory)) { core_.reset(); return false; @@ -444,7 +455,7 @@ const std::string& name, MDnsListener::Delegate* delegate) { return scoped_ptr<net::MDnsListener>( - new MDnsListenerImpl(rrtype, name, delegate, this)); + new MDnsListenerImpl(rrtype, name, clock_.get(), delegate, this)); } scoped_ptr<MDnsTransaction> MDnsClientImpl::CreateTransaction( @@ -456,13 +467,18 @@ new MDnsTransactionImpl(rrtype, name, flags, callback, this)); } -MDnsListenerImpl::MDnsListenerImpl( - uint16 rrtype, - const std::string& name, - MDnsListener::Delegate* delegate, - MDnsClientImpl* client) - : rrtype_(rrtype), name_(name), client_(client), delegate_(delegate), - started_(false), active_refresh_(false) { +MDnsListenerImpl::MDnsListenerImpl(uint16 rrtype, + const std::string& name, + base::Clock* clock, + MDnsListener::Delegate* delegate, + MDnsClientImpl* client) + : rrtype_(rrtype), + name_(name), + clock_(clock), + client_(client), + delegate_(delegate), + started_(false), + active_refresh_(false) { } MDnsListenerImpl::~MDnsListenerImpl() { @@ -571,14 +587,10 @@ kListenerRefreshRatio2 * ttl_)); base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - next_refresh_.callback(), - next_refresh1 - base::Time::Now()); + FROM_HERE, next_refresh_.callback(), next_refresh1 - clock_->Now()); base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - next_refresh_.callback(), - next_refresh2 - base::Time::Now()); + FROM_HERE, next_refresh_.callback(), next_refresh2 - clock_->Now()); } void MDnsListenerImpl::DoRefresh() {
diff --git a/net/dns/mdns_client_impl.h b/net/dns/mdns_client_impl.h index 4ed85f24..a0c5b98 100644 --- a/net/dns/mdns_client_impl.h +++ b/net/dns/mdns_client_impl.h
@@ -6,6 +6,7 @@ #define NET_DNS_MDNS_CLIENT_IMPL_H_ #include <map> +#include <queue> #include <string> #include <utility> #include <vector> @@ -21,11 +22,16 @@ #include "net/udp/udp_server_socket.h" #include "net/udp/udp_socket.h" +namespace base { +class Clock; +class Timer; +} // namespace base + namespace net { class MDnsSocketFactoryImpl : public MDnsSocketFactory { public: - MDnsSocketFactoryImpl() {}; + MDnsSocketFactoryImpl() {} ~MDnsSocketFactoryImpl() override{}; void CreateSockets(ScopedVector<DatagramServerSocket>* sockets) override; @@ -109,7 +115,7 @@ // invalidate the core. class Core : public base::SupportsWeakPtr<Core>, MDnsConnection::Delegate { public: - Core(); + Core(base::Clock* clock, base::Timer* timer); ~Core() override; // Initialize the core. Returns true on success. @@ -132,6 +138,8 @@ void OnConnectionError(int error) override; private: + FRIEND_TEST_ALL_PREFIXES(MDnsTest, CacheCleanupWithShortTTL); + typedef std::pair<std::string, uint16> ListenerKey; typedef std::map<ListenerKey, ObserverList<MDnsListenerImpl>* > ListenerMap; @@ -159,7 +167,8 @@ MDnsCache cache_; - base::CancelableClosure cleanup_callback_; + base::Clock* clock_; + base::Timer* cleanup_timer_; base::Time scheduled_cleanup_; scoped_ptr<MDnsConnection> connection_; @@ -189,7 +198,15 @@ Core* core() { return core_.get(); } private: + FRIEND_TEST_ALL_PREFIXES(MDnsTest, CacheCleanupWithShortTTL); + + // Test constructor, takes a mock clock and mock timer. + MDnsClientImpl(scoped_ptr<base::Clock> clock, + scoped_ptr<base::Timer> cleanup_timer); + scoped_ptr<Core> core_; + scoped_ptr<base::Clock> clock_; + scoped_ptr<base::Timer> cleanup_timer_; DISALLOW_COPY_AND_ASSIGN(MDnsClientImpl); }; @@ -199,6 +216,7 @@ public: MDnsListenerImpl(uint16 rrtype, const std::string& name, + base::Clock* clock, MDnsListener::Delegate* delegate, MDnsClientImpl* client); @@ -229,6 +247,7 @@ uint16 rrtype_; std::string name_; + base::Clock* clock_; MDnsClientImpl* client_; MDnsListener::Delegate* delegate_;
diff --git a/net/dns/mdns_client_unittest.cc b/net/dns/mdns_client_unittest.cc index ba03082..70514f3 100644 --- a/net/dns/mdns_client_unittest.cc +++ b/net/dns/mdns_client_unittest.cc
@@ -6,6 +6,9 @@ #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" +#include "base/time/clock.h" +#include "base/time/default_clock.h" +#include "base/timer/mock_timer.h" #include "net/base/rand_callback.h" #include "net/base/test_completion_callback.h" #include "net/dns/mdns_client_impl.h" @@ -222,6 +225,38 @@ 0xc0, 0x32 }; +const uint8 kSamplePacket3[] = { + // Header + 0x00, 0x00, // ID is zeroed out + 0x81, 0x80, // Standard query response, RA, no error + 0x00, 0x00, // No questions (for simplicity) + 0x00, 0x02, // 2 RRs (answers) + 0x00, 0x00, // 0 authority RRs + 0x00, 0x00, // 0 additional RRs + + // Answer 1 + 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', // + 0x04, '_', 't', 'c', 'p', // + 0x05, 'l', 'o', 'c', 'a', 'l', // + 0x00, 0x00, 0x0c, // TYPE is PTR. + 0x00, 0x01, // CLASS is IN. + 0x00, 0x00, // TTL (4 bytes) is 1 second; + 0x00, 0x01, // + 0x00, 0x08, // RDLENGTH is 8 bytes. + 0x05, 'h', 'e', 'l', 'l', 'o', // + 0xc0, 0x0c, // + + // Answer 2 + 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', // + 0xc0, 0x14, // Pointer to "._tcp.local" + 0x00, 0x0c, // TYPE is PTR. + 0x00, 0x01, // CLASS is IN. + 0x00, 0x00, // TTL (4 bytes) is 3 seconds. + 0x00, 0x03, // + 0x00, 0x08, // RDLENGTH is 8 bytes. + 0x05, 'h', 'e', 'l', 'l', 'o', // + 0xc0, 0x32}; + const uint8 kQueryPacketPrivet[] = { // Header 0x00, 0x00, // ID is zeroed out @@ -389,9 +424,45 @@ int ttl_; }; +class MockClock : public base::DefaultClock { + public: + MockClock() : base::DefaultClock() {} + virtual ~MockClock() {} + + MOCK_METHOD0(Now, base::Time()); + + private: + DISALLOW_COPY_AND_ASSIGN(MockClock); +}; + +class MockTimer : public base::MockTimer { + public: + MockTimer() : base::MockTimer(false, false) {} + ~MockTimer() {} + + void Start(const tracked_objects::Location& posted_from, + base::TimeDelta delay, + const base::Closure& user_task) { + StartObserver(posted_from, delay, user_task); + base::MockTimer::Start(posted_from, delay, user_task); + } + + // StartObserver is invoked when MockTimer::Start() is called. + // Does not replace the behavior of MockTimer::Start(). + MOCK_METHOD3(StartObserver, + void(const tracked_objects::Location& posted_from, + base::TimeDelta delay, + const base::Closure& user_task)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockTimer); +}; + +} // namespace + class MDnsTest : public ::testing::Test { public: - virtual void SetUp() override; + void SetUp() override; void DeleteTransaction(); void DeleteBothListeners(); void RunFor(base::TimeDelta time_period); @@ -403,12 +474,11 @@ MOCK_METHOD2(MockableRecordCallback2, void(MDnsTransaction::Result result, const RecordParsed* record)); - protected: void ExpectPacket(const uint8* packet, unsigned size); void SimulatePacketReceive(const uint8* packet, unsigned size); - MDnsClientImpl test_client_; + scoped_ptr<MDnsClientImpl> test_client_; IPEndPoint mdns_ipv4_endpoint_; StrictMock<MockMDnsSocketFactory> socket_factory_; @@ -429,7 +499,8 @@ }; void MDnsTest::SetUp() { - test_client_.StartListening(&socket_factory_); + test_client_.reset(new MDnsClientImpl()); + test_client_->StartListening(&socket_factory_); } void MDnsTest::SimulatePacketReceive(const uint8* packet, unsigned size) { @@ -471,12 +542,10 @@ PtrRecordCopyContainer record_privet; PtrRecordCopyContainer record_printer; - scoped_ptr<MDnsListener> listener_privet = - test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", - &delegate_privet); - scoped_ptr<MDnsListener> listener_printer = - test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local", - &delegate_printer); + scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener( + dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet); + scoped_ptr<MDnsListener> listener_printer = test_client_->CreateListener( + dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer); ASSERT_TRUE(listener_privet->Start()); ASSERT_TRUE(listener_printer->Start()); @@ -515,9 +584,8 @@ PtrRecordCopyContainer record_privet; PtrRecordCopyContainer record_privet2; - scoped_ptr<MDnsListener> listener_privet = - test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", - &delegate_privet); + scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener( + dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet); ASSERT_TRUE(listener_privet->Start()); @@ -545,14 +613,75 @@ "hello._privet._tcp.local")); } +// Ensure that the cleanup task scheduler won't schedule cleanup tasks in the +// past if the system clock creeps past the expiration time while in the +// cleanup dispatcher. +TEST_F(MDnsTest, CacheCleanupWithShortTTL) { + // Use a nonzero starting time as a base. + base::Time start_time = base::Time() + base::TimeDelta::FromSeconds(1); + + MockClock* clock = new MockClock; + MockTimer* timer = new MockTimer; + + test_client_.reset( + new MDnsClientImpl(make_scoped_ptr(clock), make_scoped_ptr(timer))); + test_client_->StartListening(&socket_factory_); + + EXPECT_CALL(*timer, StartObserver(_, _, _)).Times(1); + EXPECT_CALL(*clock, Now()) + .Times(3) + .WillRepeatedly(Return(start_time)) + .RetiresOnSaturation(); + + // Receive two records with different TTL values. + // TTL(privet)=1.0s + // TTL(printer)=3.0s + StrictMock<MockListenerDelegate> delegate_privet; + StrictMock<MockListenerDelegate> delegate_printer; + + PtrRecordCopyContainer record_privet; + PtrRecordCopyContainer record_printer; + + scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener( + dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet); + scoped_ptr<MDnsListener> listener_printer = test_client_->CreateListener( + dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer); + + ASSERT_TRUE(listener_privet->Start()); + ASSERT_TRUE(listener_printer->Start()); + + EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) + .Times(Exactly(1)); + EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) + .Times(Exactly(1)); + + SimulatePacketReceive(kSamplePacket3, sizeof(kSamplePacket3)); + + EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _)) + .Times(Exactly(1)); + + // Set the clock to 2.0s, which should clean up the 'privet' record, but not + // the printer. The mock clock will change Now() mid-execution from 2s to 4s. + // Note: expectations are FILO-ordered -- t+2 seconds is returned, then t+4. + EXPECT_CALL(*clock, Now()) + .WillOnce(Return(start_time + base::TimeDelta::FromSeconds(4))) + .RetiresOnSaturation(); + EXPECT_CALL(*clock, Now()) + .WillOnce(Return(start_time + base::TimeDelta::FromSeconds(2))) + .RetiresOnSaturation(); + + EXPECT_CALL(*timer, StartObserver(_, base::TimeDelta(), _)); + + timer->Fire(); +} + TEST_F(MDnsTest, MalformedPacket) { StrictMock<MockListenerDelegate> delegate_printer; PtrRecordCopyContainer record_printer; - scoped_ptr<MDnsListener> listener_printer = - test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local", - &delegate_printer); + scoped_ptr<MDnsListener> listener_printer = test_client_->CreateListener( + dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer); ASSERT_TRUE(listener_printer->Start()); @@ -582,11 +711,10 @@ ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); scoped_ptr<MDnsTransaction> transaction_privet = - test_client_.CreateTransaction( + test_client_->CreateTransaction( dns_protocol::kTypePTR, "_privet._tcp.local", - MDnsTransaction::QUERY_NETWORK | - MDnsTransaction::QUERY_CACHE | - MDnsTransaction::SINGLE_RESULT, + MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE | + MDnsTransaction::SINGLE_RESULT, base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this))); @@ -607,10 +735,9 @@ TEST_F(MDnsTest, TransactionCacheOnlyNoResult) { scoped_ptr<MDnsTransaction> transaction_privet = - test_client_.CreateTransaction( + test_client_->CreateTransaction( dns_protocol::kTypePTR, "_privet._tcp.local", - MDnsTransaction::QUERY_CACHE | - MDnsTransaction::SINGLE_RESULT, + MDnsTransaction::QUERY_CACHE | MDnsTransaction::SINGLE_RESULT, base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this))); @@ -624,10 +751,8 @@ TEST_F(MDnsTest, TransactionWithCache) { // Listener to force the client to listen StrictMock<MockListenerDelegate> delegate_irrelevant; - scoped_ptr<MDnsListener> listener_irrelevant = - test_client_.CreateListener(dns_protocol::kTypeA, - "codereview.chromium.local", - &delegate_irrelevant); + scoped_ptr<MDnsListener> listener_irrelevant = test_client_->CreateListener( + dns_protocol::kTypeA, "codereview.chromium.local", &delegate_irrelevant); ASSERT_TRUE(listener_irrelevant->Start()); @@ -641,11 +766,10 @@ &PtrRecordCopyContainer::SaveWithDummyArg)); scoped_ptr<MDnsTransaction> transaction_privet = - test_client_.CreateTransaction( + test_client_->CreateTransaction( dns_protocol::kTypePTR, "_privet._tcp.local", - MDnsTransaction::QUERY_NETWORK | - MDnsTransaction::QUERY_CACHE | - MDnsTransaction::SINGLE_RESULT, + MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE | + MDnsTransaction::SINGLE_RESULT, base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this))); @@ -660,9 +784,8 @@ PtrRecordCopyContainer record_privet; - scoped_ptr<MDnsListener> listener_privet = - test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", - &delegate_privet); + scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener( + dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet); ASSERT_TRUE(listener_privet->Start()); @@ -683,11 +806,10 @@ ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); scoped_ptr<MDnsTransaction> transaction_privet = - test_client_.CreateTransaction( + test_client_->CreateTransaction( dns_protocol::kTypePTR, "_privet._tcp.local", - MDnsTransaction::QUERY_NETWORK | - MDnsTransaction::QUERY_CACHE | - MDnsTransaction::SINGLE_RESULT, + MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE | + MDnsTransaction::SINGLE_RESULT, base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this))); @@ -705,10 +827,9 @@ ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); scoped_ptr<MDnsTransaction> transaction_privet = - test_client_.CreateTransaction( + test_client_->CreateTransaction( dns_protocol::kTypePTR, "_privet._tcp.local", - MDnsTransaction::QUERY_NETWORK | - MDnsTransaction::QUERY_CACHE , + MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE, base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this))); @@ -742,13 +863,11 @@ TEST_F(MDnsTest, TransactionReentrantDelete) { ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); - transaction_ = test_client_.CreateTransaction( + transaction_ = test_client_->CreateTransaction( dns_protocol::kTypePTR, "_privet._tcp.local", - MDnsTransaction::QUERY_NETWORK | - MDnsTransaction::QUERY_CACHE | - MDnsTransaction::SINGLE_RESULT, - base::Bind(&MDnsTest::MockableRecordCallback, - base::Unretained(this))); + MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE | + MDnsTransaction::SINGLE_RESULT, + base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this))); ASSERT_TRUE(transaction_->Start()); @@ -765,19 +884,16 @@ TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) { StrictMock<MockListenerDelegate> delegate_irrelevant; - scoped_ptr<MDnsListener> listener_irrelevant = test_client_.CreateListener( - dns_protocol::kTypeA, "codereview.chromium.local", - &delegate_irrelevant); + scoped_ptr<MDnsListener> listener_irrelevant = test_client_->CreateListener( + dns_protocol::kTypeA, "codereview.chromium.local", &delegate_irrelevant); ASSERT_TRUE(listener_irrelevant->Start()); SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); - transaction_ = test_client_.CreateTransaction( + transaction_ = test_client_->CreateTransaction( dns_protocol::kTypePTR, "_privet._tcp.local", - MDnsTransaction::QUERY_NETWORK | - MDnsTransaction::QUERY_CACHE, - base::Bind(&MDnsTest::MockableRecordCallback, - base::Unretained(this))); + MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE, + base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this))); EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _)) .Times(Exactly(1)) @@ -791,22 +907,16 @@ TEST_F(MDnsTest, TransactionReentrantCacheLookupStart) { ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); - scoped_ptr<MDnsTransaction> transaction1 = - test_client_.CreateTransaction( - dns_protocol::kTypePTR, "_privet._tcp.local", - MDnsTransaction::QUERY_NETWORK | - MDnsTransaction::QUERY_CACHE | + scoped_ptr<MDnsTransaction> transaction1 = test_client_->CreateTransaction( + dns_protocol::kTypePTR, "_privet._tcp.local", + MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE | MDnsTransaction::SINGLE_RESULT, - base::Bind(&MDnsTest::MockableRecordCallback, - base::Unretained(this))); + base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this))); - scoped_ptr<MDnsTransaction> transaction2 = - test_client_.CreateTransaction( - dns_protocol::kTypePTR, "_printer._tcp.local", - MDnsTransaction::QUERY_CACHE | - MDnsTransaction::SINGLE_RESULT, - base::Bind(&MDnsTest::MockableRecordCallback2, - base::Unretained(this))); + scoped_ptr<MDnsTransaction> transaction2 = test_client_->CreateTransaction( + dns_protocol::kTypePTR, "_printer._tcp.local", + MDnsTransaction::QUERY_CACHE | MDnsTransaction::SINGLE_RESULT, + base::Bind(&MDnsTest::MockableRecordCallback2, base::Unretained(this))); EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD, _)) @@ -826,7 +936,7 @@ TEST_F(MDnsTest, GoodbyePacketNotification) { StrictMock<MockListenerDelegate> delegate_privet; - scoped_ptr<MDnsListener> listener_privet = test_client_.CreateListener( + scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener( dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet); ASSERT_TRUE(listener_privet->Start()); @@ -838,9 +948,8 @@ TEST_F(MDnsTest, GoodbyePacketRemoval) { StrictMock<MockListenerDelegate> delegate_privet; - scoped_ptr<MDnsListener> listener_privet = - test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", - &delegate_privet); + scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener( + dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet); ASSERT_TRUE(listener_privet->Start()); EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) @@ -863,13 +972,11 @@ TEST_F(MDnsTest, ListenerReentrantDelete) { StrictMock<MockListenerDelegate> delegate_privet; - listener1_ = test_client_.CreateListener(dns_protocol::kTypePTR, - "_privet._tcp.local", - &delegate_privet); + listener1_ = test_client_->CreateListener( + dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet); - listener2_ = test_client_.CreateListener(dns_protocol::kTypePTR, - "_privet._tcp.local", - &delegate_privet); + listener2_ = test_client_->CreateListener( + dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet); ASSERT_TRUE(listener1_->Start()); @@ -896,9 +1003,8 @@ IPAddressNumber address; StrictMock<MockListenerDelegate> delegate_privet; - scoped_ptr<MDnsListener> listener_privet = - test_client_.CreateListener(dns_protocol::kTypeA, "privet.local", - &delegate_privet); + scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener( + dns_protocol::kTypeA, "privet.local", &delegate_privet); ASSERT_TRUE(listener_privet->Start()); @@ -914,16 +1020,14 @@ TEST_F(MDnsTest, NsecWithListener) { StrictMock<MockListenerDelegate> delegate_privet; - scoped_ptr<MDnsListener> listener_privet = - test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local", - &delegate_privet); + scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener( + dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet); // Test to make sure nsec callback is NOT called for PTR // (which is marked as existing). StrictMock<MockListenerDelegate> delegate_privet2; - scoped_ptr<MDnsListener> listener_privet2 = - test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", - &delegate_privet2); + scoped_ptr<MDnsListener> listener_privet2 = test_client_->CreateListener( + dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet2); ASSERT_TRUE(listener_privet->Start()); @@ -936,11 +1040,10 @@ TEST_F(MDnsTest, NsecWithTransactionFromNetwork) { scoped_ptr<MDnsTransaction> transaction_privet = - test_client_.CreateTransaction( + test_client_->CreateTransaction( dns_protocol::kTypeA, "_privet._tcp.local", - MDnsTransaction::QUERY_NETWORK | - MDnsTransaction::QUERY_CACHE | - MDnsTransaction::SINGLE_RESULT, + MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE | + MDnsTransaction::SINGLE_RESULT, base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this))); @@ -958,9 +1061,8 @@ TEST_F(MDnsTest, NsecWithTransactionFromCache) { // Force mDNS to listen. StrictMock<MockListenerDelegate> delegate_irrelevant; - scoped_ptr<MDnsListener> listener_irrelevant = - test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", - &delegate_irrelevant); + scoped_ptr<MDnsListener> listener_irrelevant = test_client_->CreateListener( + dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_irrelevant); listener_irrelevant->Start(); SimulatePacketReceive(kSamplePacketNsec, @@ -970,11 +1072,10 @@ MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL)); scoped_ptr<MDnsTransaction> transaction_privet_a = - test_client_.CreateTransaction( + test_client_->CreateTransaction( dns_protocol::kTypeA, "_privet._tcp.local", - MDnsTransaction::QUERY_NETWORK | - MDnsTransaction::QUERY_CACHE | - MDnsTransaction::SINGLE_RESULT, + MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE | + MDnsTransaction::SINGLE_RESULT, base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this))); @@ -984,11 +1085,10 @@ // valid answer to the query scoped_ptr<MDnsTransaction> transaction_privet_ptr = - test_client_.CreateTransaction( + test_client_->CreateTransaction( dns_protocol::kTypePTR, "_privet._tcp.local", - MDnsTransaction::QUERY_NETWORK | - MDnsTransaction::QUERY_CACHE | - MDnsTransaction::SINGLE_RESULT, + MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE | + MDnsTransaction::SINGLE_RESULT, base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this))); @@ -999,9 +1099,8 @@ TEST_F(MDnsTest, NsecConflictRemoval) { StrictMock<MockListenerDelegate> delegate_privet; - scoped_ptr<MDnsListener> listener_privet = - test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local", - &delegate_privet); + scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener( + dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet); ASSERT_TRUE(listener_privet->Start()); @@ -1029,9 +1128,8 @@ TEST_F(MDnsTest, RefreshQuery) { StrictMock<MockListenerDelegate> delegate_privet; - scoped_ptr<MDnsListener> listener_privet = - test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local", - &delegate_privet); + scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener( + dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet); listener_privet->SetActiveRefresh(true); ASSERT_TRUE(listener_privet->Start()); @@ -1087,7 +1185,7 @@ protected: // Follow successful connection initialization. - virtual void SetUp() override { + void SetUp() override { socket_ipv4_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV4); socket_ipv6_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV6); factory_.PushSocket(socket_ipv6_); @@ -1219,6 +1317,4 @@ callback.Run(OK); } -} // namespace - } // namespace net
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index a677825..d6aa6e2 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc
@@ -90,9 +90,7 @@ enable_quic_port_selection(true), quic_always_require_handshake_confirmation(false), quic_disable_connection_pooling(false), - quic_load_server_info_timeout_ms(0), - quic_load_server_info_timeout_srtt_multiplier(0.0f), - quic_enable_truncated_connection_ids(false), + quic_load_server_info_timeout_srtt_multiplier(0.25f), quic_enable_connection_racing(false), quic_enable_non_blocking_io(false), quic_disable_disk_cache(false), @@ -139,9 +137,7 @@ params.enable_quic_port_selection, params.quic_always_require_handshake_confirmation, params.quic_disable_connection_pooling, - params.quic_load_server_info_timeout_ms, params.quic_load_server_info_timeout_srtt_multiplier, - params.quic_enable_truncated_connection_ids, params.quic_enable_connection_racing, params.quic_enable_non_blocking_io, params.quic_disable_disk_cache,
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index 98c5ed8..07a3546 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h
@@ -117,9 +117,7 @@ bool enable_quic_port_selection; bool quic_always_require_handshake_confirmation; bool quic_disable_connection_pooling; - int quic_load_server_info_timeout_ms; float quic_load_server_info_timeout_srtt_multiplier; - bool quic_enable_truncated_connection_ids; bool quic_enable_connection_racing; bool quic_enable_non_blocking_io; bool quic_disable_disk_cache;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 6e1ad43..727ef70 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc
@@ -2372,7 +2372,125 @@ // Test the request-challenge-retry sequence for basic auth, over a connection // that requires a restart when setting up an SSL tunnel. -TEST_P(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) { +TEST_P(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp10) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.google.com/"); + // when the no authentication data flag is set. + request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; + + // Configure against proxy server "myproxy:70". + session_deps_.proxy_service.reset( + ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); + CapturingBoundNetLog log; + session_deps_.net_log = log.bound().net_log(); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + + // Since we have proxy, should try to establish tunnel. + MockWrite data_writes1[] = { + MockWrite( + "CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + + // After calling trans->RestartWithAuth(), this is the request we should + // be issuing -- the final header line contains the credentials. + MockWrite( + "CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + + MockWrite( + "GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + + // The proxy responds to the connect with a 407, using a persistent + // connection. + MockRead data_reads1[] = { + // No credentials. + MockRead("HTTP/1.0 407 Proxy Authentication Required\r\n"), + MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n"), + + MockRead("HTTP/1.0 200 Connection Established\r\n\r\n"), + + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), + MockRead("Content-Length: 5\r\n\r\n"), + MockRead(SYNCHRONOUS, "hello"), + }; + + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), + data_writes1, arraysize(data_writes1)); + session_deps_.socket_factory->AddSocketDataProvider(&data1); + SSLSocketDataProvider ssl(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); + + TestCompletionCallback callback1; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); + + int rv = trans->Start(&request, callback1.callback(), log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback1.WaitForResult(); + EXPECT_EQ(OK, rv); + net::CapturingNetLog::CapturedEntryList entries; + log.GetEntries(&entries); + size_t pos = ExpectLogContainsSomewhere( + entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, + NetLog::PHASE_NONE); + ExpectLogContainsSomewhere( + entries, pos, NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, + NetLog::PHASE_NONE); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response != NULL); + EXPECT_FALSE(response->headers->IsKeepAlive()); + ASSERT_FALSE(response->headers.get() == NULL); + EXPECT_EQ(407, response->headers->response_code()); + EXPECT_TRUE(HttpVersion(1, 0) == response->headers->GetHttpVersion()); + EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); + + LoadTimingInfo load_timing_info; + // CONNECT requests and responses are handled at the connect job level, so + // the transaction does not yet have a connection. + EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info)); + + TestCompletionCallback callback2; + + rv = + trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback2.WaitForResult(); + EXPECT_EQ(OK, rv); + + response = trans->GetResponseInfo(); + ASSERT_TRUE(response != NULL); + + EXPECT_TRUE(response->headers->IsKeepAlive()); + EXPECT_EQ(200, response->headers->response_code()); + EXPECT_EQ(5, response->headers->GetContentLength()); + EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); + + // The password prompt info should not be set. + EXPECT_TRUE(response->auth_challenge.get() == NULL); + + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + + trans.reset(); + session->CloseAllConnections(); +} + +// Test the request-challenge-retry sequence for basic auth, over a connection +// that requires a restart when setting up an SSL tunnel. +TEST_P(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp11) { HttpRequestInfo request; request.method = "GET"; request.url = GURL("https://www.google.com/"); @@ -2448,6 +2566,7 @@ const HttpResponseInfo* response = trans->GetResponseInfo(); ASSERT_TRUE(response != NULL); + EXPECT_FALSE(response->headers->IsKeepAlive()); ASSERT_FALSE(response->headers.get() == NULL); EXPECT_EQ(407, response->headers->response_code()); EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); @@ -2487,8 +2606,115 @@ } // Test the request-challenge-retry sequence for basic auth, over a keep-alive -// proxy connection, when setting up an SSL tunnel. -TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) { +// proxy connection with HTTP/1.0 responses, when setting up an SSL tunnel. +TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp10) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.google.com/"); + // Ensure that proxy authentication is attempted even + // when the no authentication data flag is set. + request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; + + // Configure against proxy server "myproxy:70". + session_deps_.proxy_service.reset(ProxyService::CreateFixed("myproxy:70")); + CapturingBoundNetLog log; + session_deps_.net_log = log.bound().net_log(); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); + + // Since we have proxy, should try to establish tunnel. + MockWrite data_writes1[] = { + MockWrite( + "CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + + // After calling trans->RestartWithAuth(), this is the request we should + // be issuing -- the final header line contains the credentials. + MockWrite( + "CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), + }; + + // The proxy responds to the connect with a 407, using a persistent + // connection. (Since it's HTTP/1.0, keep-alive has to be explicit.) + MockRead data_reads1[] = { + // No credentials. + MockRead("HTTP/1.0 407 Proxy Authentication Required\r\n"), + MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), + MockRead("Proxy-Connection: keep-alive\r\n"), + MockRead("Content-Length: 10\r\n\r\n"), + MockRead("0123456789"), + + // Wrong credentials (wrong password). + MockRead("HTTP/1.0 407 Proxy Authentication Required\r\n"), + MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), + MockRead("Proxy-Connection: keep-alive\r\n"), + MockRead("Content-Length: 10\r\n\r\n"), + // No response body because the test stops reading here. + MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. + }; + + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), + data_writes1, arraysize(data_writes1)); + session_deps_.socket_factory->AddSocketDataProvider(&data1); + + TestCompletionCallback callback1; + + int rv = trans->Start(&request, callback1.callback(), log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback1.WaitForResult(); + EXPECT_EQ(OK, rv); + net::CapturingNetLog::CapturedEntryList entries; + log.GetEntries(&entries); + size_t pos = ExpectLogContainsSomewhere( + entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, + NetLog::PHASE_NONE); + ExpectLogContainsSomewhere( + entries, pos, NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, + NetLog::PHASE_NONE); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + ASSERT_TRUE(response->headers); + EXPECT_TRUE(response->headers->IsKeepAlive()); + EXPECT_EQ(407, response->headers->response_code()); + EXPECT_EQ(10, response->headers->GetContentLength()); + EXPECT_TRUE(HttpVersion(1, 0) == response->headers->GetHttpVersion()); + EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); + + TestCompletionCallback callback2; + + // Wrong password (should be "bar"). + rv = + trans->RestartWithAuth(AuthCredentials(kFoo, kBaz), callback2.callback()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback2.WaitForResult(); + EXPECT_EQ(OK, rv); + + response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + ASSERT_TRUE(response->headers); + EXPECT_TRUE(response->headers->IsKeepAlive()); + EXPECT_EQ(407, response->headers->response_code()); + EXPECT_EQ(10, response->headers->GetContentLength()); + EXPECT_TRUE(HttpVersion(1, 0) == response->headers->GetHttpVersion()); + EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); + + // Flush the idle socket before the NetLog and HttpNetworkTransaction go + // out of scope. + session->CloseAllConnections(); +} + +// Test the request-challenge-retry sequence for basic auth, over a keep-alive +// proxy connection with HTTP/1.1 responses, when setting up an SSL tunnel. +TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp11) { HttpRequestInfo request; request.method = "GET"; request.url = GURL("https://www.google.com/"); @@ -2562,7 +2788,7 @@ ASSERT_TRUE(response->headers); EXPECT_TRUE(response->headers->IsKeepAlive()); EXPECT_EQ(407, response->headers->response_code()); - EXPECT_EQ(-1, response->headers->GetContentLength()); + EXPECT_EQ(10, response->headers->GetContentLength()); EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); @@ -2581,7 +2807,7 @@ ASSERT_TRUE(response->headers); EXPECT_TRUE(response->headers->IsKeepAlive()); EXPECT_EQ(407, response->headers->response_code()); - EXPECT_EQ(-1, response->headers->GetContentLength()); + EXPECT_EQ(10, response->headers->GetContentLength()); EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get()));
diff --git a/net/http/proxy_client_socket.cc b/net/http/proxy_client_socket.cc index 3c539c6..3c0d12d 100644 --- a/net/http/proxy_client_socket.cc +++ b/net/http/proxy_client_socket.cc
@@ -95,9 +95,19 @@ scoped_refptr<HttpResponseHeaders> new_headers = new HttpResponseHeaders( HttpUtil::AssembleRawHeaders(kHeaders, arraysize(kHeaders))); + // Copy status line and all hop-by-hop headers to preserve keep-alive + // behavior. new_headers->ReplaceStatusLine(old_headers->GetStatusLine()); - CopyHeaderValues(old_headers, new_headers, "Connection"); - CopyHeaderValues(old_headers, new_headers, "Proxy-Authenticate"); + CopyHeaderValues(old_headers, new_headers, "connection"); + CopyHeaderValues(old_headers, new_headers, "proxy-connection"); + CopyHeaderValues(old_headers, new_headers, "keep-alive"); + CopyHeaderValues(old_headers, new_headers, "trailer"); + CopyHeaderValues(old_headers, new_headers, "transfer-encoding"); + CopyHeaderValues(old_headers, new_headers, "upgrade"); + + CopyHeaderValues(old_headers, new_headers, "content-length"); + + CopyHeaderValues(old_headers, new_headers, "proxy-authenticate"); response->headers = new_headers; return true;
diff --git a/net/net.gyp b/net/net.gyp index 569147cad..2677239 100644 --- a/net/net.gyp +++ b/net/net.gyp
@@ -1470,7 +1470,7 @@ 'net_test_support', ], 'sources': [ - 'disk_cache/blockfile/stress_cache.cc', + 'tools/stress_cache/stress_cache.cc', ], # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. 'msvs_disabled_warnings': [4267, ],
diff --git a/net/net.gypi b/net/net.gypi index 7443d97..796d43d 100644 --- a/net/net.gypi +++ b/net/net.gypi
@@ -1335,6 +1335,7 @@ 'disk_cache/blockfile/block_files_unittest.cc', 'disk_cache/blockfile/index_table_v3_unittest.cc', 'disk_cache/blockfile/mapped_file_unittest.cc', + 'disk_cache/blockfile/stats_unittest.cc', 'disk_cache/blockfile/storage_block_unittest.cc', 'disk_cache/cache_util_unittest.cc', 'disk_cache/entry_unittest.cc', @@ -1678,8 +1679,6 @@ 'test/run_all_unittests.cc', 'test/scoped_disable_exit_on_dfatal.cc', 'test/scoped_disable_exit_on_dfatal.h', - 'test/scoped_mock_log.cc', - 'test/scoped_mock_log.h', 'test/test_certificate_data.h', 'tools/balsa/balsa_frame_test.cc', 'tools/balsa/balsa_headers_test.cc', @@ -1761,8 +1760,6 @@ 'tools/quic/test_tools/quic_server_peer.h', 'tools/quic/test_tools/quic_test_client.cc', 'tools/quic/test_tools/quic_test_client.h', - 'tools/quic/test_tools/quic_test_server.cc', - 'tools/quic/test_tools/quic_test_server.h', 'tools/quic/test_tools/quic_test_utils.cc', 'tools/quic/test_tools/quic_test_utils.h', 'tools/quic/test_tools/server_thread.cc',
diff --git a/net/proxy/proxy_config_service_win.cc b/net/proxy/proxy_config_service_win.cc index c0c5129f..e75fa39 100644 --- a/net/proxy/proxy_config_service_win.cc +++ b/net/proxy/proxy_config_service_win.cc
@@ -11,9 +11,10 @@ #include "base/bind_helpers.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "base/profiler/scoped_tracker.h" #include "base/stl_util.h" -#include "base/strings/string_util.h" #include "base/strings/string_tokenizer.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_restrictions.h" #include "base/win/registry.h" @@ -62,6 +63,11 @@ } void ProxyConfigServiceWin::StartWatchingRegistryForChanges() { + // TODO(eroman): Remove once crbug.com/454983 is solved. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "454983 ProxyConfigServiceWin::StartWatchingRegistryForChanges")); + if (!keys_to_watch_.empty()) return; // Already initialized.
diff --git a/net/proxy/proxy_script_decider.cc b/net/proxy/proxy_script_decider.cc index 7e5544a..3d830fc 100644 --- a/net/proxy/proxy_script_decider.cc +++ b/net/proxy/proxy_script_decider.cc
@@ -476,7 +476,6 @@ proxy_script_fetcher_->Cancel(); break; default: - NOTREACHED(); break; }
diff --git a/net/proxy/proxy_script_decider_unittest.cc b/net/proxy/proxy_script_decider_unittest.cc index 8914f5b..f26e5e1 100644 --- a/net/proxy/proxy_script_decider_unittest.cc +++ b/net/proxy/proxy_script_decider_unittest.cc
@@ -428,6 +428,16 @@ EXPECT_EQ(rule.url, decider_->effective_config().pac_url()); } +// Regression test for http://crbug.com/409698. +// This test lets the state machine get into state QUICK_CHECK_COMPLETE, then +// destroys the decider, causing a cancel. +TEST_F(ProxyScriptDeciderQuickCheckTest, CancelPartway) { + resolver_.set_synchronous_mode(false); + resolver_.set_ondemand_mode(true); + EXPECT_EQ(ERR_IO_PENDING, StartDecider()); + decider_.reset(NULL); +} + // Fails at WPAD (downloading), but succeeds in choosing the custom PAC. TEST(ProxyScriptDeciderTest, AutodetectFailCustomSuccess1) { Rules rules;
diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc index cd6e376..9e20db6 100644 --- a/net/proxy/proxy_service.cc +++ b/net/proxy/proxy_service.cc
@@ -904,6 +904,9 @@ stall_proxy_auto_config_delay_(TimeDelta::FromMilliseconds( kDelayAfterNetworkChangesMs)), quick_check_enabled_(true) { + // TODO(eroman): Remove once crbug.com/454983 is solved. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION("454983 ProxyService::ProxyService")); NetworkChangeNotifier::AddIPAddressObserver(this); NetworkChangeNotifier::AddDNSObserver(this); ResetConfigService(config_service); @@ -1421,6 +1424,11 @@ void ProxyService::ResetConfigService( ProxyConfigService* new_proxy_config_service) { + // TODO(eroman): Remove once crbug.com/454983 is solved. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "454983 ProxyService::ResetConfigService")); + DCHECK(CalledOnValidThread()); State previous_state = ResetProxyConfig(true);
diff --git a/net/quic/congestion_control/prr_sender.cc b/net/quic/congestion_control/prr_sender.cc index 588a2fe0..51b32d3 100644 --- a/net/quic/congestion_control/prr_sender.cc +++ b/net/quic/congestion_control/prr_sender.cc
@@ -39,7 +39,7 @@ QuicTime::Delta PrrSender::TimeUntilSend( QuicByteCount congestion_window, QuicByteCount bytes_in_flight, - QuicPacketCount slowstart_threshold) const { + QuicByteCount slowstart_threshold) const { // Return QuicTime::Zero In order to ensure limited transmit always works. if (bytes_sent_since_loss_ == 0 || bytes_in_flight < kMaxSegmentSize) { return QuicTime::Delta::Zero(); @@ -50,7 +50,7 @@ // when more packets are lost than the CWND reduction. // limit = MAX(prr_delivered - prr_out, DeliveredData) + MSS if (bytes_delivered_since_loss_ + ack_count_since_loss_ * kMaxSegmentSize <= - bytes_sent_since_loss_) { + bytes_sent_since_loss_) { return QuicTime::Delta::Infinite(); } return QuicTime::Delta::Zero(); @@ -59,8 +59,8 @@ // Checks a simplified version of the PRR formula that doesn't use division: // AvailableSendWindow = // CEIL(prr_delivered * ssthresh / BytesInFlightAtLoss) - prr_sent - if (bytes_delivered_since_loss_ * slowstart_threshold * kMaxSegmentSize > - bytes_sent_since_loss_ * bytes_in_flight_before_loss_) { + if (bytes_delivered_since_loss_ * slowstart_threshold > + bytes_sent_since_loss_ * bytes_in_flight_before_loss_) { return QuicTime::Delta::Zero(); } return QuicTime::Delta::Infinite();
diff --git a/net/quic/congestion_control/prr_sender.h b/net/quic/congestion_control/prr_sender.h index 495943d..c783668 100644 --- a/net/quic/congestion_control/prr_sender.h +++ b/net/quic/congestion_control/prr_sender.h
@@ -23,8 +23,7 @@ void OnPacketAcked(QuicByteCount acked_bytes); QuicTime::Delta TimeUntilSend(QuicByteCount congestion_window, QuicByteCount bytes_in_flight, - QuicPacketCount slowstart_threshold) - const; + QuicByteCount slowstart_threshold) const; private: // Bytes sent and acked since the last loss event.
diff --git a/net/quic/congestion_control/prr_sender_test.cc b/net/quic/congestion_control/prr_sender_test.cc index 7a42bd56..ed8397f 100644 --- a/net/quic/congestion_control/prr_sender_test.cc +++ b/net/quic/congestion_control/prr_sender_test.cc
@@ -35,13 +35,13 @@ bytes_in_flight -= kMaxSegmentSize; EXPECT_EQ(QuicTime::Delta::Zero(), prr.TimeUntilSend(congestion_window, bytes_in_flight, - ssthresh_after_loss)); + ssthresh_after_loss * kMaxSegmentSize)); // Send retransmission. prr.OnPacketSent(kMaxSegmentSize); // PRR shouldn't allow sending any more packets. EXPECT_EQ(QuicTime::Delta::Infinite(), prr.TimeUntilSend(congestion_window, bytes_in_flight, - ssthresh_after_loss)); + ssthresh_after_loss * kMaxSegmentSize)); // One packet is lost, and one ack was consumed above. PRR now paces // transmissions through the remaining 48 acks. PRR will alternatively @@ -52,13 +52,13 @@ bytes_in_flight -= kMaxSegmentSize; EXPECT_EQ(QuicTime::Delta::Infinite(), prr.TimeUntilSend(congestion_window, bytes_in_flight, - ssthresh_after_loss)); + ssthresh_after_loss * kMaxSegmentSize)); // Ack another packet. PRR should now allow sending a packet in response. prr.OnPacketAcked(kMaxSegmentSize); bytes_in_flight -= kMaxSegmentSize; EXPECT_EQ(QuicTime::Delta::Zero(), prr.TimeUntilSend(congestion_window, bytes_in_flight, - ssthresh_after_loss)); + ssthresh_after_loss * kMaxSegmentSize)); // Send a packet in response. prr.OnPacketSent(kMaxSegmentSize); bytes_in_flight += kMaxSegmentSize; @@ -73,7 +73,7 @@ bytes_in_flight -= kMaxSegmentSize; EXPECT_EQ(QuicTime::Delta::Zero(), prr.TimeUntilSend(congestion_window, bytes_in_flight, - ssthresh_after_loss)); + ssthresh_after_loss * kMaxSegmentSize)); // Send a packet in response, since PRR allows it. prr.OnPacketSent(kMaxSegmentSize); bytes_in_flight += kMaxSegmentSize; @@ -83,7 +83,7 @@ EXPECT_EQ(congestion_window, bytes_in_flight); EXPECT_EQ(QuicTime::Delta::Infinite(), prr.TimeUntilSend(congestion_window, bytes_in_flight, - ssthresh_after_loss)); + ssthresh_after_loss * kMaxSegmentSize)); } } @@ -106,7 +106,7 @@ for (int j = 0; j < 2; ++j) { EXPECT_EQ(QuicTime::Delta::Zero(), prr.TimeUntilSend(congestion_window, bytes_in_flight, - ssthresh_after_loss)); + ssthresh_after_loss * kMaxSegmentSize)); // Send a packet in response. prr.OnPacketSent(kMaxSegmentSize); bytes_in_flight += kMaxSegmentSize; @@ -114,7 +114,7 @@ // PRR should allow no more than 2 packets in response to an ack. EXPECT_EQ(QuicTime::Delta::Infinite(), prr.TimeUntilSend(congestion_window, bytes_in_flight, - ssthresh_after_loss)); + ssthresh_after_loss * kMaxSegmentSize)); } // Out of SSRB mode, PRR allows one send in response to each ack. @@ -123,7 +123,7 @@ bytes_in_flight -= kMaxSegmentSize; EXPECT_EQ(QuicTime::Delta::Zero(), prr.TimeUntilSend(congestion_window, bytes_in_flight, - ssthresh_after_loss)); + ssthresh_after_loss * kMaxSegmentSize)); // Send a packet in response. prr.OnPacketSent(kMaxSegmentSize); bytes_in_flight += kMaxSegmentSize;
diff --git a/net/quic/congestion_control/rtt_stats.h b/net/quic/congestion_control/rtt_stats.h index 3d256d9..a14cfcb 100644 --- a/net/quic/congestion_control/rtt_stats.h +++ b/net/quic/congestion_control/rtt_stats.h
@@ -23,9 +23,6 @@ public: RttStats(); - // Returns true if any RTT measurements have been made. - bool HasUpdates() const; - // Updates the RTT from an incoming ack which is received |send_delta| after // the packet is sent and the peer reports the ack being delayed |ack_delay|. void UpdateRtt(QuicTime::Delta send_delta,
diff --git a/net/quic/congestion_control/rtt_stats_test.cc b/net/quic/congestion_control/rtt_stats_test.cc index 6aaf2a6..7fc07a35 100644 --- a/net/quic/congestion_control/rtt_stats_test.cc +++ b/net/quic/congestion_control/rtt_stats_test.cc
@@ -7,7 +7,7 @@ #include <vector> #include "base/logging.h" -#include "net/test/scoped_mock_log.h" +#include "base/test/mock_log.h" #include "testing/gtest/include/gtest/gtest.h" using logging::LOG_WARNING; @@ -226,7 +226,7 @@ TEST_F(RttStatsTest, UpdateRttWithBadSendDeltas) { // Make sure we ignore bad RTTs. - ScopedMockLog log; + base::test::MockLog log; QuicTime::Delta initial_rtt = QuicTime::Delta::FromMilliseconds(10); rtt_stats_.UpdateRtt(initial_rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
diff --git a/net/quic/congestion_control/send_algorithm_interface.cc b/net/quic/congestion_control/send_algorithm_interface.cc index 82f1135..deeaf8c 100644 --- a/net/quic/congestion_control/send_algorithm_interface.cc +++ b/net/quic/congestion_control/send_algorithm_interface.cc
@@ -21,17 +21,15 @@ switch (congestion_control_type) { case kCubic: return new TcpCubicSender(clock, rtt_stats, false /* don't use Reno */, - initial_congestion_window, - kMaxTcpCongestionWindow, stats); + initial_congestion_window, stats); case kReno: return new TcpCubicSender(clock, rtt_stats, true /* use Reno */, - initial_congestion_window, - kMaxTcpCongestionWindow, stats); + initial_congestion_window, stats); case kBBR: // TODO(rtenneti): Enable BbrTcpSender. #if 0 return new BbrTcpSender(clock, rtt_stats, initial_congestion_window, - kMaxTcpCongestionWindow, stats); + stats); #endif LOG(DFATAL) << "BbrTcpSender is not supported."; return nullptr;
diff --git a/net/quic/congestion_control/send_algorithm_simulator.cc b/net/quic/congestion_control/send_algorithm_simulator.cc index 3d6d456..64f0ee1 100644 --- a/net/quic/congestion_control/send_algorithm_simulator.cc +++ b/net/quic/congestion_control/send_algorithm_simulator.cc
@@ -387,9 +387,4 @@ transfer->bytes_in_flight += kPacketSize; } -// Advance the time by |delta| without sending anything. -void SendAlgorithmSimulator::AdvanceTime(QuicTime::Delta delta) { - clock_->AdvanceTime(delta); -} - } // namespace net
diff --git a/net/quic/congestion_control/send_algorithm_simulator.h b/net/quic/congestion_control/send_algorithm_simulator.h index 2685d23..50e78f35 100644 --- a/net/quic/congestion_control/send_algorithm_simulator.h +++ b/net/quic/congestion_control/send_algorithm_simulator.h
@@ -122,6 +122,7 @@ QuicTime::Delta rtt); ~SendAlgorithmSimulator(); + // For local ad-hoc testing. void set_bandwidth(QuicBandwidth bandwidth) { bandwidth_ = bandwidth; } @@ -131,11 +132,13 @@ forward_loss_rate_ = loss_rate; } + // For local ad-hoc testing. void set_reverse_loss_rate(float loss_rate) { DCHECK_LT(loss_rate, 1.0f); reverse_loss_rate_ = loss_rate; } + // For local ad-hoc testing. void set_loss_correlation(float loss_correlation) { DCHECK_LT(loss_correlation, 1.0f); loss_correlation_ = loss_correlation; @@ -150,6 +153,7 @@ } // Advance the time by |delta| without sending anything. + // For local ad-hoc testing. void AdvanceTime(QuicTime::Delta delta); // Adds a pending sender. The send will run when TransferBytes is called.
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc index 4d77451..6cfe0fb 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -31,7 +31,6 @@ const RttStats* rtt_stats, bool reno, QuicPacketCount initial_tcp_congestion_window, - QuicPacketCount max_tcp_congestion_window, QuicConnectionStats* stats) : hybrid_slow_start_(clock), cubic_(clock), @@ -39,14 +38,13 @@ stats_(stats), reno_(reno), num_connections_(kDefaultNumConnections), - congestion_window_count_(0), + num_acked_packets_(0), largest_sent_sequence_number_(0), largest_acked_sequence_number_(0), largest_sent_at_last_cutback_(0), congestion_window_(initial_tcp_congestion_window), - slowstart_threshold_(max_tcp_congestion_window), + slowstart_threshold_(std::numeric_limits<uint64>::max()), last_cutback_exited_slowstart_(false), - max_tcp_congestion_window_(max_tcp_congestion_window), clock_(clock) { } @@ -89,8 +87,9 @@ // Make sure CWND is in appropriate range (in case of bad data). QuicPacketCount new_congestion_window = bandwidth.ToBytesPerPeriod(rtt_ms) / kMaxPacketSize; - congestion_window_ = max(min(new_congestion_window, kMaxTcpCongestionWindow), - kMinCongestionWindowForBandwidthResumption); + congestion_window_ = max( + min(new_congestion_window, kMaxCongestionWindowForBandwidthResumption), + kMinCongestionWindowForBandwidthResumption); // TODO(rjshade): Set appropriate CWND when previous connection was in slow // start at time of estimate. @@ -181,7 +180,7 @@ largest_sent_at_last_cutback_ = largest_sent_sequence_number_; // reset packet count from congestion avoidance mode. We start // counting again when we're out of recovery. - congestion_window_count_ = 0; + num_acked_packets_ = 0; DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ << " slowstart threshold: " << slowstart_threshold_; } @@ -216,7 +215,7 @@ if (InRecovery()) { // PRR is used when in recovery. return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight, - slowstart_threshold_); + slowstart_threshold_ * kMaxSegmentSize); } if (GetCongestionWindow() > bytes_in_flight) { return QuicTime::Delta::Zero(); @@ -302,36 +301,29 @@ return; } if (InSlowStart()) { - // congestion_window_cnt is the number of acks since last change of snd_cwnd - if (congestion_window_ < max_tcp_congestion_window_) { - // TCP slow start, exponential growth, increase by one for each ACK. - ++congestion_window_; - } + // TCP slow start, exponential growth, increase by one for each ACK. + ++congestion_window_; DVLOG(1) << "Slow start; congestion window: " << congestion_window_ << " slowstart threshold: " << slowstart_threshold_; return; } - if (congestion_window_ >= max_tcp_congestion_window_) { - return; - } // Congestion avoidance if (reno_) { // Classic Reno congestion avoidance. - ++congestion_window_count_; + ++num_acked_packets_; // Divide by num_connections to smoothly increase the CWND at a faster // rate than conventional Reno. - if (congestion_window_count_ * num_connections_ >= congestion_window_) { + if (num_acked_packets_ * num_connections_ >= congestion_window_) { ++congestion_window_; - congestion_window_count_ = 0; + num_acked_packets_ = 0; } DVLOG(1) << "Reno; congestion window: " << congestion_window_ << " slowstart threshold: " << slowstart_threshold_ - << " congestion window count: " << congestion_window_count_; + << " congestion window count: " << num_acked_packets_; } else { - congestion_window_ = min(max_tcp_congestion_window_, - cubic_.CongestionWindowAfterAck( - congestion_window_, rtt_stats_->min_rtt())); + congestion_window_ = cubic_.CongestionWindowAfterAck(congestion_window_, + rtt_stats_->min_rtt()); DVLOG(1) << "Cubic; congestion window: " << congestion_window_ << " slowstart threshold: " << slowstart_threshold_; }
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h index e22894a0..4659a4b 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -31,12 +31,10 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { public: - // Reno option and max_tcp_congestion_window are provided for testing. TcpCubicSender(const QuicClock* clock, const RttStats* rtt_stats, bool reno, QuicPacketCount initial_tcp_congestion_window, - QuicPacketCount max_tcp_congestion_window, QuicConnectionStats* stats); ~TcpCubicSender() override; @@ -102,7 +100,7 @@ uint32 num_connections_; // ACK counter for the Reno implementation. - uint64 congestion_window_count_; + uint64 num_acked_packets_; // Track the largest packet that has been sent. QuicPacketSequenceNumber largest_sent_sequence_number_; @@ -123,9 +121,6 @@ // Used for stats collection of slowstart_packets_lost bool last_cutback_exited_slowstart_; - // Maximum number of outstanding packets for tcp. - QuicPacketCount max_tcp_congestion_window_; - const QuicClock* clock_; DISALLOW_COPY_AND_ASSIGN(TcpCubicSender);
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc index 2d0f61c..ab5fcdb 100644 --- a/net/quic/congestion_control/tcp_cubic_sender_test.cc +++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -30,13 +30,12 @@ class TcpCubicSenderPeer : public TcpCubicSender { public: - TcpCubicSenderPeer(const QuicClock* clock, - bool reno, - QuicPacketCount max_tcp_congestion_window) - : TcpCubicSender( - clock, &rtt_stats_, reno, kInitialCongestionWindowPackets, - max_tcp_congestion_window, &stats_) { - } + TcpCubicSenderPeer(const QuicClock* clock, bool reno) + : TcpCubicSender(clock, + &rtt_stats_, + reno, + kInitialCongestionWindowPackets, + &stats_) {} QuicPacketCount congestion_window() { return congestion_window_; @@ -62,8 +61,7 @@ protected: TcpCubicSenderTest() : one_ms_(QuicTime::Delta::FromMilliseconds(1)), - sender_(new TcpCubicSenderPeer(&clock_, true, - kMaxTcpCongestionWindow)), + sender_(new TcpCubicSenderPeer(&clock_, true)), sequence_number_(1), acked_sequence_number_(0), bytes_in_flight_(0) { @@ -208,8 +206,6 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) { sender_->SetNumEmulatedConnections(1); - EXPECT_EQ(kMaxTcpCongestionWindow * kDefaultTCPMSS, - sender_->GetSlowStartThreshold()); // Make sure that we fall out of slow start when we send ACK train longer // than half the RTT, in this test case 30ms, which is more than 30 calls to @@ -418,8 +414,6 @@ TEST_F(TcpCubicSenderTest, RTOCongestionWindow) { EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - EXPECT_EQ(kMaxTcpCongestionWindow, sender_->slowstart_threshold()); - // Expect the window to decrease to the minimum once the RTO fires // and slow start threshold to be set to 1/2 of the CWND. sender_->OnRetransmissionTimeout(true); @@ -472,68 +466,6 @@ sender_->BandwidthEstimate().ToBytesPerSecond()); } -TEST_F(TcpCubicSenderTest, SlowStartMaxSendWindow) { - const QuicPacketCount kMaxCongestionWindowTCP = 50; - const int kNumberOfAcks = 100; - sender_.reset( - new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindowTCP)); - - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - QuicByteCount expected_send_window = - kMaxCongestionWindowTCP * kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, TcpRenoMaxCongestionWindow) { - const QuicPacketCount kMaxCongestionWindowTCP = 50; - const int kNumberOfAcks = 1000; - sender_.reset( - new TcpCubicSenderPeer(&clock_, true, kMaxCongestionWindowTCP)); - - SendAvailableSendWindow(); - AckNPackets(2); - // Make sure we fall out of slow start. - LoseNPackets(1); - - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - - QuicByteCount expected_send_window = - kMaxCongestionWindowTCP * kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, TcpCubicMaxCongestionWindow) { - const QuicPacketCount kMaxCongestionWindowTCP = 50; - // Set to 10000 to compensate for small cubic alpha. - const int kNumberOfAcks = 10000; - - sender_.reset( - new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindowTCP)); - - SendAvailableSendWindow(); - AckNPackets(2); - // Make sure we fall out of slow start. - LoseNPackets(1); - - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - - QuicByteCount expected_send_window = - kMaxCongestionWindowTCP * kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); -} - TEST_F(TcpCubicSenderTest, MultipleLossesInOneWindow) { SendAvailableSendWindow(); const QuicByteCount initial_window = sender_->GetCongestionWindow(); @@ -715,9 +647,10 @@ // Resumed CWND is limited to be in a sensible range. cached_network_params.set_bandwidth_estimate_bytes_per_second( - (kMaxTcpCongestionWindow + 1) * kMaxPacketSize); + (kMaxCongestionWindowForBandwidthResumption + 1) * kMaxPacketSize); EXPECT_TRUE(sender_->ResumeConnectionState(cached_network_params)); - EXPECT_EQ(kMaxTcpCongestionWindow, sender_->congestion_window()); + EXPECT_EQ(kMaxCongestionWindowForBandwidthResumption, + sender_->congestion_window()); cached_network_params.set_bandwidth_estimate_bytes_per_second( (kMinCongestionWindowForBandwidthResumption - 1) * kMaxPacketSize);
diff --git a/net/quic/crypto/crypto_handshake_message.cc b/net/quic/crypto/crypto_handshake_message.cc index 73fc9cf..296e194 100644 --- a/net/quic/crypto/crypto_handshake_message.cc +++ b/net/quic/crypto/crypto_handshake_message.cc
@@ -165,11 +165,6 @@ } } -QuicErrorCode CryptoHandshakeMessage::GetUint16(QuicTag tag, - uint16* out) const { - return GetPOD(tag, out, sizeof(uint16)); -} - QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag, uint32* out) const { return GetPOD(tag, out, sizeof(uint32)); @@ -244,6 +239,7 @@ case kSFCW: case kIRTT: case kMSPC: + case kSRBF: case kSWND: // uint32 value if (it->second.size() == 4) {
diff --git a/net/quic/crypto/crypto_handshake_message.h b/net/quic/crypto/crypto_handshake_message.h index fcb39307..7b686596 100644 --- a/net/quic/crypto/crypto_handshake_message.h +++ b/net/quic/crypto/crypto_handshake_message.h
@@ -85,7 +85,6 @@ QuicErrorCode GetNthValue24(QuicTag tag, unsigned index, base::StringPiece* out) const; - QuicErrorCode GetUint16(QuicTag tag, uint16* out) const; QuicErrorCode GetUint32(QuicTag tag, uint32* out) const; QuicErrorCode GetUint64(QuicTag tag, uint64* out) const;
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h index ae7e78d..821874e0 100644 --- a/net/quic/crypto/crypto_protocol.h +++ b/net/quic/crypto/crypto_protocol.h
@@ -59,9 +59,6 @@ const QuicTag kNTLP = TAG('N', 'T', 'L', 'P'); // No tail loss probe const QuicTag kNCON = TAG('N', 'C', 'O', 'N'); // N Connection Congestion Ctrl const QuicTag kNRTO = TAG('N', 'R', 'T', 'O'); // CWND reduction on loss - -// Loss detection algorithm types -const QuicTag kNACK = TAG('N', 'A', 'C', 'K'); // TCP style nack counting const QuicTag kTIME = TAG('T', 'I', 'M', 'E'); // Time based // Optional support of truncated Connection IDs. If sent by a peer, the value
diff --git a/net/quic/quic_bandwidth_test.cc b/net/quic/quic_bandwidth_test.cc index 04fe93b..7f07a6a6 100644 --- a/net/quic/quic_bandwidth_test.cc +++ b/net/quic/quic_bandwidth_test.cc
@@ -84,5 +84,18 @@ EXPECT_EQ(QuicTime::Delta::Zero(), QuicBandwidth::Zero().TransferTime(1000)); } +TEST_F(QuicBandwidthTest, RelOps) { + const QuicBandwidth b1 = QuicBandwidth::FromKBitsPerSecond(1); + const QuicBandwidth b2 = QuicBandwidth::FromKBytesPerSecond(2); + EXPECT_EQ(b1, b1); + EXPECT_NE(b1, b2); + EXPECT_LT(b1, b2); + EXPECT_GT(b2, b1); + EXPECT_LE(b1, b1); + EXPECT_LE(b1, b2); + EXPECT_GE(b1, b1); + EXPECT_GE(b2, b1); +} + } // namespace test } // namespace net
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc index 803ae7f51..f3e93aa3 100644 --- a/net/quic/quic_config.cc +++ b/net/quic/quic_config.cc
@@ -280,74 +280,6 @@ return error; } -QuicFixedTag::QuicFixedTag(QuicTag name, - QuicConfigPresence presence) - : QuicConfigValue(name, presence), - has_send_value_(false), - has_receive_value_(false) { -} - -QuicFixedTag::~QuicFixedTag() {} - -bool QuicFixedTag::HasSendValue() const { - return has_send_value_; -} - -uint32 QuicFixedTag::GetSendValue() const { - LOG_IF(DFATAL, !has_send_value_) - << "No send value to get for tag:" << QuicUtils::TagToString(tag_); - return send_value_; -} - -void QuicFixedTag::SetSendValue(uint32 value) { - has_send_value_ = true; - send_value_ = value; -} - -bool QuicFixedTag::HasReceivedValue() const { - return has_receive_value_; -} - -uint32 QuicFixedTag::GetReceivedValue() const { - LOG_IF(DFATAL, !has_receive_value_) - << "No receive value to get for tag:" << QuicUtils::TagToString(tag_); - return receive_value_; -} - -void QuicFixedTag::SetReceivedValue(uint32 value) { - has_receive_value_ = true; - receive_value_ = value; -} - -void QuicFixedTag::ToHandshakeMessage(CryptoHandshakeMessage* out) const { - if (has_send_value_) { - out->SetValue(tag_, send_value_); - } -} - -QuicErrorCode QuicFixedTag::ProcessPeerHello( - const CryptoHandshakeMessage& peer_hello, - HelloType hello_type, - string* error_details) { - DCHECK(error_details != nullptr); - QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value_); - switch (error) { - case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: - if (presence_ == PRESENCE_OPTIONAL) { - return QUIC_NO_ERROR; - } - *error_details = "Missing " + QuicUtils::TagToString(tag_); - break; - case QUIC_NO_ERROR: - has_receive_value_ = true; - break; - default: - *error_details = "Bad " + QuicUtils::TagToString(tag_); - break; - } - return error; -} - QuicFixedTagVector::QuicFixedTagVector(QuicTag name, QuicConfigPresence presence) : QuicConfigValue(name, presence), @@ -476,6 +408,7 @@ idle_connection_state_lifetime_seconds_.GetUint32()); } +// TODO(ianswett) Use this for silent close on mobile, or delete. void QuicConfig::SetSilentClose(bool silent_close) { silent_close_.set(silent_close ? 1 : 0, silent_close ? 1 : 0); } @@ -577,10 +510,6 @@ socket_receive_buffer_.SetSendValue(tcp_receive_window); } -uint32 QuicConfig::GetSocketReceiveBufferToSend() const { - return socket_receive_buffer_.GetSendValue(); -} - bool QuicConfig::HasReceivedSocketReceiveBuffer() const { return socket_receive_buffer_.HasReceivedValue(); }
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h index 83e0618..ceb56e2 100644 --- a/net/quic/quic_config.h +++ b/net/quic/quic_config.h
@@ -182,39 +182,6 @@ }; // Stores tag from CHLO or SHLO messages that are not negotiated. -class NET_EXPORT_PRIVATE QuicFixedTag : public QuicConfigValue { - public: - QuicFixedTag(QuicTag name, QuicConfigPresence presence); - ~QuicFixedTag() override; - - bool HasSendValue() const; - - QuicTag GetSendValue() const; - - void SetSendValue(QuicTag value); - - bool HasReceivedValue() const; - - QuicTag GetReceivedValue() const; - - void SetReceivedValue(QuicTag value); - - // If has_send_value is true, serialises |tag_| and |send_value_| to |out|. - void ToHandshakeMessage(CryptoHandshakeMessage* out) const override; - - // Sets |value_| to the corresponding value from |client_hello_| if it exists. - QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello, - HelloType hello_type, - std::string* error_details) override; - - private: - QuicTag send_value_; - bool has_send_value_; - QuicTag receive_value_; - bool has_receive_value_; -}; - -// Stores tag from CHLO or SHLO messages that are not negotiated. class NET_EXPORT_PRIVATE QuicFixedTagVector : public QuicConfigValue { public: QuicFixedTagVector(QuicTag name, QuicConfigPresence presence); @@ -348,8 +315,6 @@ // Sets socket receive buffer to transmit to the peer. void SetSocketReceiveBufferToSend(uint32 window_bytes); - uint32 GetSocketReceiveBufferToSend() const; - bool HasReceivedSocketReceiveBuffer() const; uint32 ReceivedSocketReceiveBuffer() const;
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index aca4d203..4a510fb7 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc
@@ -61,9 +61,6 @@ // Maximum number of acks received before sending an ack in response. const QuicPacketCount kMaxPacketsReceivedBeforeAckSend = 20; -// Maximum number of tracked packets. -const QuicPacketCount kMaxTrackedPackets = 5 * kMaxTcpCongestionWindow; - bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) { QuicPacketSequenceNumber delta = (a > b) ? a - b : b - a; return delta <= kMaxPacketGap;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index 1964e1ec4..c23ea73 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc
@@ -711,13 +711,6 @@ return encrypted->length(); } - void ProcessPingPacket(QuicPacketSequenceNumber number) { - scoped_ptr<QuicPacket> packet(ConstructPingPacket(number)); - scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket( - ENCRYPTION_NONE, number, *packet)); - connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); - } - void ProcessClosePacket(QuicPacketSequenceNumber number, QuicFecGroupNumber fec_group) { scoped_ptr<QuicPacket> packet(ConstructClosePacket(number, fec_group)); @@ -1359,8 +1352,8 @@ TEST_P(QuicConnectionTest, TooManySentPackets) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - - for (int i = 0; i < 1100; ++i) { + const QuicPacketCount num_sent_packets = kMaxTrackedPackets + 100; + for (QuicPacketCount i = 0; i < num_sent_packets; ++i) { SendStreamDataToPeer(1, "foo", 3 * i, !kFin, nullptr); } @@ -1372,8 +1365,8 @@ EXPECT_CALL(visitor_, OnCanWrite()).Times(0); // Nack every packet except the last one, leaving a huge gap. - QuicAckFrame frame1 = InitAckFrame(1100); - for (QuicPacketSequenceNumber i = 1; i < 1100; ++i) { + QuicAckFrame frame1 = InitAckFrame(num_sent_packets); + for (QuicPacketSequenceNumber i = 1; i < num_sent_packets; ++i) { NackPacket(i, &frame1); } ProcessAckPacket(&frame1); @@ -1384,8 +1377,8 @@ EXPECT_CALL(visitor_, OnConnectionClosed( QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS, false)); - // Miss every other packet for 1000 packets. - for (QuicPacketSequenceNumber i = 1; i < 1000; ++i) { + // Miss every other packet for 5000 packets. + for (QuicPacketSequenceNumber i = 1; i < kMaxTrackedPackets; ++i) { ProcessPacket(i * 2); if (!connection_.connected()) { break;
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index c7c0291..eaff528 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc
@@ -134,6 +134,7 @@ return num_client_hellos_; } +// Used in Chromium, but not in the server. bool QuicCryptoClientStream::WasChannelIDSent() const { return channel_id_sent_; }
diff --git a/net/quic/quic_crypto_stream_test.cc b/net/quic/quic_crypto_stream_test.cc index 3c62644..0abd49d 100644 --- a/net/quic/quic_crypto_stream_test.cc +++ b/net/quic/quic_crypto_stream_test.cc
@@ -102,7 +102,6 @@ } TEST_F(QuicCryptoStreamTest, NoConnectionLevelFlowControl) { - EXPECT_TRUE(stream_.flow_controller()->IsEnabled()); EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl( &stream_)); }
diff --git a/net/quic/quic_data_reader.cc b/net/quic/quic_data_reader.cc index b9a6acf..7542c831 100644 --- a/net/quic/quic_data_reader.cc +++ b/net/quic/quic_data_reader.cc
@@ -25,43 +25,10 @@ return ReadBytes(result, sizeof(*result)); } -bool QuicDataReader::ReadUInt48(uint64* result) { - uint32 lo; - if (!ReadUInt32(&lo)) { - return false; - } - - uint16 hi; - if (!ReadUInt16(&hi)) { - return false; - } - - *result = hi; - *result <<= 32; - *result += lo; - - return true; -} - bool QuicDataReader::ReadUInt64(uint64* result) { return ReadBytes(result, sizeof(*result)); } -bool QuicDataReader::ReadUInt128(uint128* result) { - uint64 high_hash; - uint64 low_hash; - - if (!ReadUInt64(&low_hash)) { - return false; - } - if (!ReadUInt64(&high_hash)) { - return false; - } - - *result = uint128(high_hash, low_hash); - return true; -} - bool QuicDataReader::ReadUFloat16(uint64* result) { uint16 value; if (!ReadUInt16(&value)) {
diff --git a/net/quic/quic_data_reader.h b/net/quic/quic_data_reader.h index 1686de02..3384e20 100644 --- a/net/quic/quic_data_reader.h +++ b/net/quic/quic_data_reader.h
@@ -44,21 +44,11 @@ // Returns true on success, false otherwise. bool ReadUInt32(uint32* result); - // Reads a 48-bit unsigned integer into the given output parameter. - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadUInt48(uint64* result); - // Reads a 64-bit unsigned integer into the given output parameter. // Forwards the internal iterator on success. // Returns true on success, false otherwise. bool ReadUInt64(uint64* result); - // Reads a 128-bit unsigned integer into the given output parameter. - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadUInt128(uint128* result); - // Reads a 16-bit unsigned float into the given output parameter. // Forwards the internal iterator on success. // Returns true on success, false otherwise.
diff --git a/net/quic/quic_data_stream.cc b/net/quic/quic_data_stream.cc index aa24d0c..10f8b4c 100644 --- a/net/quic/quic_data_stream.cc +++ b/net/quic/quic_data_stream.cc
@@ -26,14 +26,11 @@ } // namespace -QuicDataStream::QuicDataStream(QuicStreamId id, - QuicSession* session) +QuicDataStream::QuicDataStream(QuicStreamId id, QuicSession* session) : ReliableQuicStream(id, session), visitor_(nullptr), headers_decompressed_(false), - priority_(kDefaultPriority), - decompression_failed_(false), - priority_parsed_(false) { + priority_(kDefaultPriority) { DCHECK_NE(kCryptoStreamId, id); // Don't receive any callbacks from the sequencer until headers // are complete.
diff --git a/net/quic/quic_data_stream.h b/net/quic/quic_data_stream.h index 965a5ae..c80cacf 100644 --- a/net/quic/quic_data_stream.h +++ b/net/quic/quic_data_stream.h
@@ -135,10 +135,6 @@ // Contains a copy of the decompressed headers until they are consumed // via ProcessData or Readv. std::string decompressed_headers_; - // True if an error was encountered during decompression. - bool decompression_failed_; - // True if the priority has been read, false otherwise. - bool priority_parsed_; DISALLOW_COPY_AND_ASSIGN(QuicDataStream); };
diff --git a/net/quic/quic_data_writer.cc b/net/quic/quic_data_writer.cc index 1c6e47fe..05bc044 100644 --- a/net/quic/quic_data_writer.cc +++ b/net/quic/quic_data_writer.cc
@@ -159,37 +159,5 @@ length_ = capacity_; } -bool QuicDataWriter::WriteUInt8ToOffset(uint8 value, size_t offset) { - if (offset >= capacity_) { - LOG(DFATAL) << "offset: " << offset << " >= capacity: " << capacity_; - return false; - } - size_t latched_length = length_; - length_ = offset; - bool success = WriteUInt8(value); - DCHECK_LE(length_, latched_length); - length_ = latched_length; - return success; -} - -bool QuicDataWriter::WriteUInt32ToOffset(uint32 value, size_t offset) { - DCHECK_LT(offset, capacity_); - size_t latched_length = length_; - length_ = offset; - bool success = WriteUInt32(value); - DCHECK_LE(length_, latched_length); - length_ = latched_length; - return success; -} - -bool QuicDataWriter::WriteUInt48ToOffset(uint64 value, size_t offset) { - DCHECK_LT(offset, capacity_); - size_t latched_length = length_; - length_ = offset; - bool success = WriteUInt48(value); - DCHECK_LE(length_, latched_length); - length_ = latched_length; - return success; -} } // namespace net
diff --git a/net/quic/quic_data_writer.h b/net/quic/quic_data_writer.h index 4b5958e..caffcf1 100644 --- a/net/quic/quic_data_writer.h +++ b/net/quic/quic_data_writer.h
@@ -54,13 +54,6 @@ // Fills the remaining buffer with null characters. void WritePadding(); - // Methods for editing the payload at a specific offset, where the - // offset must be within the writer's capacity. - // Return true if there is enough space at that offset, false otherwise. - bool WriteUInt8ToOffset(uint8 value, size_t offset); - bool WriteUInt32ToOffset(uint32 value, size_t offset); - bool WriteUInt48ToOffset(uint64 value, size_t offset); - size_t capacity() const { return capacity_; }
diff --git a/net/quic/quic_data_writer_test.cc b/net/quic/quic_data_writer_test.cc index 01b3c6d..a7ac2a8 100644 --- a/net/quic/quic_data_writer_test.cc +++ b/net/quic/quic_data_writer_test.cc
@@ -13,30 +13,6 @@ namespace test { namespace { -TEST(QuicDataWriterTest, WriteUInt8ToOffset) { - char buffer[4]; - QuicDataWriter writer(4, buffer); - - writer.WriteUInt32(0xfefdfcfb); - EXPECT_TRUE(writer.WriteUInt8ToOffset(1, 0)); - EXPECT_TRUE(writer.WriteUInt8ToOffset(2, 1)); - EXPECT_TRUE(writer.WriteUInt8ToOffset(3, 2)); - EXPECT_TRUE(writer.WriteUInt8ToOffset(4, 3)); - - EXPECT_EQ(1, writer.data()[0]); - EXPECT_EQ(2, writer.data()[1]); - EXPECT_EQ(3, writer.data()[2]); - EXPECT_EQ(4, writer.data()[3]); -} - -TEST(QuicDataWriterDeathTest, WriteUInt8ToOffset) { - char buffer[4]; - QuicDataWriter writer(4, buffer); - - EXPECT_DFATAL(EXPECT_FALSE(writer.WriteUInt8ToOffset(5, 4)), - "offset: 4 >= capacity: 4"); -} - TEST(QuicDataWriterTest, SanityCheckUFloat16Consts) { // Check the arithmetic on the constants - otherwise the values below make // no sense.
diff --git a/net/quic/quic_dispatcher.cc b/net/quic/quic_dispatcher.cc index f750bfa..1ce40c9d 100644 --- a/net/quic/quic_dispatcher.cc +++ b/net/quic/quic_dispatcher.cc
@@ -361,28 +361,17 @@ QuicConnectionId connection_id, const IPEndPoint& server_address, const IPEndPoint& client_address) { - QuicServerSession* session = new QuicServerSession( - config_, - CreateQuicConnection(connection_id, server_address, client_address), - this); + // The QuicSession takes ownership of |connection| below. + QuicConnection* connection = new QuicConnection( + connection_id, client_address, helper_, connection_writer_factory_, + /* owns_writer= */ true, /* is_server= */ true, + crypto_config_.HasProofSource(), supported_versions_); + + QuicServerSession* session = new QuicServerSession(config_, connection, this); session->InitializeSession(crypto_config_); return session; } -QuicConnection* QuicDispatcher::CreateQuicConnection( - QuicConnectionId connection_id, - const IPEndPoint& server_address, - const IPEndPoint& client_address) { - return new QuicConnection(connection_id, - client_address, - helper_, - connection_writer_factory_, - /* owns_writer= */ true, - /* is_server= */ true, - crypto_config_.HasProofSource(), - supported_versions_); -} - QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() { return new QuicTimeWaitListManager( writer_.get(), this, helper_, supported_versions());
diff --git a/net/quic/quic_dispatcher.h b/net/quic/quic_dispatcher.h index 8e2ce03..c507556 100644 --- a/net/quic/quic_dispatcher.h +++ b/net/quic/quic_dispatcher.h
@@ -129,11 +129,6 @@ const IPEndPoint& server_address, const IPEndPoint& client_address); - virtual QuicConnection* CreateQuicConnection( - QuicConnectionId connection_id, - const IPEndPoint& server_address, - const IPEndPoint& client_address); - // Called by |framer_visitor_| when the public header has been parsed. virtual bool OnUnauthenticatedPublicHeader( const QuicPacketPublicHeader& header); @@ -142,11 +137,6 @@ // will be owned by the dispatcher as time_wait_list_manager_ virtual QuicTimeWaitListManager* CreateQuicTimeWaitListManager(); - // Replaces the packet writer with |writer|. Takes ownership of |writer|. - void set_writer(QuicServerPacketWriter* writer) { - writer_.reset(writer); - } - QuicTimeWaitListManager* time_wait_list_manager() { return time_wait_list_manager_.get(); }
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc index e19d92634..ac5cc864a 100644 --- a/net/quic/quic_flags.cc +++ b/net/quic/quic_flags.cc
@@ -52,9 +52,5 @@ // no configured limit. int64 FLAGS_quic_time_wait_list_max_connections = 50000; -// If true, limit the number of connections on the quic time-wait list using a -// flag. -bool FLAGS_quic_limit_time_wait_list_size = true; - // Use small QUIC packet sizes by default. bool FLAGS_quic_small_default_packet_size = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h index c32b50d..bb18b49 100644 --- a/net/quic/quic_flags.h +++ b/net/quic/quic_flags.h
@@ -21,7 +21,6 @@ NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_multiple_address_in_source_tokens; NET_EXPORT_PRIVATE extern int64 FLAGS_quic_time_wait_list_seconds; NET_EXPORT_PRIVATE extern int64 FLAGS_quic_time_wait_list_max_connections; -NET_EXPORT_PRIVATE extern bool FLAGS_quic_limit_time_wait_list_size; NET_EXPORT_PRIVATE extern bool FLAGS_quic_small_default_packet_size; #endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_flow_controller.cc b/net/quic/quic_flow_controller.cc index 59ae8c0..1fedd06 100644 --- a/net/quic/quic_flow_controller.cc +++ b/net/quic/quic_flow_controller.cc
@@ -21,7 +21,6 @@ QuicByteCount max_receive_window) : connection_(connection), id_(id), - is_enabled_(true), is_server_(is_server), bytes_consumed_(0), highest_received_byte_offset_(0), @@ -39,10 +38,6 @@ } void QuicFlowController::AddBytesConsumed(QuicByteCount bytes_consumed) { - if (!IsEnabled()) { - return; - } - bytes_consumed_ += bytes_consumed; DVLOG(1) << ENDPOINT << "Stream " << id_ << " consumed: " << bytes_consumed_; @@ -51,10 +46,6 @@ bool QuicFlowController::UpdateHighestReceivedOffset( QuicStreamOffset new_offset) { - if (!IsEnabled()) { - return false; - } - // Only update if offset has increased. if (new_offset <= highest_received_byte_offset_) { return false; @@ -68,10 +59,6 @@ } void QuicFlowController::AddBytesSent(QuicByteCount bytes_sent) { - if (!IsEnabled()) { - return; - } - if (bytes_sent_ + bytes_sent > send_window_offset_) { LOG(DFATAL) << ENDPOINT << "Stream " << id_ << " Trying to send an extra " << bytes_sent << " bytes, when bytes_sent = " << bytes_sent_ @@ -88,10 +75,6 @@ } bool QuicFlowController::FlowControlViolation() { - if (!IsEnabled()) { - return false; - } - if (highest_received_byte_offset_ > receive_window_offset_) { LOG(ERROR) << ENDPOINT << "Flow control violation on stream " << id_ << ", receive window offset: " @@ -104,10 +87,6 @@ } void QuicFlowController::MaybeSendWindowUpdate() { - if (!IsEnabled()) { - return; - } - // Send WindowUpdate to increase receive window if // (receive window offset - consumed bytes) < (max window / 2). // This is behaviour copied from SPDY. @@ -132,10 +111,6 @@ } void QuicFlowController::MaybeSendBlocked() { - if (!IsEnabled()) { - return; - } - if (SendWindowSize() == 0 && last_blocked_send_window_offset_ < send_window_offset_) { DVLOG(1) << ENDPOINT << "Stream " << id_ << " is flow control blocked. " @@ -154,10 +129,6 @@ bool QuicFlowController::UpdateSendWindowOffset( QuicStreamOffset new_send_window_offset) { - if (!IsEnabled()) { - return false; - } - // Only update if send window has increased. if (new_send_window_offset <= send_window_offset_) { return false; @@ -173,16 +144,8 @@ return blocked; } -void QuicFlowController::Disable() { - is_enabled_ = false; -} - -bool QuicFlowController::IsEnabled() const { - return is_enabled_; -} - bool QuicFlowController::IsBlocked() const { - return IsEnabled() && SendWindowSize() == 0; + return SendWindowSize() == 0; } uint64 QuicFlowController::SendWindowSize() const {
diff --git a/net/quic/quic_flow_controller.h b/net/quic/quic_flow_controller.h index 371b8c9..1b5ed61 100644 --- a/net/quic/quic_flow_controller.h +++ b/net/quic/quic_flow_controller.h
@@ -56,12 +56,6 @@ // Send a BLOCKED frame if appropriate. void MaybeSendBlocked(); - // Disable flow control. - void Disable(); - - // Returns true if flow control is enabled. - bool IsEnabled() const; - // Returns true if flow control send limits have been reached. bool IsBlocked() const; @@ -89,9 +83,6 @@ // connection level flow controller. QuicStreamId id_; - // True if flow control is enabled. - bool is_enabled_; - // True if this is owned by a server. bool is_server_;
diff --git a/net/quic/quic_flow_controller_test.cc b/net/quic/quic_flow_controller_test.cc index e3fcafe..b3c75c4 100644 --- a/net/quic/quic_flow_controller_test.cc +++ b/net/quic/quic_flow_controller_test.cc
@@ -44,7 +44,6 @@ TEST_F(QuicFlowControllerTest, SendingBytes) { Initialize(); - EXPECT_TRUE(flow_controller_->IsEnabled()); EXPECT_FALSE(flow_controller_->IsBlocked()); EXPECT_FALSE(flow_controller_->FlowControlViolation()); EXPECT_EQ(send_window_, flow_controller_->SendWindowSize()); @@ -86,7 +85,6 @@ TEST_F(QuicFlowControllerTest, ReceivingBytes) { Initialize(); - EXPECT_TRUE(flow_controller_->IsEnabled()); EXPECT_FALSE(flow_controller_->IsBlocked()); EXPECT_FALSE(flow_controller_->FlowControlViolation()); EXPECT_EQ(kInitialSessionFlowControlWindowForTest, @@ -116,7 +114,6 @@ // Test that we don't send duplicate BLOCKED frames. We should only send one // BLOCKED frame at a given send window offset. - EXPECT_TRUE(flow_controller_->IsEnabled()); EXPECT_FALSE(flow_controller_->IsBlocked()); EXPECT_FALSE(flow_controller_->FlowControlViolation()); EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc index 9d684ac..d4cf018 100644 --- a/net/quic/quic_headers_stream_test.cc +++ b/net/quic/quic_headers_stream_test.cc
@@ -457,7 +457,6 @@ } TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) { - EXPECT_TRUE(headers_stream_->flow_controller()->IsEnabled()); EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl( headers_stream_)); }
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h index d61998a8..a43d027 100644 --- a/net/quic/quic_packet_creator.h +++ b/net/quic/quic_packet_creator.h
@@ -215,10 +215,6 @@ static bool ShouldRetransmit(const QuicFrame& frame); - // Updates sequence number and max packet lengths on a packet or FEC group - // boundary. - void MaybeUpdateLengths(); - // Updates lengths and also starts an FEC group if FEC protection is on and // there is not already an FEC group open. InFecGroup MaybeUpdateLengthsAndStartFec();
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 548755e..7d33a8a 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h
@@ -68,11 +68,14 @@ // Minimum size of initial flow control window, for both stream and session. const uint32 kMinimumFlowControlSendWindow = 16 * 1024; // 16 KB -// Minimum size of the CWND, in packets, when doing bandwidth resumption. +// Minimum and maximum size of the CWND, in packets, +// when doing bandwidth resumption. const QuicPacketCount kMinCongestionWindowForBandwidthResumption = 10; +const QuicPacketCount kMaxCongestionWindowForBandwidthResumption = 200; -// Maximum size of the CWND, in packets, for TCP congestion control algorithms. -const QuicPacketCount kMaxTcpCongestionWindow = 200; +// Maximum number of tracked packets before the connection will be closed. +// This effectively limits the max CWND to a smaller value than this. +const QuicPacketCount kMaxTrackedPackets = 5000; // Default size of the socket receive buffer in bytes. const QuicByteCount kDefaultSocketReceiveBuffer = 256 * 1024; @@ -106,8 +109,6 @@ // Limit on the delta between stream IDs. const QuicStreamId kMaxStreamIdDelta = 200; -// Limit on the delta between header IDs. -const QuicHeaderId kMaxHeaderIdDelta = 200; // Reserved ID for the crypto stream. const QuicStreamId kCryptoStreamId = 1;
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index 9c502f4..242d8e7 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc
@@ -435,16 +435,14 @@ TransmissionType transmission_type = pending_retransmissions_.begin()->second; if (unacked_packets_.HasPendingCryptoPackets()) { // Ensure crypto packets are retransmitted before other packets. - PendingRetransmissionMap::const_iterator it = - pending_retransmissions_.begin(); - do { - if (HasCryptoHandshake(unacked_packets_.GetTransmissionInfo(it->first))) { - sequence_number = it->first; - transmission_type = it->second; + for (const auto& pair : pending_retransmissions_) { + if (HasCryptoHandshake( + unacked_packets_.GetTransmissionInfo(pair.first))) { + sequence_number = pair.first; + transmission_type = pair.second; break; } - ++it; - } while (it != pending_retransmissions_.end()); + } } DCHECK(unacked_packets_.IsUnacked(sequence_number)) << sequence_number; const TransmissionInfo& transmission_info =
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h index d4d68e8..d917106 100644 --- a/net/quic/quic_sent_packet_manager.h +++ b/net/quic/quic_sent_packet_manager.h
@@ -238,10 +238,12 @@ network_change_visitor_ = visitor; } + // Used in Chromium, but not in the server. size_t consecutive_rto_count() const { return consecutive_rto_count_; } + // Used in Chromium, but not in the server. size_t consecutive_tlp_count() const { return consecutive_tlp_count_; }
diff --git a/net/quic/quic_server_id.h b/net/quic/quic_server_id.h index 6d016705..7236bfc 100644 --- a/net/quic/quic_server_id.h +++ b/net/quic/quic_server_id.h
@@ -39,6 +39,7 @@ // based on |is_https|. std::string ToString() const; + // Used in Chromium, but not in the server. const HostPortPair& host_port_pair() const { return host_port_pair_; } const std::string& host() const { return host_port_pair_.host(); }
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index f102845..993f4292 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc
@@ -412,8 +412,7 @@ // If we haven't received a FIN or RST for this stream, we need to keep track // of the how many bytes the stream's flow controller believes it has // received, for accurate connection level flow control accounting. - if (!stream->HasFinalReceivedByteOffset() && - stream->flow_controller()->IsEnabled()) { + if (!stream->HasFinalReceivedByteOffset()) { locally_closed_streams_highest_offset_[stream_id] = stream->flow_controller()->highest_received_byte_offset(); }
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index 092c48ca..2da1286b 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc
@@ -395,20 +395,18 @@ // To mitigate the effects of disk cache taking too long to load QUIC server // information, set up a timer to cancel WaitForDataReady's callback. - int64 load_server_info_timeout_ms = factory_->load_server_info_timeout_ms_; if (factory_->load_server_info_timeout_srtt_multiplier_ > 0) { - DCHECK_EQ(0, load_server_info_timeout_ms); - load_server_info_timeout_ms = + int64 load_server_info_timeout_ms = (factory_->load_server_info_timeout_srtt_multiplier_ * factory_->GetServerNetworkStatsSmoothedRttInMicroseconds(server_id_)) / 1000; - } - if (load_server_info_timeout_ms > 0) { - factory_->task_runner_->PostDelayedTask( - FROM_HERE, - base::Bind(&QuicStreamFactory::Job::CancelWaitForDataReadyCallback, - GetWeakPtr()), - base::TimeDelta::FromMilliseconds(load_server_info_timeout_ms)); + if (load_server_info_timeout_ms > 0) { + factory_->task_runner_->PostDelayedTask( + FROM_HERE, + base::Bind(&QuicStreamFactory::Job::CancelWaitForDataReadyCallback, + GetWeakPtr()), + base::TimeDelta::FromMilliseconds(load_server_info_timeout_ms)); + } } int rv = server_info_->WaitForDataReady( @@ -594,9 +592,7 @@ bool enable_port_selection, bool always_require_handshake_confirmation, bool disable_connection_pooling, - int load_server_info_timeout, float load_server_info_timeout_srtt_multiplier, - bool enable_truncated_connection_ids, bool enable_connection_racing, bool enable_non_blocking_io, bool disable_disk_cache, @@ -618,10 +614,8 @@ always_require_handshake_confirmation_( always_require_handshake_confirmation), disable_connection_pooling_(disable_connection_pooling), - load_server_info_timeout_ms_(load_server_info_timeout), load_server_info_timeout_srtt_multiplier_( load_server_info_timeout_srtt_multiplier), - enable_truncated_connection_ids_(enable_truncated_connection_ids), enable_connection_racing_(enable_connection_racing), enable_non_blocking_io_(enable_non_blocking_io), disable_disk_cache_(disable_disk_cache), @@ -1153,8 +1147,7 @@ FROM_HERE_WITH_EXPLICIT_FUNCTION( "422516 QuicStreamFactory::CreateSession57")); - if (enable_truncated_connection_ids_) - config.SetBytesForConnectionIdToSend(0); + config.SetBytesForConnectionIdToSend(0); if (quic_server_info_factory_ && !server_info) { // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h index 4ffbac6..49ecde8 100644 --- a/net/quic/quic_stream_factory.h +++ b/net/quic/quic_stream_factory.h
@@ -105,9 +105,7 @@ bool enable_port_selection, bool always_require_handshake_confirmation, bool disable_connection_pooling, - int load_server_info_timeout, float load_server_info_timeout_srtt_multiplier, - bool enable_truncated_connection_ids, bool enable_connection_racing, bool enable_non_blocking_io, bool disable_disk_cache, @@ -313,20 +311,12 @@ // Set if we do not want connection pooling. bool disable_connection_pooling_; - // Specifies the timeout in milliseconds to wait for loading of QUIC server - // information. If we don't want to timeout, set - // |load_server_info_timeout_ms_| to 0. - int load_server_info_timeout_ms_; - // Specifies the ratio between time to load QUIC server information from disk // cache to 'smoothed RTT'. This ratio is used to calculate the timeout in // milliseconds to wait for loading of QUIC server information. If we don't // want to timeout, set |load_server_info_timeout_srtt_multiplier_| to 0. float load_server_info_timeout_srtt_multiplier_; - // Set this for setting config's BytesForConnectionIdToSend (TCID param) to 0. - bool enable_truncated_connection_ids_; - // Set if we want to race connections - one connection that sends // INCHOATE_HELLO and another connection that sends CHLO after loading server // config from the disk cache.
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index 2e62d5e..fdc023b2 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc
@@ -125,11 +125,6 @@ factory->task_runner_ = task_runner; } - static void SetLoadServerInfoTimeout(QuicStreamFactory* factory, - size_t load_server_info_timeout) { - factory->load_server_info_timeout_ms_ = load_server_info_timeout; - } - static void SetEnableConnectionRacing(QuicStreamFactory* factory, bool enable_connection_racing) { factory->enable_connection_racing_ = enable_connection_racing; @@ -207,9 +202,7 @@ /*enable_port_selection=*/true, /*always_require_handshake_confirmation=*/false, /*disable_connection_pooling=*/false, - /*load_server_info_timeout=*/0u, /*load_server_info_timeout_srtt_multiplier=*/0.0f, - /*enable_truncated_connection_ids=*/true, /*enable_connection_racing=*/false, /*enable_non_blocking_io=*/true, /*disable_disk_cache=*/false, @@ -1613,62 +1606,11 @@ } } -TEST_P(QuicStreamFactoryTest, CancelWaitForDataReady) { - // Don't race quic connections when testing cancel reading of server config - // from disk cache. - if (GetParam().enable_connection_racing) - return; - factory_.set_quic_server_info_factory(&quic_server_info_factory_); - QuicStreamFactoryPeer::SetTaskRunner(&factory_, runner_.get()); - const size_t kLoadServerInfoTimeoutMs = 50; - QuicStreamFactoryPeer::SetLoadServerInfoTimeout( - &factory_, kLoadServerInfoTimeoutMs); - - MockRead reads[] = { - MockRead(ASYNC, OK, 0) // EOF - }; - DeterministicSocketData socket_data(reads, arraysize(reads), nullptr, 0); - socket_factory_.AddSocketDataProvider(&socket_data); - socket_data.StopAfter(1); - - crypto_client_stream_factory_.set_handshake_mode( - MockCryptoClientStream::ZERO_RTT); - host_resolver_.set_synchronous_mode(true); - host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(), - "192.168.0.1", ""); - - QuicStreamRequest request(&factory_); - EXPECT_EQ(ERR_IO_PENDING, - request.Request(host_port_pair_, - is_https_, - privacy_mode_, - "GET", - net_log_, - callback_.callback())); - - // Verify that the CancelWaitForDataReady task has been posted. - ASSERT_EQ(1u, runner_->GetPostedTasks().size()); - EXPECT_EQ(base::TimeDelta::FromMilliseconds(kLoadServerInfoTimeoutMs), - runner_->GetPostedTasks()[0].delay); - - runner_->RunNextTask(); - ASSERT_EQ(0u, runner_->GetPostedTasks().size()); - - scoped_ptr<QuicHttpStream> stream = request.ReleaseStream(); - EXPECT_TRUE(stream.get()); - EXPECT_TRUE(socket_data.at_read_eof()); - EXPECT_TRUE(socket_data.at_write_eof()); -} - TEST_P(QuicStreamFactoryTest, RacingConnections) { if (!GetParam().enable_connection_racing) return; factory_.set_quic_server_info_factory(&quic_server_info_factory_); QuicStreamFactoryPeer::SetTaskRunner(&factory_, runner_.get()); - const size_t kLoadServerInfoTimeoutMs = 50; - QuicStreamFactoryPeer::SetLoadServerInfoTimeout(&factory_, - kLoadServerInfoTimeoutMs); - MockRead reads[] = { MockRead(ASYNC, OK, 0) // EOF }; @@ -1710,9 +1652,6 @@ TEST_P(QuicStreamFactoryTest, EnableNotLoadFromDiskCache) { factory_.set_quic_server_info_factory(&quic_server_info_factory_); QuicStreamFactoryPeer::SetTaskRunner(&factory_, runner_.get()); - const size_t kLoadServerInfoTimeoutMs = 50; - QuicStreamFactoryPeer::SetLoadServerInfoTimeout(&factory_, - kLoadServerInfoTimeoutMs); QuicStreamFactoryPeer::SetDisableDiskCache(&factory_, true); MockRead reads[] = {
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc index 6e3d57d..39cea58 100644 --- a/net/quic/quic_stream_sequencer_test.cc +++ b/net/quic/quic_stream_sequencer_test.cc
@@ -69,13 +69,6 @@ QuicStreamSequencerPeer::GetBufferedFrames(sequencer_.get())) { } - bool VerifyReadableRegions(const char** expected, size_t num_expected) { - iovec iovecs[5]; - size_t num_iovecs = sequencer_->GetReadableRegions(iovecs, - arraysize(iovecs)); - return VerifyIovecs(iovecs, num_iovecs, expected, num_expected); - } - bool VerifyIovecs(iovec* iovecs, size_t num_iovecs, const char** expected,
diff --git a/net/quic/quic_time.cc b/net/quic/quic_time.cc index 5d653a3..6d31557 100644 --- a/net/quic/quic_time.cc +++ b/net/quic/quic_time.cc
@@ -173,6 +173,7 @@ return QuicWallTime(seconds); } +// TODO(ianswett) Test this. QuicWallTime QuicWallTime::Subtract(QuicTime::Delta delta) const { uint64 seconds = seconds_ - delta.ToSeconds(); if (seconds > seconds_) {
diff --git a/net/quic/quic_time_wait_list_manager.cc b/net/quic/quic_time_wait_list_manager.cc index 2e3e16d5..a5384b7 100644 --- a/net/quic/quic_time_wait_list_manager.cc +++ b/net/quic/quic_time_wait_list_manager.cc
@@ -113,10 +113,8 @@ connection_id_map_.erase(it); } TrimTimeWaitListIfNeeded(); - if (FLAGS_quic_limit_time_wait_list_size) { - DCHECK_LT(num_connections(), - static_cast<size_t>(FLAGS_quic_time_wait_list_max_connections)); - } + DCHECK_LT(num_connections(), + static_cast<size_t>(FLAGS_quic_time_wait_list_max_connections)); ConnectionIdData data(num_packets, version, helper_->GetClock()->ApproximateNow(), @@ -291,36 +289,20 @@ void QuicTimeWaitListManager::CleanUpOldConnectionIds() { QuicTime now = helper_->GetClock()->ApproximateNow(); QuicTime expiration = now.Subtract(kTimeWaitPeriod_); - if (FLAGS_quic_limit_time_wait_list_size) { - while (MaybeExpireOldestConnection(expiration)) { - } - } else { - while (!connection_id_map_.empty()) { - ConnectionIdMap::iterator it = connection_id_map_.begin(); - QuicTime oldest_connection_id = it->second.time_added; - if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) { - break; - } - const QuicConnectionId connection_id = it->first; - // This connection_id has lived its age, retire it now. - delete it->second.close_packet; - connection_id_map_.erase(it); - visitor_->OnConnectionRemovedFromTimeWaitList(connection_id); - } + + while (MaybeExpireOldestConnection(expiration)) { } SetConnectionIdCleanUpAlarm(); } void QuicTimeWaitListManager::TrimTimeWaitListIfNeeded() { - if (FLAGS_quic_limit_time_wait_list_size) { - if (FLAGS_quic_time_wait_list_max_connections < 0) { - return; - } - while (num_connections() >= - static_cast<size_t>(FLAGS_quic_time_wait_list_max_connections)) { - MaybeExpireOldestConnection(QuicTime::Infinite()); - } + if (FLAGS_quic_time_wait_list_max_connections < 0) { + return; + } + while (num_connections() >= + static_cast<size_t>(FLAGS_quic_time_wait_list_max_connections)) { + MaybeExpireOldestConnection(QuicTime::Infinite()); } }
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc index be665d2..5f29a2b 100644 --- a/net/quic/quic_unacked_packet_map.cc +++ b/net/quic/quic_unacked_packet_map.cc
@@ -273,7 +273,7 @@ QuicPacketSequenceNumber sequence_number, const TransmissionInfo& info) const { return (!IsPacketUsefulForMeasuringRtt(sequence_number, info) || - unacked_packets_.size() > kMaxTcpCongestionWindow) && + unacked_packets_.size() > kMaxTrackedPackets / 2) && !IsPacketUsefulForCongestionControl(info) && !IsPacketUsefulForRetransmittableData(info); }
diff --git a/net/quic/quic_unacked_packet_map_test.cc b/net/quic/quic_unacked_packet_map_test.cc index 2077c67..0e1d68aa 100644 --- a/net/quic/quic_unacked_packet_map_test.cc +++ b/net/quic/quic_unacked_packet_map_test.cc
@@ -126,9 +126,9 @@ TEST_F(QuicUnackedPacketMapTest, DiscardOldRttOnly) { // Acks are only tracked for RTT measurement purposes, and are discarded - // when more than 200 accumulate. - const size_t kNumUnackedPackets = 200; - for (size_t i = 1; i < 400; ++i) { + // when more than 2500 accumulate. + const size_t kNumUnackedPackets = 2500; + for (size_t i = 1; i < 3000; ++i) { unacked_packets_.AddSentPacket(CreateNonRetransmittablePacket(i), 0, NOT_RETRANSMISSION, now_, kDefaultAckLength, false);
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index 17e74618..998f0e0 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc
@@ -123,15 +123,6 @@ } // static -void QuicUtils::SerializeUint128(uint128 v, uint8* out) { - const uint64 lo = Uint128Low64(v); - const uint64 hi = Uint128High64(v); - // This assumes that the system is little-endian. - memcpy(out, &lo, sizeof(lo)); - memcpy(out + sizeof(lo), &hi, sizeof(hi)); -} - -// static void QuicUtils::SerializeUint128Short(uint128 v, uint8* out) { const uint64 lo = Uint128Low64(v); const uint64 hi = Uint128High64(v); @@ -347,11 +338,6 @@ } // static -QuicPriority QuicUtils::LowestPriority() { - return QuicWriteBlockedList::kLowestPriority; -} - -// static QuicPriority QuicUtils::HighestPriority() { return QuicWriteBlockedList::kHighestPriority; }
diff --git a/net/quic/quic_utils.h b/net/quic/quic_utils.h index 5e76a0d..46652f2 100644 --- a/net/quic/quic_utils.h +++ b/net/quic/quic_utils.h
@@ -56,9 +56,6 @@ QuicTag* out_result, size_t* out_index); - // SerializeUint128 writes |v| in little-endian form to |out|. - static void SerializeUint128(uint128 v, uint8* out); - // SerializeUint128 writes the first 96 bits of |v| in little-endian form // to |out|. static void SerializeUint128Short(uint128 v, uint8* out); @@ -97,8 +94,6 @@ return reinterpret_cast<char*>(data); } - static QuicPriority LowestPriority(); - static QuicPriority HighestPriority(); private:
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index 8f34cf5..c997d6b8 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc
@@ -348,27 +348,25 @@ // A FIN with zero data payload should not be flow control blocked. bool fin_with_zero_data = (fin && write_length == 0); - if (flow_controller_.IsEnabled()) { - // How much data we are allowed to write from flow control. - QuicByteCount send_window = flow_controller_.SendWindowSize(); - if (stream_contributes_to_connection_flow_control_) { - send_window = - min(send_window, connection_flow_controller_->SendWindowSize()); - } + // How much data we are allowed to write from flow control. + QuicByteCount send_window = flow_controller_.SendWindowSize(); + if (stream_contributes_to_connection_flow_control_) { + send_window = + min(send_window, connection_flow_controller_->SendWindowSize()); + } - if (send_window == 0 && !fin_with_zero_data) { - // Quick return if we can't send anything. - MaybeSendBlocked(); - return QuicConsumedData(0, false); - } + if (send_window == 0 && !fin_with_zero_data) { + // Quick return if we can't send anything. + MaybeSendBlocked(); + return QuicConsumedData(0, false); + } - if (write_length > send_window) { - // Don't send the FIN if we aren't going to send all the data. - fin = false; + if (write_length > send_window) { + // Don't send the FIN if we aren't going to send all the data. + fin = false; - // Writing more data would be a violation of flow control. - write_length = static_cast<size_t>(send_window); - } + // Writing more data would be a violation of flow control. + write_length = static_cast<size_t>(send_window); } // Fill an IOVector with bytes from the iovec. @@ -458,10 +456,6 @@ void ReliableQuicStream::OnWindowUpdateFrame( const QuicWindowUpdateFrame& frame) { - if (!flow_controller_.IsEnabled()) { - DLOG(DFATAL) << "Flow control not enabled! " << version(); - return; - } if (flow_controller_.UpdateSendWindowOffset(frame.byte_offset)) { // We can write again! // TODO(rjshade): This does not respect priorities (e.g. multiple @@ -474,9 +468,6 @@ bool ReliableQuicStream::MaybeIncreaseHighestReceivedOffset( QuicStreamOffset new_offset) { - if (!flow_controller_.IsEnabled()) { - return false; - } uint64 increment = new_offset - flow_controller_.highest_received_byte_offset(); if (!flow_controller_.UpdateHighestReceivedOffset(new_offset)) { @@ -495,24 +486,20 @@ } void ReliableQuicStream::AddBytesSent(QuicByteCount bytes) { - if (flow_controller_.IsEnabled()) { - flow_controller_.AddBytesSent(bytes); - if (stream_contributes_to_connection_flow_control_) { - connection_flow_controller_->AddBytesSent(bytes); - } + flow_controller_.AddBytesSent(bytes); + if (stream_contributes_to_connection_flow_control_) { + connection_flow_controller_->AddBytesSent(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_) { - flow_controller_.AddBytesConsumed(bytes); - } + // Only adjust stream level flow controller if we are still reading. + if (!read_side_closed_) { + flow_controller_.AddBytesConsumed(bytes); + } - if (stream_contributes_to_connection_flow_control_) { - connection_flow_controller_->AddBytesConsumed(bytes); - } + if (stream_contributes_to_connection_flow_control_) { + connection_flow_controller_->AddBytesConsumed(bytes); } }
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc index cecae4b..5073e1e 100644 --- a/net/quic/reliable_quic_stream_test.cc +++ b/net/quic/reliable_quic_stream_test.cc
@@ -105,10 +105,6 @@ "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo "; } - void set_supported_versions(const QuicVersionVector& versions) { - supported_versions_ = versions; - } - void Initialize(bool stream_should_process_data) { connection_ = new StrictMock<MockConnection>(kIsServer, supported_versions_);
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc index 201d451b..dd75ca8 100644 --- a/net/quic/test_tools/quic_connection_peer.cc +++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -67,35 +67,12 @@ } // static -QuicReceivedPacketManager* QuicConnectionPeer::GetReceivedPacketManager( - QuicConnection* connection) { - return &connection->received_packet_manager_; -} - -// static QuicTime::Delta QuicConnectionPeer::GetNetworkTimeout( QuicConnection* connection) { return connection->idle_network_timeout_; } // static -bool QuicConnectionPeer::IsSavedForRetransmission( - QuicConnection* connection, - QuicPacketSequenceNumber sequence_number) { - return connection->sent_packet_manager_.IsUnacked(sequence_number) && - connection->sent_packet_manager_.HasRetransmittableFrames( - sequence_number); -} - -// static -bool QuicConnectionPeer::IsRetransmission( - QuicConnection* connection, - QuicPacketSequenceNumber sequence_number) { - return QuicSentPacketManagerPeer::IsRetransmission( - &connection->sent_packet_manager_, sequence_number); -} - -// static // TODO(ianswett): Create a GetSentEntropyHash which accepts an AckFrame. QuicPacketEntropyHash QuicConnectionPeer::GetSentEntropyHash( QuicConnection* connection, @@ -240,12 +217,6 @@ } // static -void QuicConnectionPeer::SetSupportedVersions(QuicConnection* connection, - QuicVersionVector versions) { - connection->framer_.SetSupportedVersions(versions); -} - -// static QuicPacketHeader* QuicConnectionPeer::GetLastHeader( QuicConnection* connection) { return &connection->last_header_;
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h index 086e353..67463380 100644 --- a/net/quic/test_tools/quic_connection_peer.h +++ b/net/quic/test_tools/quic_connection_peer.h
@@ -53,18 +53,8 @@ static QuicSentPacketManager* GetSentPacketManager( QuicConnection* connection); - static QuicReceivedPacketManager* GetReceivedPacketManager( - QuicConnection* connection); - static QuicTime::Delta GetNetworkTimeout(QuicConnection* connection); - static bool IsSavedForRetransmission( - QuicConnection* connection, - QuicPacketSequenceNumber sequence_number); - - static bool IsRetransmission(QuicConnection* connection, - QuicPacketSequenceNumber sequence_number); - static QuicPacketEntropyHash GetSentEntropyHash( QuicConnection* connection, QuicPacketSequenceNumber sequence_number); @@ -115,9 +105,6 @@ static QuicEncryptedPacket* GetConnectionClosePacket( QuicConnection* connection); - static void SetSupportedVersions(QuicConnection* connection, - QuicVersionVector versions); - static QuicPacketHeader* GetLastHeader(QuicConnection* connection); static void SetSequenceNumberOfLastSentPacket(
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 4e182ab..c50a1715 100644 --- a/net/quic/test_tools/quic_sent_packet_manager_peer.cc +++ b/net/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -78,20 +78,6 @@ } // static -QuicPacketCount QuicSentPacketManagerPeer::GetNackCount( - const QuicSentPacketManager* sent_packet_manager, - QuicPacketSequenceNumber sequence_number) { - return sent_packet_manager->unacked_packets_. - GetTransmissionInfo(sequence_number).nack_count; -} - -// static -size_t QuicSentPacketManagerPeer::GetPendingRetransmissionCount( - const QuicSentPacketManager* sent_packet_manager) { - return sent_packet_manager->pending_retransmissions_.size(); -} - -// static bool QuicSentPacketManagerPeer::HasPendingPackets( const QuicSentPacketManager* sent_packet_manager) { return sent_packet_manager->unacked_packets_.HasInFlightPackets();
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 6ac34ffc..3543a1b 100644 --- a/net/quic/test_tools/quic_sent_packet_manager_peer.h +++ b/net/quic/test_tools/quic_sent_packet_manager_peer.h
@@ -44,13 +44,6 @@ static RttStats* GetRttStats(QuicSentPacketManager* sent_packet_manager); - static QuicPacketCount GetNackCount( - const QuicSentPacketManager* sent_packet_manager, - QuicPacketSequenceNumber sequence_number); - - static size_t GetPendingRetransmissionCount( - const QuicSentPacketManager* sent_packet_manager); - static bool HasPendingPackets( const QuicSentPacketManager* sent_packet_manager);
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 5282d62..900bb150 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h
@@ -42,7 +42,6 @@ static const QuicStreamId kClientDataStreamId1 = 5; static const QuicStreamId kClientDataStreamId2 = 7; static const QuicStreamId kClientDataStreamId3 = 9; -static const QuicStreamId kClientDataStreamId4 = 11; // Returns the test peer IP address. IPAddressNumber TestPeerIPAddress();
diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc index f9f37ad5..431f446 100644 --- a/net/quic/test_tools/simple_quic_framer.cc +++ b/net/quic/test_tools/simple_quic_framer.cc
@@ -208,10 +208,6 @@ return visitor_->version_negotiation_packet(); } -const QuicPublicResetPacket* SimpleQuicFramer::public_reset_packet() const { - return visitor_->public_reset_packet(); -} - QuicFramer* SimpleQuicFramer::framer() { return &framer_; }
diff --git a/net/quic/test_tools/simple_quic_framer.h b/net/quic/test_tools/simple_quic_framer.h index 4e2ed31..aab23ff 100644 --- a/net/quic/test_tools/simple_quic_framer.h +++ b/net/quic/test_tools/simple_quic_framer.h
@@ -48,7 +48,6 @@ const std::vector<QuicStreamFrame>& stream_frames() const; const QuicFecData& fec_data() const; const QuicVersionNegotiationPacket* version_negotiation_packet() const; - const QuicPublicResetPacket* public_reset_packet() const; QuicFramer* framer();
diff --git a/net/sdch/sdch_owner.cc b/net/sdch/sdch_owner.cc index 4e3eef0d..1396c79 100644 --- a/net/sdch/sdch_owner.cc +++ b/net/sdch/sdch_owner.cc
@@ -63,7 +63,7 @@ // Adjust SDCH limits downwards for mobile. #if defined(OS_ANDROID) || defined(OS_IOS) // static -const size_t SdchOwner::kMaxTotalDictionarySize = 1000 * 1000; +const size_t SdchOwner::kMaxTotalDictionarySize = 500 * 1000; #else // static const size_t SdchOwner::kMaxTotalDictionarySize = 20 * 1000 * 1000;
diff --git a/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java b/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java index dd40220..48c257e 100644 --- a/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java +++ b/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
@@ -80,11 +80,14 @@ final boolean mIsRedirect; final Runnable mResponseAction; final boolean mIsNotFound; + final boolean mIsNoContent; Response(byte[] responseData, List<Pair<String, String>> responseHeaders, - boolean isRedirect, boolean isNotFound, Runnable responseAction) { + boolean isRedirect, boolean isNotFound, boolean isNoContent, + Runnable responseAction) { mIsRedirect = isRedirect; mIsNotFound = isNotFound; + mIsNoContent = isNoContent; mResponseData = responseData; mResponseHeaders = responseHeaders == null ? new ArrayList<Pair<String, String>>() : responseHeaders; @@ -208,6 +211,7 @@ private static final int RESPONSE_STATUS_NORMAL = 0; private static final int RESPONSE_STATUS_MOVED_TEMPORARILY = 1; private static final int RESPONSE_STATUS_NOT_FOUND = 2; + private static final int RESPONSE_STATUS_NO_CONTENT = 3; private String setResponseInternal( String requestPath, byte[] responseData, @@ -215,10 +219,12 @@ int status) { final boolean isRedirect = (status == RESPONSE_STATUS_MOVED_TEMPORARILY); final boolean isNotFound = (status == RESPONSE_STATUS_NOT_FOUND); + final boolean isNoContent = (status == RESPONSE_STATUS_NO_CONTENT); synchronized (mLock) { mResponseMap.put(requestPath, new Response( - responseData, responseHeaders, isRedirect, isNotFound, responseAction)); + responseData, responseHeaders, isRedirect, isNotFound, isNoContent, + responseAction)); mResponseCountMap.put(requestPath, Integer.valueOf(0)); mLastRequestMap.put(requestPath, null); } @@ -251,6 +257,18 @@ } /** + * Sets a 204 (no content) response to be returned when a particular request path is passed in. + * + * @param requestPath The path to respond to. + * @return The full URL including the path that should be requested to get the expected + * response. + */ + public String setResponseWithNoContentStatus(String requestPath) { + return setResponseInternal( + requestPath, "".getBytes(), null, null, RESPONSE_STATUS_NO_CONTENT); + } + + /** * Sets a response to be returned when a particular request path is passed * in (with the option to specify additional headers). * @@ -451,6 +469,10 @@ } else if (response.mIsNotFound) { httpResponse = createResponse(HttpStatus.SC_NOT_FOUND); servedResponseFor(path, request); + } else if (response.mIsNoContent) { + httpResponse = createResponse(HttpStatus.SC_NO_CONTENT); + httpResponse.setHeader("Content-Length", "0"); + servedResponseFor(path, request); } else if (response.mIsRedirect) { httpResponse = createResponse(HttpStatus.SC_MOVED_TEMPORARILY); for (Pair<String, String> header : response.mResponseHeaders) {
diff --git a/net/test/gtest_util.h b/net/test/gtest_util.h index 14492c2..1d6708774 100644 --- a/net/test/gtest_util.h +++ b/net/test/gtest_util.h
@@ -7,8 +7,8 @@ #ifndef NET_QUIC_TEST_TOOLS_GTEST_UTIL_H_ #define NET_QUIC_TEST_TOOLS_GTEST_UTIL_H_ +#include "base/test/mock_log.h" #include "net/test/scoped_disable_exit_on_dfatal.h" -#include "net/test/scoped_mock_log.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -17,26 +17,25 @@ // Internal implementation for the EXPECT_DFATAL and ASSERT_DFATAL // macros. Do not use this directly. -#define GTEST_DFATAL_(statement, matcher, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (true) { \ - ::net::test::ScopedMockLog gtest_log; \ - ::net::test::ScopedDisableExitOnDFatal gtest_disable_exit; \ - using ::testing::_; \ - EXPECT_CALL(gtest_log, Log(_, _, _, _, _)) \ - .WillRepeatedly(::testing::Return(false)); \ - EXPECT_CALL(gtest_log, Log(logging::LOG_DFATAL, _, _, _, matcher)) \ - .Times(::testing::AtLeast(1)) \ - .WillOnce(::testing::Return(false)); \ - gtest_log.StartCapturingLogs(); \ - { statement; } \ - gtest_log.StopCapturingLogs(); \ - if (!testing::Mock::VerifyAndClear(>est_log)) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_dfatal_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_dfatal_, __LINE__): \ - fail("") +#define GTEST_DFATAL_(statement, matcher, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (true) { \ + ::base::test::MockLog gtest_log; \ + ::net::test::ScopedDisableExitOnDFatal gtest_disable_exit; \ + using ::testing::_; \ + EXPECT_CALL(gtest_log, Log(_, _, _, _, _)) \ + .WillRepeatedly(::testing::Return(false)); \ + EXPECT_CALL(gtest_log, Log(logging::LOG_DFATAL, _, _, _, matcher)) \ + .Times(::testing::AtLeast(1)) \ + .WillOnce(::testing::Return(false)); \ + gtest_log.StartCapturingLogs(); \ + { statement; } \ + gtest_log.StopCapturingLogs(); \ + if (!testing::Mock::VerifyAndClear(>est_log)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_dfatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_dfatal_, __LINE__) : fail("") // The EXPECT_DFATAL and ASSERT_DFATAL macros are lightweight // alternatives to EXPECT_DEBUG_DEATH and ASSERT_DEBUG_DEATH. They
diff --git a/net/test/python_utils.cc b/net/test/python_utils.cc index bd0e565..7d137b7 100644 --- a/net/test/python_utils.cc +++ b/net/test/python_utils.cc
@@ -17,6 +17,10 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#if defined(OS_MACOSX) +#include "base/mac/foundation_util.h" +#endif + const char kPythonPathEnv[] = "PYTHONPATH"; void AppendToPythonPath(const base::FilePath& dir) { @@ -42,31 +46,6 @@ } } -namespace { - -#if defined(OS_MACOSX) || defined(OS_CHROMEOS) -// Search for |to_try|, rolling up the directory tree from -// |start_dir|. If found, return true and put the path to |to_try| in -// |out_dir|. If not, return false and leave |out_dir| untouched. -bool TryRelativeToDir(const base::FilePath& start_dir, - const base::FilePath& to_try, - base::FilePath* out_dir) { - base::FilePath dir(start_dir); - while (!base::DirectoryExists(dir.Append(to_try))) { - base::FilePath parent = dir.DirName(); - if (parent == dir) { - // We hit the root directory. - return false; - } - dir = parent; - } - *out_dir = dir; - return true; -} -#endif // defined(OS_MACOSX) || defined(OS_CHROMEOS) - -} // namespace - bool GetPyProtoPath(base::FilePath* dir) { // Locate the Python code generated by the protocol buffers compiler. base::FilePath generated_code_dir; @@ -75,38 +54,26 @@ return false; } - const base::FilePath kPyProto(FILE_PATH_LITERAL("pyproto")); - -#if defined(OS_MACOSX) || defined(OS_CHROMEOS) - base::FilePath source_dir; - if (!PathService::Get(base::DIR_SOURCE_ROOT, &source_dir)) { - LOG(ERROR) << "Can't find " << source_dir.value(); - return false; - } - // On Mac, and possibly Chrome OS, DIR_EXE might be pointing deep - // into the Release/ (or Debug/) directory and we can't depend on - // how far down it goes. So we walk upwards from DIR_EXE until we - // find a likely looking spot. - if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) { - LOG(WARNING) << "Can't find " << kPyProto.value() - << " next to " << generated_code_dir.value(); - // On Chrome OS, we may have installed the test binaries and support tools - // in a wholly separate location, relative to DIR_SOURCE_ROOT. We'll want - // to do a similar investigation from that point as well. - generated_code_dir = source_dir - .Append(FILE_PATH_LITERAL("out")) - .Append(FILE_PATH_LITERAL("Release")); - if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) { - LOG(WARNING) << "Can't find " << kPyProto.value() - << " next to " << generated_code_dir.value(); - return false; - } - } - generated_code_dir = *dir; +#if defined(OS_MACOSX) + if (base::mac::AmIBundled()) + generated_code_dir = generated_code_dir.DirName().DirName().DirName(); #endif - *dir = generated_code_dir.Append(kPyProto); - VLOG(2) << "Found " << kPyProto.value() << " in " << dir->value(); - return true; + + // Used for GYP. TODO(jam): remove after GN conversion. + const base::FilePath kPyProto(FILE_PATH_LITERAL("pyproto")); + if (base::DirectoryExists(generated_code_dir.Append(kPyProto))) { + *dir = generated_code_dir.Append(kPyProto); + return true; + } + + // Used for GN. + const base::FilePath kGen(FILE_PATH_LITERAL("gen")); + if (base::DirectoryExists(generated_code_dir.Append(kGen))) { + *dir = generated_code_dir.Append(kGen); + return true; + } + + return false; } #if defined(OS_WIN)
diff --git a/net/test/scoped_mock_log.cc b/net/test/scoped_mock_log.cc deleted file mode 100644 index 3bc99cb..0000000 --- a/net/test/scoped_mock_log.cc +++ /dev/null
@@ -1,58 +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 "net/test/scoped_mock_log.h" - -#include "base/logging.h" - -namespace net { -namespace test { - -// static -ScopedMockLog* ScopedMockLog::g_instance_ = NULL; - -ScopedMockLog::ScopedMockLog() : is_capturing_logs_(false) {} - -ScopedMockLog::~ScopedMockLog() { - if (is_capturing_logs_) { - StopCapturingLogs(); - } -} - -void ScopedMockLog::StartCapturingLogs() { - // We don't use CHECK(), which can generate a new LOG message, and - // thus can confuse ScopedMockLog objects or other registered - // LogSinks. - RAW_CHECK(!is_capturing_logs_); - RAW_CHECK(!g_instance_); - - is_capturing_logs_ = true; - g_instance_ = this; - previous_handler_ = logging::GetLogMessageHandler(); - logging::SetLogMessageHandler(LogMessageHandler); -} - -void ScopedMockLog::StopCapturingLogs() { - // We don't use CHECK(), which can generate a new LOG message, and - // thus can confuse ScopedMockLog objects or other registered - // LogSinks. - RAW_CHECK(is_capturing_logs_); - RAW_CHECK(g_instance_ == this); - - is_capturing_logs_ = false; - logging::SetLogMessageHandler(previous_handler_); - g_instance_ = NULL; -} - -// static -bool ScopedMockLog::LogMessageHandler(int severity, - const char* file, - int line, - size_t message_start, - const std::string& str) { - return g_instance_->Log(severity, file, line, message_start, str); -} - -} // namespace test -} // namespace net
diff --git a/net/test/scoped_mock_log.h b/net/test/scoped_mock_log.h deleted file mode 100644 index e1edfcc..0000000 --- a/net/test/scoped_mock_log.h +++ /dev/null
@@ -1,98 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_QUIC_TEST_TOOLS_SCOPED_MOCK_LOG_H_ -#define NET_QUIC_TEST_TOOLS_SCOPED_MOCK_LOG_H_ - -#include "base/logging.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { -namespace test { - -// A ScopedMockLog object intercepts LOG() messages issued during its -// lifespan. Using this together with gMock, it's very easy to test -// how a piece of code calls LOG(). The typical usage: -// -// TEST(FooTest, LogsCorrectly) { -// ScopedMockLog log; -// -// // We expect the WARNING "Something bad!" exactly twice. -// EXPECT_CALL(log, Log(WARNING, _, "Something bad!")) -// .Times(2); -// -// // We allow foo.cc to call LOG(INFO) any number of times. -// EXPECT_CALL(log, Log(INFO, HasSubstr("/foo.cc"), _)) -// .Times(AnyNumber()); -// -// log.StartCapturingLogs(); // Call this after done setting expectations. -// Foo(); // Exercises the code under test. -// } -// -// CAVEAT: base/logging does not allow a thread to call LOG() again -// when it's already inside a LOG() call. Doing so will cause a -// deadlock. Therefore, it's the user's responsibility to not call -// LOG() in an action triggered by ScopedMockLog::Log(). You may call -// RAW_LOG() instead. -class ScopedMockLog { - public: - // Creates a ScopedMockLog object that is not capturing logs. - // If it were to start to capture logs, it could be a problem if - // some other threads already exist and are logging, as the user - // hasn't had a chance to set up expectation on this object yet - // (calling a mock method before setting the expectation is - // UNDEFINED behavior). - ScopedMockLog(); - - // When the object is destructed, it stops intercepting logs. - ~ScopedMockLog(); - - // Starts log capturing if the object isn't already doing so. - // Otherwise crashes. Usually this method is called in the same - // thread that created this object. It is the user's responsibility - // to not call this method if another thread may be calling it or - // StopCapturingLogs() at the same time. - void StartCapturingLogs(); - - // Stops log capturing if the object is capturing logs. Otherwise - // crashes. Usually this method is called in the same thread that - // created this object. It is the user's responsibility to not call - // this method if another thread may be calling it or - // StartCapturingLogs() at the same time. - void StopCapturingLogs(); - - // Sets the Log Message Handler that gets passed every log message before - // it's sent to other log destinations (if any). - // Returns true to signal that it handled the message and the message - // should not be sent to other log destinations. - MOCK_METHOD5(Log, bool(int severity, - const char* file, - int line, - size_t message_start, - const std::string& str)); - - private: - // The currently active scoped mock log. - static ScopedMockLog* g_instance_; - - // Static function which is set as the logging message handler. - // Called once for each message. - static bool LogMessageHandler(int severity, - const char* file, - int line, - size_t message_start, - const std::string& str); - - // True if this object is currently capturing logs. - bool is_capturing_logs_; - - // The previous handler to restore when the ScopedMockLog is destroyed. - logging::LogMessageHandlerFunction previous_handler_; -}; - -} // namespace test -} // namespace net - -#endif // NET_QUIC_TEST_TOOLS_SCOPED_MOCK_LOG_H_
diff --git a/net/third_party/nss/patches/aesgcmchromium.patch b/net/third_party/nss/patches/aesgcmchromium.patch index 8549c35..0cf49a1 100644 --- a/net/third_party/nss/patches/aesgcmchromium.patch +++ b/net/third_party/nss/patches/aesgcmchromium.patch
@@ -1,7 +1,15 @@ diff -pu a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c --- a/nss/lib/ssl/ssl3con.c 2014-01-17 18:04:43.127747463 -0800 +++ b/nss/lib/ssl/ssl3con.c 2014-01-17 18:06:21.919386088 -0800 -@@ -44,6 +44,9 @@ +@@ -8,6 +8,7 @@ + + /* TODO(ekr): Implement HelloVerifyRequest on server side. OK for now. */ + ++#define _GNU_SOURCE 1 + #include "cert.h" + #include "ssl.h" + #include "cryptohi.h" /* for DSAU_ stuff */ +@@ -44,6 +45,9 @@ #ifdef NSS_ENABLE_ZLIB #include "zlib.h" #endif @@ -11,7 +19,7 @@ #ifndef PK11_SETATTRS #define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \ -@@ -1842,6 +1845,69 @@ ssl3_BuildRecordPseudoHeader(unsigned ch +@@ -1842,6 +1846,63 @@ ssl3_BuildRecordPseudoHeader(unsigned ch return 13; } @@ -31,14 +39,8 @@ +#ifdef LINUX + /* On Linux we use the system NSS libraries. Look up the PK11_Encrypt and + * PK11_Decrypt functions at run time. */ -+ void *handle = dlopen(NULL, RTLD_LAZY); -+ if (!handle) { -+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); -+ return PR_FAILURE; -+ } -+ pk11_encrypt = (PK11CryptFcn)dlsym(handle, "PK11_Encrypt"); -+ pk11_decrypt = (PK11CryptFcn)dlsym(handle, "PK11_Decrypt"); -+ dlclose(handle); ++ pk11_encrypt = (PK11CryptFcn)dlsym(RTLD_DEFAULT, "PK11_Encrypt"); ++ pk11_decrypt = (PK11CryptFcn)dlsym(RTLD_DEFAULT, "PK11_Decrypt"); + return PR_SUCCESS; +#else + /* On other platforms we use our own copy of NSS. PK11_Encrypt and @@ -81,7 +83,7 @@ static SECStatus ssl3_AESGCM(ssl3KeyMaterial *keys, PRBool doDecrypt, -@@ -1893,10 +1959,10 @@ ssl3_AESGCM(ssl3KeyMaterial *keys, +@@ -1893,10 +1960,10 @@ ssl3_AESGCM(ssl3KeyMaterial *keys, gcmParams.ulTagBits = tagSize * 8; if (doDecrypt) { @@ -94,7 +96,7 @@ maxout, in, inlen); } *outlen += (int) uOutLen; -@@ -5103,6 +5169,10 @@ ssl3_SendClientHello(sslSocket *ss, PRBo +@@ -5103,6 +5170,10 @@ ssl3_SendClientHello(sslSocket *ss, PRBo ssl3_DisableNonDTLSSuites(ss); } @@ -105,7 +107,7 @@ /* how many suites are permitted by policy and user preference? */ num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE); if (!num_suites) { -@@ -8080,6 +8150,10 @@ ssl3_HandleClientHello(sslSocket *ss, SS +@@ -8080,6 +8151,10 @@ ssl3_HandleClientHello(sslSocket *ss, SS ssl3_DisableNonDTLSSuites(ss); }
diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c index ffb757a..91a1f1e 100644 --- a/net/third_party/nss/ssl/ssl3con.c +++ b/net/third_party/nss/ssl/ssl3con.c
@@ -8,6 +8,7 @@ /* TODO(ekr): Implement HelloVerifyRequest on server side. OK for now. */ +#define _GNU_SOURCE 1 #include "cert.h" #include "ssl.h" #include "cryptohi.h" /* for DSAU_ stuff */ @@ -1884,14 +1885,8 @@ #ifdef LINUX /* On Linux we use the system NSS libraries. Look up the PK11_Encrypt and * PK11_Decrypt functions at run time. */ - void *handle = dlopen(NULL, RTLD_LAZY); - if (!handle) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return PR_FAILURE; - } - pk11_encrypt = (PK11CryptFcn)dlsym(handle, "PK11_Encrypt"); - pk11_decrypt = (PK11CryptFcn)dlsym(handle, "PK11_Decrypt"); - dlclose(handle); + pk11_encrypt = (PK11CryptFcn)dlsym(RTLD_DEFAULT, "PK11_Encrypt"); + pk11_decrypt = (PK11CryptFcn)dlsym(RTLD_DEFAULT, "PK11_Decrypt"); return PR_SUCCESS; #else /* On other platforms we use our own copy of NSS. PK11_Encrypt and
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index 8f19cf4..99219409 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc
@@ -372,28 +372,17 @@ QuicConnectionId connection_id, const IPEndPoint& server_address, const IPEndPoint& client_address) { - QuicServerSession* session = new QuicServerSession( - config_, - CreateQuicConnection(connection_id, server_address, client_address), - this); + // The QuicSession takes ownership of |connection| below. + QuicConnection* connection = new QuicConnection( + connection_id, client_address, helper_.get(), connection_writer_factory_, + /* owns_writer= */ true, /* is_server= */ true, + crypto_config_.HasProofSource(), supported_versions_); + + QuicServerSession* session = new QuicServerSession(config_, connection, this); session->InitializeSession(crypto_config_); return session; } -QuicConnection* QuicDispatcher::CreateQuicConnection( - QuicConnectionId connection_id, - const IPEndPoint& server_address, - const IPEndPoint& client_address) { - return new QuicConnection(connection_id, - client_address, - helper_.get(), - connection_writer_factory_, - /* owns_writer= */ true, - /* is_server= */ true, - crypto_config_.HasProofSource(), - supported_versions_); -} - QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() { return new QuicTimeWaitListManager( writer_.get(), this, epoll_server(), supported_versions());
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h index 36e711a..4b3fe0a 100644 --- a/net/tools/quic/quic_dispatcher.h +++ b/net/tools/quic/quic_dispatcher.h
@@ -135,11 +135,6 @@ const IPEndPoint& server_address, const IPEndPoint& client_address); - virtual QuicConnection* CreateQuicConnection( - QuicConnectionId connection_id, - const IPEndPoint& server_address, - const IPEndPoint& client_address); - // Called by |framer_visitor_| when the public header has been parsed. virtual bool OnUnauthenticatedPublicHeader( const QuicPacketPublicHeader& header); @@ -148,11 +143,6 @@ // will be owned by the dispatcher as time_wait_list_manager_ virtual QuicTimeWaitListManager* CreateQuicTimeWaitListManager(); - // Replaces the packet writer with |writer|. Takes ownership of |writer|. - void set_writer(QuicPacketWriter* writer) { - writer_.reset(writer); - } - QuicTimeWaitListManager* time_wait_list_manager() { return time_wait_list_manager_.get(); }
diff --git a/net/tools/quic/quic_packet_writer_wrapper.cc b/net/tools/quic/quic_packet_writer_wrapper.cc index 3d1b03d..3befce9e 100644 --- a/net/tools/quic/quic_packet_writer_wrapper.cc +++ b/net/tools/quic/quic_packet_writer_wrapper.cc
@@ -40,9 +40,5 @@ writer_.reset(writer); } -QuicPacketWriter* QuicPacketWriterWrapper::release_writer() { - return writer_.release(); -} - } // namespace tools } // namespace net
diff --git a/net/tools/quic/quic_packet_writer_wrapper.h b/net/tools/quic/quic_packet_writer_wrapper.h index a8b819c..ca366b55 100644 --- a/net/tools/quic/quic_packet_writer_wrapper.h +++ b/net/tools/quic/quic_packet_writer_wrapper.h
@@ -34,9 +34,6 @@ // Takes ownership of |writer|. void set_writer(QuicPacketWriter* writer); - // Releases ownership of |writer_|. - QuicPacketWriter* release_writer(); - private: scoped_ptr<QuicPacketWriter> writer_;
diff --git a/net/tools/quic/quic_server.h b/net/tools/quic/quic_server.h index 31e5988..7c50371f 100644 --- a/net/tools/quic/quic_server.h +++ b/net/tools/quic/quic_server.h
@@ -133,10 +133,6 @@ // skipped as necessary). QuicVersionVector supported_versions_; - // Size of flow control receive window to advertise to clients on new - // connections. - uint32 server_initial_flow_control_receive_window_; - DISALLOW_COPY_AND_ASSIGN(QuicServer); };
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc index 71c2b42..8074d31 100644 --- a/net/tools/quic/quic_server_session_test.cc +++ b/net/tools/quic/quic_server_session_test.cc
@@ -36,7 +36,6 @@ using net::test::kClientDataStreamId1; using net::test::kClientDataStreamId2; using net::test::kClientDataStreamId3; -using net::test::kClientDataStreamId4; using std::string; using testing::StrictMock; using testing::_; @@ -51,9 +50,6 @@ QuicServerSession* s, QuicStreamId id) { return s->GetIncomingDataStream(id); } - static QuicDataStream* GetDataStream(QuicServerSession* s, QuicStreamId id) { - return s->GetDataStream(id); - } static void SetCryptoStream(QuicServerSession* s, QuicCryptoServerStream* crypto_stream) { s->crypto_stream_.reset(crypto_stream); @@ -87,8 +83,6 @@ visitor_ = QuicConnectionPeer::GetVisitor(connection_); } - QuicVersion version() const { return connection_->version(); } - StrictMock<MockQuicServerSessionVisitor> owner_; StrictMock<MockConnection>* connection_; QuicConfig config_;
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc index c9e589c..98f96ec 100644 --- a/net/tools/quic/quic_time_wait_list_manager.cc +++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -118,10 +118,8 @@ connection_id_map_.erase(it); } TrimTimeWaitListIfNeeded(); - if (FLAGS_quic_limit_time_wait_list_size) { - DCHECK_LT(num_connections(), - static_cast<size_t>(FLAGS_quic_time_wait_list_max_connections)); - } + DCHECK_LT(num_connections(), + static_cast<size_t>(FLAGS_quic_time_wait_list_max_connections)); ConnectionIdData data(num_packets, version, clock_.ApproximateNow(), @@ -300,36 +298,20 @@ void QuicTimeWaitListManager::CleanUpOldConnectionIds() { QuicTime now = clock_.ApproximateNow(); QuicTime expiration = now.Subtract(kTimeWaitPeriod_); - if (FLAGS_quic_limit_time_wait_list_size) { - while (MaybeExpireOldestConnection(expiration)) { - } - } else { - while (!connection_id_map_.empty()) { - ConnectionIdMap::iterator it = connection_id_map_.begin(); - QuicTime oldest_connection_id = it->second.time_added; - if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) { - break; - } - const QuicConnectionId connection_id = it->first; - // This connection_id has lived its age, retire it now. - delete it->second.close_packet; - connection_id_map_.erase(it); - visitor_->OnConnectionRemovedFromTimeWaitList(connection_id); - } + + while (MaybeExpireOldestConnection(expiration)) { } SetConnectionIdCleanUpAlarm(); } void QuicTimeWaitListManager::TrimTimeWaitListIfNeeded() { - if (FLAGS_quic_limit_time_wait_list_size) { - if (FLAGS_quic_time_wait_list_max_connections < 0) { - return; - } - while (num_connections() >= - static_cast<size_t>(FLAGS_quic_time_wait_list_max_connections)) { - MaybeExpireOldestConnection(QuicTime::Infinite()); - } + if (FLAGS_quic_time_wait_list_max_connections < 0) { + return; + } + while (num_connections() >= + static_cast<size_t>(FLAGS_quic_time_wait_list_max_connections)) { + MaybeExpireOldestConnection(QuicTime::Infinite()); } }
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc index bddcc176..f67fe7e2 100644 --- a/net/tools/quic/quic_time_wait_list_manager_test.cc +++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -488,7 +488,6 @@ } TEST_F(QuicTimeWaitListManagerTest, MaxConnectionsTest) { - ValueRestore<bool> old_flag(&FLAGS_quic_limit_time_wait_list_size, true); // Basically, shut off time-based eviction. FLAGS_quic_time_wait_list_seconds = 10000000000; FLAGS_quic_time_wait_list_max_connections = 5;
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.h b/net/tools/quic/test_tools/packet_dropping_test_writer.h index cdd8efc..b39539f0 100644 --- a/net/tools/quic/test_tools/packet_dropping_test_writer.h +++ b/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -104,6 +104,7 @@ buffer_size_ = buffer_size; } + // Useful for reproducing very flaky issues. void set_seed(uint64 seed) { simple_random_.set_seed(seed); }
diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.cc b/net/tools/quic/test_tools/quic_dispatcher_peer.cc index 1900420..5d3ce7a 100644 --- a/net/tools/quic/test_tools/quic_dispatcher_peer.cc +++ b/net/tools/quic/test_tools/quic_dispatcher_peer.cc
@@ -44,17 +44,6 @@ } // static -QuicConnection* QuicDispatcherPeer::CreateQuicConnection( - QuicDispatcher* dispatcher, - QuicConnectionId connection_id, - const IPEndPoint& server, - const IPEndPoint& client) { - return dispatcher->CreateQuicConnection(connection_id, - server, - client); -} - -// static QuicDispatcher::WriteBlockedList* QuicDispatcherPeer::GetWriteBlockedList( QuicDispatcher* dispatcher) { return &dispatcher->write_blocked_list_;
diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.h b/net/tools/quic/test_tools/quic_dispatcher_peer.h index 62716157..e5edf16 100644 --- a/net/tools/quic/test_tools/quic_dispatcher_peer.h +++ b/net/tools/quic/test_tools/quic_dispatcher_peer.h
@@ -34,12 +34,6 @@ static QuicEpollConnectionHelper* GetHelper(QuicDispatcher* dispatcher); - static QuicConnection* CreateQuicConnection( - QuicDispatcher* dispatcher, - QuicConnectionId connection_id, - const IPEndPoint& server, - const IPEndPoint& client); - static QuicDispatcher::WriteBlockedList* GetWriteBlockedList( QuicDispatcher* dispatcher);
diff --git a/net/tools/quic/test_tools/quic_test_server.cc b/net/tools/quic/test_tools/quic_test_server.cc deleted file mode 100644 index 3d6c247..0000000 --- a/net/tools/quic/test_tools/quic_test_server.cc +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/tools/quic/test_tools/quic_test_server.h" - -namespace net { - -namespace tools { - -namespace test { - -class QuicTestDispatcher : public QuicDispatcher { - public: - QuicTestDispatcher(const QuicConfig& config, - const QuicCryptoServerConfig& crypto_config, - const QuicVersionVector& versions, - PacketWriterFactory* factory, - EpollServer* eps) - : QuicDispatcher(config, crypto_config, versions, factory, eps) {} - QuicSession* CreateQuicSession(QuicConnectionId id, - const IPEndPoint& server, - const IPEndPoint& client) override { - if (session_creator_ == nullptr) { - return QuicDispatcher::CreateQuicSession(id, server, client); - } else { - QuicConnection* connection = CreateQuicConnection(id, server, client); - QuicServerSession* session = - (session_creator_)(config(), connection, this); - session->InitializeSession(crypto_config()); - return session; - } - } - - void set_session_creator( - const QuicTestServer::SessionCreationFunction& function) { - session_creator_ = function; - } - - private: - QuicTestServer::SessionCreationFunction session_creator_; -}; - -QuicDispatcher* QuicTestServer::CreateQuicDispatcher() { - return new QuicTestDispatcher( - config(), crypto_config(), supported_versions(), - new QuicDispatcher::DefaultPacketWriterFactory(), epoll_server()); -} - -void QuicTestServer::SetSessionCreator( - const SessionCreationFunction& function) { - static_cast<QuicTestDispatcher*>(dispatcher())->set_session_creator(function); -} - -/////////////////////////// TEST SESSIONS /////////////////////////////// - -ImmediateGoAwaySession::ImmediateGoAwaySession( - const QuicConfig& config, - QuicConnection* connection, - QuicServerSessionVisitor* visitor) - : QuicServerSession(config, connection, visitor) { - SendGoAway(QUIC_PEER_GOING_AWAY, ""); -} - -} // namespace test - -} // namespace tools - -} // namespace net
diff --git a/net/tools/quic/test_tools/quic_test_server.h b/net/tools/quic/test_tools/quic_test_server.h deleted file mode 100644 index 1e56e43..0000000 --- a/net/tools/quic/test_tools/quic_test_server.h +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_SERVER_H_ -#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_SERVER_H_ - -#include "net/tools/quic/quic_dispatcher.h" -#include "net/tools/quic/quic_server.h" -#include "net/tools/quic/quic_server_session.h" - -namespace net { - -namespace tools { - -namespace test { - -// A test server which enables easy creation of custom QuicServerSessions -// -// Eventually this may be extended to allow custom QuicConnections etc. -class QuicTestServer : public QuicServer { - public: - typedef std::function<QuicServerSession*(const QuicConfig& config, - QuicConnection* connection, - QuicServerSessionVisitor* visitor)> - SessionCreationFunction; - - // Create a custom dispatcher which creates custom sessions. - QuicDispatcher* CreateQuicDispatcher() override; - - void SetSessionCreator(const SessionCreationFunction& function); -}; - -// Useful test sessions for the QuicTestServer. - -// Test session which sends a GOAWAY immedaitely on creation, before crypto -// credentials have even been established. -class ImmediateGoAwaySession : public QuicServerSession { - public: - ImmediateGoAwaySession(const QuicConfig& config, - QuicConnection* connection, - QuicServerSessionVisitor* visitor); -}; - -} // namespace test - -} // namespace tools - -} // namespace net - -#endif // NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_SERVER_H_
diff --git a/net/tools/stress_cache/stress_cache.cc b/net/tools/stress_cache/stress_cache.cc new file mode 100644 index 0000000..b63ce21 --- /dev/null +++ b/net/tools/stress_cache/stress_cache.cc
@@ -0,0 +1,293 @@ +// 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 is a simple application that stress-tests the crash recovery of the disk +// cache. The main application starts a copy of itself on a loop, checking the +// exit code of the child process. When the child dies in an unexpected way, +// the main application quits. + +// The child application has two threads: one to exercise the cache in an +// infinite loop, and another one to asynchronously kill the process. + +// A regular build should never crash. +// To test that the disk cache doesn't generate critical errors with regular +// application level crashes, edit stress_support.h. + +#include <string> +#include <vector> + +#include "base/at_exit.h" +#include "base/bind.h" +#include "base/command_line.h" +#include "base/debug/debugger.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/path_service.h" +#include "base/process/launch.h" +#include "base/process/process.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/platform_thread.h" +#include "base/threading/thread.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" +#include "net/base/test_completion_callback.h" +#include "net/disk_cache/blockfile/backend_impl.h" +#include "net/disk_cache/blockfile/stress_support.h" +#include "net/disk_cache/blockfile/trace.h" +#include "net/disk_cache/disk_cache.h" +#include "net/disk_cache/disk_cache_test_util.h" + +#if defined(OS_WIN) +#include "base/logging_win.h" +#endif + +using base::Time; + +const int kError = -1; +const int kExpectedCrash = 100; + +// Starts a new process. +int RunSlave(int iteration) { + base::FilePath exe; + PathService::Get(base::FILE_EXE, &exe); + + base::CommandLine cmdline(exe); + cmdline.AppendArg(base::IntToString(iteration)); + + base::Process process = base::LaunchProcess(cmdline, base::LaunchOptions()); + if (!process.IsValid()) { + printf("Unable to run test\n"); + return kError; + } + + int exit_code; + if (!process.WaitForExit(&exit_code)) { + printf("Unable to get return code\n"); + return kError; + } + return exit_code; +} + +// Main loop for the master process. +int MasterCode() { + for (int i = 0; i < 100000; i++) { + int ret = RunSlave(i); + if (kExpectedCrash != ret) + return ret; + } + + printf("More than enough...\n"); + + return 0; +} + +// ----------------------------------------------------------------------- + +std::string GenerateStressKey() { + char key[20 * 1024]; + size_t size = 50 + rand() % 20000; + CacheTestFillBuffer(key, size, true); + + key[size - 1] = '\0'; + return std::string(key); +} + +// This thread will loop forever, adding and removing entries from the cache. +// iteration is the current crash cycle, so the entries on the cache are marked +// to know which instance of the application wrote them. +void StressTheCache(int iteration) { + int cache_size = 0x2000000; // 32MB. + uint32 mask = 0xfff; // 4096 entries. + + base::FilePath path; + PathService::Get(base::DIR_TEMP, &path); + path = path.AppendASCII("cache_test_stress"); + + base::Thread cache_thread("CacheThread"); + if (!cache_thread.StartWithOptions( + base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) + return; + + disk_cache::BackendImpl* cache = + new disk_cache::BackendImpl(path, mask, + cache_thread.message_loop_proxy().get(), + NULL); + cache->SetMaxSize(cache_size); + cache->SetFlags(disk_cache::kNoLoadProtection); + + net::TestCompletionCallback cb; + int rv = cache->Init(cb.callback()); + + if (cb.GetResult(rv) != net::OK) { + printf("Unable to initialize cache.\n"); + return; + } + printf("Iteration %d, initial entries: %d\n", iteration, + cache->GetEntryCount()); + + int seed = static_cast<int>(Time::Now().ToInternalValue()); + srand(seed); + + // kNumKeys is meant to be enough to have about 3x or 4x iterations before + // the process crashes. +#ifdef NDEBUG + const int kNumKeys = 4000; +#else + const int kNumKeys = 1200; +#endif + const int kNumEntries = 30; + std::string keys[kNumKeys]; + disk_cache::Entry* entries[kNumEntries] = {0}; + + for (int i = 0; i < kNumKeys; i++) { + keys[i] = GenerateStressKey(); + } + + const int kSize = 20000; + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); + memset(buffer->data(), 'k', kSize); + + for (int i = 0;; i++) { + int slot = rand() % kNumEntries; + int key = rand() % kNumKeys; + bool truncate = (rand() % 2 == 0); + int size = kSize - (rand() % 20) * kSize / 20; + + if (entries[slot]) + entries[slot]->Close(); + + net::TestCompletionCallback cb; + rv = cache->OpenEntry(keys[key], &entries[slot], cb.callback()); + if (cb.GetResult(rv) != net::OK) { + rv = cache->CreateEntry(keys[key], &entries[slot], cb.callback()); + CHECK_EQ(net::OK, cb.GetResult(rv)); + } + + base::snprintf(buffer->data(), kSize, + "i: %d iter: %d, size: %d, truncate: %d ", i, iteration, + size, truncate ? 1 : 0); + rv = entries[slot]->WriteData(0, 0, buffer.get(), size, cb.callback(), + truncate); + CHECK_EQ(size, cb.GetResult(rv)); + + if (rand() % 100 > 80) { + key = rand() % kNumKeys; + net::TestCompletionCallback cb2; + rv = cache->DoomEntry(keys[key], cb2.callback()); + cb2.GetResult(rv); + } + + if (!(i % 100)) + printf("Entries: %d \r", i); + } +} + +// We want to prevent the timer thread from killing the process while we are +// waiting for the debugger to attach. +bool g_crashing = false; + +// RunSoon() and CrashCallback() reference each other, unfortunately. +void RunSoon(base::MessageLoop* target_loop); + +void CrashCallback() { + // Keep trying to run. + RunSoon(base::MessageLoop::current()); + + if (g_crashing) + return; + + if (rand() % 100 > 30) { + printf("sweet death...\n"); +#if defined(OS_WIN) + // Windows does more work on _exit() than we would like. + base::Process::Current().Terminate(kExpectedCrash); +#elif defined(OS_POSIX) + // On POSIX, _exit() will terminate the process with minimal cleanup, + // and it is cleaner than killing. + _exit(kExpectedCrash); +#endif + } +} + +void RunSoon(base::MessageLoop* target_loop) { + const base::TimeDelta kTaskDelay = base::TimeDelta::FromSeconds(10); + target_loop->PostDelayedTask( + FROM_HERE, base::Bind(&CrashCallback), kTaskDelay); +} + +// We leak everything here :) +bool StartCrashThread() { + base::Thread* thread = new base::Thread("party_crasher"); + if (!thread->Start()) + return false; + + RunSoon(thread->message_loop()); + return true; +} + +void CrashHandler(const std::string& str) { + g_crashing = true; + base::debug::BreakDebugger(); +} + +bool MessageHandler(int severity, const char* file, int line, + size_t message_start, const std::string& str) { + const size_t kMaxMessageLen = 48; + char message[kMaxMessageLen]; + size_t len = std::min(str.length() - message_start, kMaxMessageLen - 1); + + memcpy(message, str.c_str() + message_start, len); + message[len] = '\0'; +#if !defined(DISK_CACHE_TRACE_TO_LOG) + disk_cache::Trace("%s", message); +#endif + return false; +} + +// ----------------------------------------------------------------------- + +#if defined(OS_WIN) +// {B9A153D4-31C3-48e4-9ABF-D54383F14A0D} +const GUID kStressCacheTraceProviderName = { + 0xb9a153d4, 0x31c3, 0x48e4, + { 0x9a, 0xbf, 0xd5, 0x43, 0x83, 0xf1, 0x4a, 0xd } }; +#endif + +int main(int argc, const char* argv[]) { + // Setup an AtExitManager so Singleton objects will be destructed. + base::AtExitManager at_exit_manager; + + if (argc < 2) + return MasterCode(); + + logging::SetLogAssertHandler(CrashHandler); + logging::SetLogMessageHandler(MessageHandler); + +#if defined(OS_WIN) + logging::LogEventProvider::Initialize(kStressCacheTraceProviderName); +#else + base::CommandLine::Init(argc, argv); + logging::LoggingSettings settings; + settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; + logging::InitLogging(settings); +#endif + + // Some time for the memory manager to flush stuff. + base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(3)); + base::MessageLoopForIO message_loop; + + char* end; + long int iteration = strtol(argv[1], &end, 0); + + if (!StartCrashThread()) { + printf("failed to start thread\n"); + return kError; + } + + StressTheCache(iteration); + return 0; +}
diff --git a/pdf/DEPS b/pdf/DEPS index aeba85b..316f7e7 100644 --- a/pdf/DEPS +++ b/pdf/DEPS
@@ -4,6 +4,7 @@ "+components/ui/zoom/page_zoom_constants.h", "+net", "+ppapi", + "+printing/units.h", "+third_party/pdfium/fpdfsdk/include", "+ui/events/keycodes/keyboard_codes.h", "+v8/include/v8.h"
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index b179e1e..d247db0 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -33,6 +33,7 @@ #include "ppapi/cpp/url_response_info.h" #include "ppapi/cpp/var.h" #include "ppapi/cpp/var_dictionary.h" +#include "printing/units.h" #include "third_party/pdfium/fpdfsdk/include/fpdf_ext.h" #include "third_party/pdfium/fpdfsdk/include/fpdf_flatten.h" #include "third_party/pdfium/fpdfsdk/include/fpdf_searchex.h" @@ -45,6 +46,11 @@ #include "third_party/pdfium/fpdfsdk/include/pdfwindow/PWL_FontMap.h" #include "ui/events/keycodes/keyboard_codes.h" +using printing::ConvertUnit; +using printing::ConvertUnitDouble; +using printing::kPointsPerInch; +using printing::kPixelsPerInch; + namespace chrome_pdf { namespace { @@ -90,11 +96,6 @@ // painting the scrollbars > 60 Hz. #define kMaxInitialProgressivePaintTimeMs 10 -// Copied from printing/units.cc because we don't want to depend on printing -// since it brings in libpng which causes duplicate symbols with PDFium. -const int kPointsPerInch = 72; -const int kPixelsPerInch = 96; - struct ClipBox { float left; float right; @@ -102,17 +103,6 @@ float bottom; }; -int ConvertUnit(int value, int old_unit, int new_unit) { - // With integer arithmetic, to divide a value with correct rounding, you need - // to add half of the divisor value to the dividend value. You need to do the - // reverse with negative number. - if (value >= 0) { - return ((value * new_unit) + (old_unit / 2)) / old_unit; - } else { - return ((value * new_unit) - (old_unit / 2)) / old_unit; - } -} - std::vector<uint32_t> GetPageNumbersFromPrintPageNumberRange( const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count) { @@ -1398,11 +1388,12 @@ print_settings.orientation, FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH); - double ratio_x = (static_cast<double>(bitmap_size.width()) * kPointsPerInch) / - print_settings.dpi; - double ratio_y = - (static_cast<double>(bitmap_size.height()) * kPointsPerInch) / - print_settings.dpi; + double ratio_x = ConvertUnitDouble(bitmap_size.width(), + print_settings.dpi, + kPointsPerInch); + double ratio_y = ConvertUnitDouble(bitmap_size.height(), + print_settings.dpi, + kPointsPerInch); // Add the bitmap to an image object and add the image object to the output // page. @@ -1450,10 +1441,10 @@ source_page_height)); int width_in_pixels = ConvertUnit(source_page_width, - static_cast<int>(kPointsPerInch), + kPointsPerInch, print_settings.dpi); int height_in_pixels = ConvertUnit(source_page_height, - static_cast<int>(kPointsPerInch), + kPointsPerInch, print_settings.dpi); pp::Rect rect(width_in_pixels, height_in_pixels); @@ -1614,25 +1605,27 @@ FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_DP); } -PDFiumPage::Area PDFiumEngine::GetCharIndex( - const pp::MouseInputEvent& event, int* page_index, - int* char_index, PDFiumPage::LinkTarget* target) { +PDFiumPage::Area PDFiumEngine::GetCharIndex(const pp::MouseInputEvent& event, + int* page_index, + int* char_index, + int* form_type, + PDFiumPage::LinkTarget* target) { // First figure out which page this is in. pp::Point mouse_point = event.GetPosition(); - pp::Point point( - static_cast<int>((mouse_point.x() + position_.x()) / current_zoom_), - static_cast<int>((mouse_point.y() + position_.y()) / current_zoom_)); - return GetCharIndex(point, page_index, char_index, target); + return GetCharIndex(mouse_point, page_index, char_index, form_type, target); } -PDFiumPage::Area PDFiumEngine::GetCharIndex( - const pp::Point& point, - int* page_index, - int* char_index, - PDFiumPage::LinkTarget* target) { +PDFiumPage::Area PDFiumEngine::GetCharIndex(const pp::Point& point, + int* page_index, + int* char_index, + int* form_type, + PDFiumPage::LinkTarget* target) { int page = -1; + pp::Point point_in_page( + static_cast<int>((point.x() + position_.x()) / current_zoom_), + static_cast<int>((point.y() + position_.y()) / current_zoom_)); for (size_t i = 0; i < visible_pages_.size(); ++i) { - if (pages_[visible_pages_[i]]->rect().Contains(point)) { + if (pages_[visible_pages_[i]]->rect().Contains(point_in_page)) { page = visible_pages_[i]; break; } @@ -1648,15 +1641,11 @@ } *page_index = page; - return pages_[page]->GetCharIndex(point, current_rotation_, char_index, - target); + return pages_[page]->GetCharIndex( + point_in_page, current_rotation_, char_index, form_type, target); } bool PDFiumEngine::OnMouseDown(const pp::MouseInputEvent& event) { - if (event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_LEFT && - event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_RIGHT) { - return false; - } if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_RIGHT) { if (!selection_.size()) return false; @@ -1672,15 +1661,18 @@ selection_.clear(); return true; } + if (event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_LEFT) + return false; SelectionChangeInvalidator selection_invalidator(this); selection_.clear(); int page_index = -1; int char_index = -1; + int form_type = FPDF_FORMFIELD_UNKNOWN; PDFiumPage::LinkTarget target; - PDFiumPage::Area area = GetCharIndex(event, &page_index, - &char_index, &target); + PDFiumPage::Area area = + GetCharIndex(event, &page_index, &char_index, &form_type, &target); mouse_down_state_.Set(area, target); // Decide whether to open link or not based on user action in mouse up and @@ -1701,16 +1693,14 @@ DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y); FORM_OnLButtonDown(form_, pages_[page_index]->GetPage(), 0, page_x, page_y); - int control = FPDPage_HasFormFieldAtPoint( - form_, pages_[page_index]->GetPage(), page_x, page_y); - if (control > FPDF_FORMFIELD_UNKNOWN) { // returns -1 sometimes... + if (form_type > FPDF_FORMFIELD_UNKNOWN) { // returns -1 sometimes... + mouse_down_state_.Set(PDFiumPage::NONSELECTABLE_AREA, target); + bool is_valid_control = (form_type == FPDF_FORMFIELD_TEXTFIELD || + form_type == FPDF_FORMFIELD_COMBOBOX); #ifdef PDF_USE_XFA - client_->FormTextFieldFocusChange(control == FPDF_FORMFIELD_TEXTFIELD || - control == FPDF_FORMFIELD_COMBOBOX || control == FPDF_FORMFIELD_XFA); -#else - client_->FormTextFieldFocusChange(control == FPDF_FORMFIELD_TEXTFIELD || - control == FPDF_FORMFIELD_COMBOBOX); + is_valid_control |= (form_type == FPDF_FORMFIELD_XFA); #endif + client_->FormTextFieldFocusChange(is_valid_control); return true; // Return now before we get into the selection code. } } @@ -1769,9 +1759,10 @@ int page_index = -1; int char_index = -1; + int form_type = FPDF_FORMFIELD_UNKNOWN; PDFiumPage::LinkTarget target; PDFiumPage::Area area = - GetCharIndex(event, &page_index, &char_index, &target); + GetCharIndex(event, &page_index, &char_index, &form_type, &target); // Open link on mouse up for same link for which mouse down happened earlier. if (mouse_down_state_.Matches(area, target)) { @@ -1801,9 +1792,10 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) { int page_index = -1; int char_index = -1; + int form_type = FPDF_FORMFIELD_UNKNOWN; PDFiumPage::LinkTarget target; PDFiumPage::Area area = - GetCharIndex(event, &page_index, &char_index, &target); + GetCharIndex(event, &page_index, &char_index, &form_type, &target); // Clear |mouse_down_state_| if mouse moves away from where the mouse down // happened. @@ -1822,7 +1814,21 @@ break; case PDFiumPage::NONSELECTABLE_AREA: default: - cursor = PP_CURSORTYPE_POINTER; + switch (form_type) { + case FPDF_FORMFIELD_PUSHBUTTON: + case FPDF_FORMFIELD_CHECKBOX: + case FPDF_FORMFIELD_RADIOBUTTON: + case FPDF_FORMFIELD_COMBOBOX: + case FPDF_FORMFIELD_LISTBOX: + cursor = PP_CURSORTYPE_HAND; + break; + case FPDF_FORMFIELD_TEXTFIELD: + cursor = PP_CURSORTYPE_IBEAM; + break; + default: + cursor = PP_CURSORTYPE_POINTER; + break; + } break; } @@ -1830,24 +1836,7 @@ double page_x, page_y; pp::Point point = event.GetPosition(); DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y); - FORM_OnMouseMove(form_, pages_[page_index]->GetPage(), 0, page_x, page_y); - int control = FPDPage_HasFormFieldAtPoint( - form_, pages_[page_index]->GetPage(), page_x, page_y); - switch (control) { - case FPDF_FORMFIELD_PUSHBUTTON: - case FPDF_FORMFIELD_CHECKBOX: - case FPDF_FORMFIELD_RADIOBUTTON: - case FPDF_FORMFIELD_COMBOBOX: - case FPDF_FORMFIELD_LISTBOX: - cursor = PP_CURSORTYPE_HAND; - break; - case FPDF_FORMFIELD_TEXTFIELD: - cursor = PP_CURSORTYPE_IBEAM; - break; - default: - break; - } } client_->UpdateCursor(cursor); @@ -2321,15 +2310,16 @@ } std::string PDFiumEngine::GetLinkAtPosition(const pp::Point& point) { + std::string url; int temp; + int page_index = -1; + int form_type = FPDF_FORMFIELD_UNKNOWN; PDFiumPage::LinkTarget target; - pp::Point point_in_page( - static_cast<int>((point.x() + position_.x()) / current_zoom_), - static_cast<int>((point.y() + position_.y()) / current_zoom_)); - PDFiumPage::Area area = GetCharIndex(point_in_page, &temp, &temp, &target); + PDFiumPage::Area area = + GetCharIndex(point, &page_index, &temp, &form_type, &target); if (area == PDFiumPage::WEBLINK_AREA) - return target.url; - return std::string(); + url = target.url; + return url; } bool PDFiumEngine::IsSelecting() { @@ -2507,10 +2497,12 @@ pp::Rect page_rect(page_rects[i]); page_rect.Inset(kPageShadowLeft, kPageShadowTop, kPageShadowRight, kPageShadowBottom); - double width_in_points = - page_rect.width() * kPointsPerInch / kPixelsPerInch; - double height_in_points = - page_rect.height() * kPointsPerInch / kPixelsPerInch; + double width_in_points = ConvertUnitDouble(page_rect.width(), + kPixelsPerInch, + kPointsPerInch); + double height_in_points = ConvertUnitDouble(page_rect.height(), + kPixelsPerInch, + kPointsPerInch); FPDFPage_New(doc_, i, width_in_points, height_in_points); pages_.push_back(new PDFiumPage(this, i, page_rect, true)); } @@ -2794,9 +2786,9 @@ if (rv) { int width_in_pixels = static_cast<int>( - width_in_points * kPixelsPerInch / kPointsPerInch); + ConvertUnitDouble(width_in_points, kPointsPerInch, kPixelsPerInch)); int height_in_pixels = static_cast<int>( - height_in_points * kPixelsPerInch / kPointsPerInch); + ConvertUnitDouble(height_in_points, kPointsPerInch, kPixelsPerInch)); if (current_rotation_ % 2 == 1) std::swap(width_in_pixels, height_in_pixels); size = pp::Size(width_in_pixels, height_in_pixels); @@ -3781,10 +3773,12 @@ int CalculatePosition(FPDF_PAGE page, const PDFiumEngineExports::RenderingSettings& settings, pp::Rect* dest) { - int page_width = static_cast<int>( - FPDF_GetPageWidth(page) * settings.dpi_x / kPointsPerInch); - int page_height = static_cast<int>( - FPDF_GetPageHeight(page) * settings.dpi_y / kPointsPerInch); + int page_width = static_cast<int>(ConvertUnitDouble(FPDF_GetPageWidth(page), + kPointsPerInch, + settings.dpi_x)); + int page_height = static_cast<int>(ConvertUnitDouble(FPDF_GetPageHeight(page), + kPointsPerInch, + settings.dpi_y)); // Start by assuming that we will draw exactly to the bounds rect // specified.
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h index 44ed9ae..ac05303 100644 --- a/pdf/pdfium/pdfium_engine.h +++ b/pdf/pdfium/pdfium_engine.h
@@ -310,10 +310,12 @@ PDFiumPage::Area GetCharIndex(const pp::MouseInputEvent& event, int* page_index, int* char_index, + int* form_type, PDFiumPage::LinkTarget* target); PDFiumPage::Area GetCharIndex(const pp::Point& point, int* page_index, int* char_index, + int* form_type, PDFiumPage::LinkTarget* target); void OnSingleClick(int page_index, int char_index);
diff --git a/pdf/pdfium/pdfium_page.cc b/pdf/pdfium/pdfium_page.cc index 1335f07..e514af33 100644 --- a/pdf/pdfium/pdfium_page.cc +++ b/pdf/pdfium/pdfium_page.cc
@@ -258,6 +258,7 @@ PDFiumPage::Area PDFiumPage::GetCharIndex(const pp::Point& point, int rotation, int* char_index, + int* form_type, LinkTarget* target) { if (!available_) return NONSELECTABLE_AREA; @@ -270,6 +271,13 @@ GetTextPage(), new_x, new_y, kTolerance, kTolerance); *char_index = rv; + int control = + FPDPage_HasFormFieldAtPoint(engine_->form(), GetPage(), new_x, new_y); + if (control > FPDF_FORMFIELD_UNKNOWN) { + *form_type = control; + return PDFiumPage::NONSELECTABLE_AREA; + } + FPDF_LINK link = FPDFLink_GetLinkAtPoint(GetPage(), new_x, new_y); if (link) { // We don't handle all possible link types of the PDF. For example,
diff --git a/pdf/pdfium/pdfium_page.h b/pdf/pdfium/pdfium_page.h index de4317e..d4174f54 100644 --- a/pdf/pdfium/pdfium_page.h +++ b/pdf/pdfium/pdfium_page.h
@@ -64,7 +64,7 @@ // Target is optional. It will be filled in for WEBLINK_AREA or // DOCLINK_AREA only. Area GetCharIndex(const pp::Point& point, int rotation, int* char_index, - LinkTarget* target); + int* form_type, LinkTarget* target); // Gets the character at the given index. base::char16 GetCharAtIndex(int index);
diff --git a/ppapi/BUILD.gn b/ppapi/BUILD.gn index f7ff011..9bc9e889 100644 --- a/ppapi/BUILD.gn +++ b/ppapi/BUILD.gn
@@ -2,7 +2,33 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +copy("copy_test_files") { + visibility = [ ":*" ] + sources = [ + # Keep "test_case.html.mock-http-headers" with "test_case.html". + "tests/test_case.html", + "tests/test_case.html.mock-http-headers", + "tests/test_page.css", + "tests/ppapi_nacl_tests_newlib.nmf", + ] + outputs = [ + "$root_out_dir/{{source_file_part}}", + ] +} + +copy("copy_test_files2") { + visibility = [ ":*" ] + sources = [ + "tests/test_url_loader_data/hello.txt", + ] + outputs = [ + "$root_out_dir/test_url_loader_data/{{source_file_part}}", + ] +} + import("//ppapi/ppapi_sources.gni") +import("//testing/test.gni") + shared_library("ppapi_tests") { sources = ppapi_sources.test_common_source_files + ppapi_sources.test_trusted_source_files @@ -13,6 +39,80 @@ deps = [ "//ppapi/cpp", "//ppapi/shared_impl", + ":copy_test_files", + ":copy_test_files2", ] } -# TODO(GYP) other targets from ppapi_tests.gyp + +test("ppapi_unittests") { + sources = [ + "host/resource_message_filter_unittest.cc", + "proxy/device_enumeration_resource_helper_unittest.cc", + "proxy/file_chooser_resource_unittest.cc", + "proxy/file_system_resource_unittest.cc", + "proxy/flash_resource_unittest.cc", + "proxy/interface_list_unittest.cc", + "proxy/mock_resource.cc", + "proxy/mock_resource.h", + "proxy/nacl_message_scanner_unittest.cc", + "proxy/pdf_resource_unittest.cc", + "proxy/plugin_dispatcher_unittest.cc", + "proxy/plugin_resource_tracker_unittest.cc", + "proxy/plugin_var_tracker_unittest.cc", + "proxy/ppb_var_unittest.cc", + "proxy/ppp_instance_private_proxy_unittest.cc", + "proxy/ppp_instance_proxy_unittest.cc", + "proxy/ppp_messaging_proxy_unittest.cc", + "proxy/printing_resource_unittest.cc", + "proxy/raw_var_data_unittest.cc", + "proxy/serialized_var_unittest.cc", + "proxy/talk_resource_unittest.cc", + "proxy/video_decoder_resource_unittest.cc", + "proxy/video_encoder_resource_unittest.cc", + "proxy/websocket_resource_unittest.cc", + "shared_impl/media_stream_audio_track_shared_unittest.cc", + "shared_impl/media_stream_buffer_manager_unittest.cc", + "shared_impl/media_stream_video_track_shared_unittest.cc", + "shared_impl/proxy_lock_unittest.cc", + "shared_impl/resource_tracker_unittest.cc", + "shared_impl/thread_aware_callback_unittest.cc", + "shared_impl/time_conversion_unittest.cc", + "shared_impl/tracked_callback_unittest.cc", + "shared_impl/var_tracker_unittest.cc", + ] + + deps = [ + "//base/allocator", + "//base/test:run_all_unittests", + "//base/test:test_support", + "//gpu/ipc", + "//ipc", + "//ipc:test_support", + "//media:shared_memory_support", + "//ppapi/host", + "//ppapi/proxy", + "//ppapi/proxy:test_support", + "//ppapi/shared_impl", + "//ppapi/shared_impl:test_support", + "//testing/gmock", + "//testing/gtest", + "//ui/surface", + ] +} + +test("ppapi_perftests") { + sources = [ + "proxy/ppapi_perftests.cc", + "proxy/ppp_messaging_proxy_perftest.cc", + ] + + deps = [ + "//base/allocator", + "//base/test:test_support", + "//ppapi/proxy", + "//ppapi/proxy:test_support", + "//ppapi/shared_impl", + "//ppapi/shared_impl:test_support", + "//testing/gtest", + ] +}
diff --git a/ppapi/examples/BUILD.gn b/ppapi/examples/BUILD.gn index fedb176..9369c585 100644 --- a/ppapi/examples/BUILD.gn +++ b/ppapi/examples/BUILD.gn
@@ -32,5 +32,6 @@ "//ppapi/examples/video_capture", "//ppapi/examples/video_decode", "//ppapi/examples/video_effects", + "//ppapi/examples/video_encode", ] }
diff --git a/ppapi/examples/video_encode/BUILD.gn b/ppapi/examples/video_encode/BUILD.gn new file mode 100644 index 0000000..eaa3586f --- /dev/null +++ b/ppapi/examples/video_encode/BUILD.gn
@@ -0,0 +1,15 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//ppapi/examples/ppapi_example.gni") + +ppapi_example("video_encode") { + output_name = "ppapi_example_video_encode" + sources = [ + "video_encode.cc", + ] + deps = [ + "//ppapi/cpp", + ] +}
diff --git a/ppapi/examples/video_encode/video_encode.cc b/ppapi/examples/video_encode/video_encode.cc new file mode 100644 index 0000000..26c66df --- /dev/null +++ b/ppapi/examples/video_encode/video_encode.cc
@@ -0,0 +1,502 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <math.h> +#include <stdio.h> +#include <string.h> + +#include <iostream> +#include <sstream> +#include <vector> + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_console.h" +#include "ppapi/cpp/input_event.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/media_stream_video_track.h" +#include "ppapi/cpp/module.h" +#include "ppapi/cpp/rect.h" +#include "ppapi/cpp/var.h" +#include "ppapi/cpp/var_array_buffer.h" +#include "ppapi/cpp/var_dictionary.h" +#include "ppapi/cpp/video_encoder.h" +#include "ppapi/cpp/video_frame.h" +#include "ppapi/utility/completion_callback_factory.h" + +// TODO(llandwerlin): turn on by default when we have software encode. +// #define USE_VP8_INSTEAD_OF_H264 + +// When compiling natively on Windows, PostMessage can be #define-d to +// something else. +#ifdef PostMessage +#undef PostMessage +#endif + +// Use assert as a poor-man's CHECK, even in non-debug mode. +// Since <assert.h> redefines assert on every inclusion (it doesn't use +// include-guards), make sure this is the last file #include'd in this file. +#undef NDEBUG +#include <assert.h> + +namespace { + +std::string VideoProfileToString(PP_VideoProfile profile) { + switch (profile) { + case PP_VIDEOPROFILE_H264BASELINE: + return "h264baseline"; + case PP_VIDEOPROFILE_H264MAIN: + return "h264main"; + case PP_VIDEOPROFILE_H264EXTENDED: + return "h264extended"; + case PP_VIDEOPROFILE_H264HIGH: + return "h264high"; + case PP_VIDEOPROFILE_H264HIGH10PROFILE: + return "h264high10"; + case PP_VIDEOPROFILE_H264HIGH422PROFILE: + return "h264high422"; + case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE: + return "h264high444predictive"; + case PP_VIDEOPROFILE_H264SCALABLEBASELINE: + return "h264scalablebaseline"; + case PP_VIDEOPROFILE_H264SCALABLEHIGH: + return "h264scalablehigh"; + case PP_VIDEOPROFILE_H264STEREOHIGH: + return "h264stereohigh"; + case PP_VIDEOPROFILE_H264MULTIVIEWHIGH: + return "h264multiviewhigh"; + case PP_VIDEOPROFILE_VP8_ANY: + return "vp8"; + case PP_VIDEOPROFILE_VP9_ANY: + return "vp9"; + // No default to catch unhandled profiles. + } + return "unknown"; +} + +std::string HardwareAccelerationToString(PP_HardwareAcceleration acceleration) { + switch (acceleration) { + case PP_HARDWAREACCELERATION_ONLY: + return "hardware"; + case PP_HARDWAREACCELERATION_WITHFALLBACK: + return "hardware/software"; + case PP_HARDWAREACCELERATION_NONE: + return "software"; + // No default to catch unhandled accelerations. + } + return "unknown"; +} + +// This object is the global object representing this plugin library as long +// as it is loaded. +class VideoEncoderModule : public pp::Module { + public: + VideoEncoderModule() : pp::Module() {} + virtual ~VideoEncoderModule() {} + + virtual pp::Instance* CreateInstance(PP_Instance instance); +}; + +class VideoEncoderInstance : public pp::Instance { + public: + VideoEncoderInstance(PP_Instance instance, pp::Module* module); + virtual ~VideoEncoderInstance(); + + // pp::Instance implementation. + virtual void HandleMessage(const pp::Var& var_message); + + private: + void ConfigureTrack(); + void OnConfiguredTrack(int32_t result); + void ProbeEncoder(); + void OnEncoderProbed(int32_t result, + const std::vector<PP_VideoProfileDescription> profiles); + void OnInitializedEncoder(int32_t result); + void ScheduleNextEncode(); + void GetEncoderFrameTick(int32_t result); + void GetEncoderFrame(const pp::VideoFrame& track_frame); + void OnEncoderFrame(int32_t result, + pp::VideoFrame encoder_frame, + pp::VideoFrame track_frame); + int32_t CopyVideoFrame(pp::VideoFrame dest, pp::VideoFrame src); + void EncodeFrame(const pp::VideoFrame& frame); + void OnEncodeDone(int32_t result); + void OnGetBitstreamBuffer(int32_t result, PP_BitstreamBuffer buffer); + void StartTrackFrames(); + void StopTrackFrames(); + void OnTrackFrame(int32_t result, pp::VideoFrame frame); + + void StopEncode(); + + void LogError(int32_t error, const std::string& message); + void Log(const std::string& message); + + void PostDataMessage(const void* buffer, uint32_t size); + void PostSignalMessage(const char* name); + + bool is_encoding_; + bool is_receiving_track_frames_; + + pp::VideoEncoder video_encoder_; + pp::MediaStreamVideoTrack video_track_; + pp::CompletionCallbackFactory<VideoEncoderInstance> callback_factory_; + + PP_VideoProfile video_profile_; + PP_VideoFrame_Format frame_format_; + + pp::Size requested_size_; + pp::Size frame_size_; + pp::Size encoder_size_; + uint32_t encoded_frames_; + + pp::VideoFrame current_track_frame_; +}; + +VideoEncoderInstance::VideoEncoderInstance(PP_Instance instance, + pp::Module* module) + : pp::Instance(instance), + is_encoding_(false), + callback_factory_(this), +#if defined(USE_VP8_INSTEAD_OF_H264) + video_profile_(PP_VIDEOPROFILE_VP8_ANY), +#else + video_profile_(PP_VIDEOPROFILE_H264MAIN), +#endif + frame_format_(PP_VIDEOFRAME_FORMAT_I420), + encoded_frames_(0) { +} + +VideoEncoderInstance::~VideoEncoderInstance() { +} + +void VideoEncoderInstance::ConfigureTrack() { + if (encoder_size_.IsEmpty()) + frame_size_ = requested_size_; + else + frame_size_ = encoder_size_; + + int32_t attrib_list[] = {PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT, + frame_format_, + PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH, + frame_size_.width(), + PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT, + frame_size_.height(), + PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE}; + + pp::VarDictionary dict; + dict.Set(pp::Var("status"), pp::Var("configuring video track")); + dict.Set(pp::Var("width"), pp::Var(frame_size_.width())); + dict.Set(pp::Var("height"), pp::Var(frame_size_.height())); + PostMessage(dict); + + video_track_.Configure( + attrib_list, + callback_factory_.NewCallback(&VideoEncoderInstance::OnConfiguredTrack)); +} + +void VideoEncoderInstance::OnConfiguredTrack(int32_t result) { + if (result != PP_OK) { + LogError(result, "Cannot configure track"); + return; + } + + if (is_encoding_) { + StartTrackFrames(); + ScheduleNextEncode(); + } else + ProbeEncoder(); +} + +void VideoEncoderInstance::ProbeEncoder() { + video_encoder_ = pp::VideoEncoder(this); + video_encoder_.GetSupportedProfiles(callback_factory_.NewCallbackWithOutput( + &VideoEncoderInstance::OnEncoderProbed)); +} + +void VideoEncoderInstance::OnEncoderProbed( + int32_t result, + const std::vector<PP_VideoProfileDescription> profiles) { + bool has_required_profile = false; + + Log("Available profiles:"); + for (const PP_VideoProfileDescription& profile : profiles) { + std::ostringstream oss; + oss << " profile=" << VideoProfileToString(profile.profile) + << " max_resolution=" << profile.max_resolution.width << "x" + << profile.max_resolution.height + << " max_framerate=" << profile.max_framerate_numerator << "/" + << profile.max_framerate_denominator << " acceleration=" + << HardwareAccelerationToString(profile.acceleration); + Log(oss.str()); + + has_required_profile |= profile.profile == video_profile_; + } + + if (!has_required_profile) { + std::ostringstream oss; + oss << "Cannot find required video profile: "; + oss << VideoProfileToString(video_profile_); + LogError(PP_ERROR_FAILED, oss.str()); + return; + } + + video_encoder_ = pp::VideoEncoder(this); + + pp::VarDictionary dict; + dict.Set(pp::Var("status"), pp::Var("initializing encoder")); + dict.Set(pp::Var("width"), pp::Var(encoder_size_.width())); + dict.Set(pp::Var("height"), pp::Var(encoder_size_.height())); + PostMessage(dict); + + int32_t error = video_encoder_.Initialize( + frame_format_, frame_size_, video_profile_, 2000000, + PP_HARDWAREACCELERATION_WITHFALLBACK, + callback_factory_.NewCallback( + &VideoEncoderInstance::OnInitializedEncoder)); + if (error != PP_OK_COMPLETIONPENDING) { + LogError(error, "Cannot initialize encoder"); + return; + } +} + +void VideoEncoderInstance::OnInitializedEncoder(int32_t result) { + if (result != PP_OK) { + LogError(result, "Encoder initialization failed"); + return; + } + + is_encoding_ = true; + + if (video_encoder_.GetFrameCodedSize(&encoder_size_) != PP_OK) { + LogError(result, "Cannot get encoder coded frame size"); + return; + } + + pp::VarDictionary dict; + dict.Set(pp::Var("status"), pp::Var("encoder initialized")); + dict.Set(pp::Var("width"), pp::Var(encoder_size_.width())); + dict.Set(pp::Var("height"), pp::Var(encoder_size_.height())); + PostMessage(dict); + + video_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput( + &VideoEncoderInstance::OnGetBitstreamBuffer)); + + if (encoder_size_ != frame_size_) + ConfigureTrack(); + else { + StartTrackFrames(); + ScheduleNextEncode(); + } +} + +void VideoEncoderInstance::ScheduleNextEncode() { + pp::Module::Get()->core()->CallOnMainThread( + 1000 / 30, + callback_factory_.NewCallback(&VideoEncoderInstance::GetEncoderFrameTick), + 0); +} + +void VideoEncoderInstance::GetEncoderFrameTick(int32_t result) { + if (is_encoding_) { + if (!current_track_frame_.is_null()) { + pp::VideoFrame frame = current_track_frame_; + current_track_frame_.detach(); + GetEncoderFrame(frame); + } + ScheduleNextEncode(); + } +} + +void VideoEncoderInstance::GetEncoderFrame(const pp::VideoFrame& track_frame) { + video_encoder_.GetVideoFrame(callback_factory_.NewCallbackWithOutput( + &VideoEncoderInstance::OnEncoderFrame, track_frame)); +} + +void VideoEncoderInstance::OnEncoderFrame(int32_t result, + pp::VideoFrame encoder_frame, + pp::VideoFrame track_frame) { + if (result == PP_ERROR_ABORTED) { + video_track_.RecycleFrame(track_frame); + return; + } + if (result != PP_OK) { + video_track_.RecycleFrame(track_frame); + LogError(result, "Cannot get video frame from video encoder"); + return; + } + + track_frame.GetSize(&frame_size_); + + if (frame_size_ != encoder_size_) { + video_track_.RecycleFrame(track_frame); + LogError(PP_ERROR_FAILED, "MediaStreamVideoTrack frame size incorrect"); + return; + } + + if (CopyVideoFrame(encoder_frame, track_frame) == PP_OK) + EncodeFrame(encoder_frame); + video_track_.RecycleFrame(track_frame); +} + +int32_t VideoEncoderInstance::CopyVideoFrame(pp::VideoFrame dest, + pp::VideoFrame src) { + if (dest.GetDataBufferSize() < src.GetDataBufferSize()) { + std::ostringstream oss; + oss << "Incorrect destination video frame buffer size : " + << dest.GetDataBufferSize() << " < " << src.GetDataBufferSize(); + LogError(PP_ERROR_FAILED, oss.str()); + return PP_ERROR_FAILED; + } + + memcpy(dest.GetDataBuffer(), src.GetDataBuffer(), src.GetDataBufferSize()); + return PP_OK; +} + +void VideoEncoderInstance::EncodeFrame(const pp::VideoFrame& frame) { + video_encoder_.Encode( + frame, PP_FALSE, + callback_factory_.NewCallback(&VideoEncoderInstance::OnEncodeDone)); +} + +void VideoEncoderInstance::OnEncodeDone(int32_t result) { + if (result == PP_ERROR_ABORTED) + return; + if (result != PP_OK) + LogError(result, "Encode failed"); +} + +void VideoEncoderInstance::OnGetBitstreamBuffer(int32_t result, + PP_BitstreamBuffer buffer) { + if (result == PP_ERROR_ABORTED) + return; + if (result != PP_OK) { + LogError(result, "Cannot get bitstream buffer"); + return; + } + + encoded_frames_++; + PostDataMessage(buffer.buffer, buffer.size); + video_encoder_.RecycleBitstreamBuffer(buffer); + + video_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput( + &VideoEncoderInstance::OnGetBitstreamBuffer)); +} + +void VideoEncoderInstance::StartTrackFrames() { + is_receiving_track_frames_ = true; + video_track_.GetFrame(callback_factory_.NewCallbackWithOutput( + &VideoEncoderInstance::OnTrackFrame)); +} + +void VideoEncoderInstance::StopTrackFrames() { + is_receiving_track_frames_ = false; + if (!current_track_frame_.is_null()) { + video_track_.RecycleFrame(current_track_frame_); + current_track_frame_.detach(); + } +} + +void VideoEncoderInstance::OnTrackFrame(int32_t result, pp::VideoFrame frame) { + if (result == PP_ERROR_ABORTED) + return; + + if (!current_track_frame_.is_null()) { + video_track_.RecycleFrame(current_track_frame_); + current_track_frame_.detach(); + } + + if (result != PP_OK) { + LogError(result, "Cannot get video frame from video track"); + return; + } + + current_track_frame_ = frame; + if (is_receiving_track_frames_) + video_track_.GetFrame(callback_factory_.NewCallbackWithOutput( + &VideoEncoderInstance::OnTrackFrame)); +} + +void VideoEncoderInstance::StopEncode() { + video_encoder_.Close(); + StopTrackFrames(); + video_track_.Close(); + is_encoding_ = false; + encoded_frames_ = 0; +} + +// + +void VideoEncoderInstance::HandleMessage(const pp::Var& var_message) { + if (!var_message.is_dictionary()) { + LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Invalid message!")); + return; + } + + pp::VarDictionary dict_message(var_message); + std::string command = dict_message.Get("command").AsString(); + + if (command == "start") { + requested_size_ = pp::Size(dict_message.Get("width").AsInt(), + dict_message.Get("height").AsInt()); + pp::Var var_track = dict_message.Get("track"); + if (!var_track.is_resource()) { + LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Given track is not a resource")); + return; + } + pp::Resource resource_track = var_track.AsResource(); + video_track_ = pp::MediaStreamVideoTrack(resource_track); + video_encoder_ = pp::VideoEncoder(); + ConfigureTrack(); + } else if (command == "stop") { + StopEncode(); + PostSignalMessage("stopped"); + } else { + LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Invalid command!")); + } +} + +void VideoEncoderInstance::PostDataMessage(const void* buffer, uint32_t size) { + pp::VarDictionary dictionary; + + dictionary.Set(pp::Var("name"), pp::Var("data")); + + pp::VarArrayBuffer array_buffer(size); + void* data_ptr = array_buffer.Map(); + memcpy(data_ptr, buffer, size); + array_buffer.Unmap(); + dictionary.Set(pp::Var("data"), array_buffer); + + PostMessage(dictionary); +} + +void VideoEncoderInstance::PostSignalMessage(const char* name) { + pp::VarDictionary dictionary; + dictionary.Set(pp::Var("name"), pp::Var(name)); + + PostMessage(dictionary); +} + +void VideoEncoderInstance::LogError(int32_t error, const std::string& message) { + std::string msg("Error: "); + msg.append(pp::Var(error).DebugString()); + msg.append(" : "); + msg.append(message); + LogToConsole(PP_LOGLEVEL_ERROR, pp::Var(msg)); +} + +void VideoEncoderInstance::Log(const std::string& message) { + LogToConsole(PP_LOGLEVEL_LOG, pp::Var(message)); +} + +pp::Instance* VideoEncoderModule::CreateInstance(PP_Instance instance) { + return new VideoEncoderInstance(instance, this); +} + +} // anonymous namespace + +namespace pp { +// Factory function for your specialization of the Module object. +Module* CreateModule() { + return new VideoEncoderModule(); +} +} // namespace pp
diff --git a/ppapi/examples/video_encode/video_encode.html b/ppapi/examples/video_encode/video_encode.html new file mode 100644 index 0000000..803c1f4 --- /dev/null +++ b/ppapi/examples/video_encode/video_encode.html
@@ -0,0 +1,127 @@ +<!DOCTYPE html> +<html> + <!-- + Copyright 2015 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. + --> +<head> + <title>Video Encoder Example</title> + <style type="text/css"> + #video { + position: fixed; + } + #video-playback { + position: fixed; + left: 640px; + } + #plugin { + position: fixed; + } + </style> + <script type="text/javascript"> + var plugin; + var track; + var video; + + function $(id) { + return document.getElementById(id); + } + + function success(stream) { + track = stream.getVideoTracks()[0]; + video.src = URL.createObjectURL(stream); + video.play(); + + plugin.postMessage({ + command: 'start', + track: track, + width: 640, + height: 480 + }); + } + + function failure(e) { + console.log("Error: ", e); + } + + function startRecord() { + console.log("starting record"); + navigator.webkitGetUserMedia({audio: false, video: true}, + success, failure); + } + + function stopRecord() { + plugin.postMessage({ + command: "stop" + }); + var video = $('video'); + video.pause(); + track.stop(); + } + + function saveBlob(blob) { + var blobUrl = URL.createObjectURL(blob); + window.location = blobUrl; + } + + function handleMessage(msg) { + if (msg.data.name == 'started') { + console.log('recording!'); + } else if (msg.data.name == 'data') { + appendData(msg.data.data); + } else if (msg.data.name == 'stopped') { + console.log('done recording! bytes: ' + dataArray.byteLength); + } + } + + function resetData() { + window.dataArray = new ArrayBuffer(0); + } + + function appendData(data) { + var tmp = new Uint8Array(dataArray.byteLength + data.byteLength); + tmp.set(new Uint8Array(dataArray), 0 ); + tmp.set(new Uint8Array(data), dataArray.byteLength); + dataArray = tmp.buffer; + $('length').innerHTML = ' Size: ' + dataArray.byteLength + ' bytes'; + } + + function initialize() { + plugin = $('plugin'); + plugin.addEventListener('message', handleMessage, false); + + video = $('video'); + + $('start').addEventListener('click', function (e) { + resetData(); + startRecord(); + }); + $('stop').addEventListener('click', function (e) { + stopRecord(); + }); + $('download').addEventListener('click', function (e) { + saveBlob(new Blob([dataArray], { type: "application/octet-stream" })); + }); + } + + document.addEventListener('DOMContentLoaded', initialize, false); + </script> +</head> + +<body> + <h1>Video Encoder API Example</h1><br> + This example demonstrates receiving frames from a video MediaStreamTrack and + encoding them in a plugin. + <br> + <input type="button" id="start" value="Start Recording"/> + <input type="button" id="stop" value="Stop Recording"/> + <input type="button" id="download" value="Download Recording"/> + <div id="length"></div> + <br> + <div> + <embed id="plugin" type="application/x-ppapi-example-video-encode"/> + <video id="video" width="640" height="480"/> + </div> +</body> +</html>
diff --git a/ppapi/ppapi_host.gypi b/ppapi/ppapi_host.gypi index eea53b4..3113ddf 100644 --- a/ppapi/ppapi_host.gypi +++ b/ppapi/ppapi_host.gypi
@@ -5,7 +5,7 @@ { 'targets': [ { - # GN version: //ppapi:ppapi_host + # GN version: //ppapi/host 'target_name': 'ppapi_host', 'type': '<(component)', 'dependencies': [
diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi index 562903d..0002843 100644 --- a/ppapi/ppapi_tests.gypi +++ b/ppapi/ppapi_tests.gypi
@@ -5,6 +5,7 @@ { 'targets': [ { + # GN version: //ppapi:ppapi_tests 'target_name': 'ppapi_tests', 'type': 'loadable_module', 'include_dirs': [ @@ -106,6 +107,7 @@ }, { + # GN version: //ppapi:ppapi_perftests 'target_name': 'ppapi_perftests', 'type': 'executable', 'variables': { @@ -132,6 +134,7 @@ ], }, { + # GN version: //ppapi:ppapi_unittests 'target_name': 'ppapi_unittests', 'type': 'executable', 'variables': { @@ -153,6 +156,7 @@ '../ui/surface/surface.gyp:surface', ], 'sources': [ + # Note: sources list duplicated in GN build. 'host/resource_message_filter_unittest.cc', 'proxy/device_enumeration_resource_helper_unittest.cc', 'proxy/file_chooser_resource_unittest.cc', @@ -498,6 +502,16 @@ ], }, { + 'target_name': 'ppapi_example_video_encode', + 'dependencies': [ + 'ppapi_example_skeleton', + 'ppapi.gyp:ppapi_cpp', + ], + 'sources': [ + 'examples/video_encode/video_encode.cc', + ], + }, + { # GN version: //ppapi/example/video_capture 'target_name': 'ppapi_example_vc', 'dependencies': [
diff --git a/printing/printing_context.cc b/printing/printing_context.cc index a589900..9748a170 100644 --- a/printing/printing_context.cc +++ b/printing/printing_context.cc
@@ -63,6 +63,7 @@ pdf_settings->SetBoolean(kSettingPrintToPDF, true); pdf_settings->SetBoolean(kSettingCloudPrintDialog, false); pdf_settings->SetBoolean(kSettingPrintWithPrivet, false); + pdf_settings->SetBoolean(kSettingPrintWithExtension, false); return UpdatePrintSettings(*pdf_settings); } @@ -78,10 +79,13 @@ bool print_to_pdf = false; bool is_cloud_dialog = false; bool print_with_privet = false; + bool print_with_extension = false; if (!job_settings.GetBoolean(kSettingPrintToPDF, &print_to_pdf) || !job_settings.GetBoolean(kSettingCloudPrintDialog, &is_cloud_dialog) || - !job_settings.GetBoolean(kSettingPrintWithPrivet, &print_with_privet)) { + !job_settings.GetBoolean(kSettingPrintWithPrivet, &print_with_privet) || + !job_settings.GetBoolean(kSettingPrintWithExtension, + &print_with_extension)) { NOTREACHED(); return OnError(); } @@ -90,8 +94,9 @@ bool open_in_external_preview = job_settings.HasKey(kSettingOpenPDFInPreview); - if (!open_in_external_preview && (print_to_pdf || print_to_cloud || - is_cloud_dialog || print_with_privet)) { + if (!open_in_external_preview && + (print_to_pdf || print_to_cloud || is_cloud_dialog || print_with_privet || + print_with_extension)) { settings_.set_dpi(kDefaultPdfDpi); gfx::Size paper_size(GetPdfPaperSizeDeviceUnits()); if (!settings_.requested_media().size_microns.IsEmpty()) {
diff --git a/remoting/BUILD.gn b/remoting/BUILD.gn new file mode 100644 index 0000000..f87db3d --- /dev/null +++ b/remoting/BUILD.gn
@@ -0,0 +1,115 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/features.gni") +import("//build/config/ui.gni") +import("//remoting/remoting_version.gni") +import("//testing/test.gni") + +enable_remoting_host = is_win || is_mac || is_chromeos || use_x11 + +# Various remoting targets need this version definition. +config("version") { + defines = [ "VERSION=$version_full" ] +} + +# GYP version: remoting/remoting_test.gypi:remoting_test_common +source_set("test_support") { + testonly = true + + sources = [ + # Files from remoting_test_common not in separate test_support targets. + "signaling/fake_signal_strategy.cc", + "signaling/fake_signal_strategy.h", + "signaling/mock_signal_strategy.cc", + "signaling/mock_signal_strategy.h", + "test/access_token_fetcher.cc", + "test/app_remoting_test_driver_environment.cc", + "test/fake_access_token_fetcher.cc", + "test/fake_network_dispatcher.cc", + "test/fake_network_dispatcher.h", + "test/fake_network_manager.cc", + "test/fake_network_manager.h", + "test/fake_port_allocator.cc", + "test/fake_port_allocator.h", + "test/fake_socket_factory.cc", + "test/fake_socket_factory.h", + "test/leaky_bucket.cc", + "test/leaky_bucket.h", + "test/mock_access_token_fetcher.cc", + "test/refresh_token_store.cc", + ] + + deps = [ + "//base", + "//components/policy:test_support", + "//net", + "//remoting/base", + "//remoting/client", + "//remoting/codec", + "//remoting/protocol:test_support", + "//remoting/resources", + "//testing/gmock", + "//testing/gtest", + ] + + if (enable_remoting_host) { + deps += [ "//remoting/host:test_support" ] + } +} + +# TODO(GYP) remoting_unittests on Mac/Windows. Currently this fails with a +# duplicate resource error on linking on Windows. Just needs to be checked on +# Mac. +if (!is_win && !is_mac) { + test("remoting_unittests") { + # Sources not included in one of the more specific unit_tests deps. + sources = [ + "signaling/iq_sender_unittest.cc", + "signaling/log_to_server_unittest.cc", + "signaling/server_log_entry_unittest.cc", + "signaling/server_log_entry_unittest.h", + "test/access_token_fetcher_unittest.cc", + "test/app_remoting_test_driver_environment_unittest.cc", + ] + + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + + deps = [ + ":test_support", + "//base/allocator", + "//google_apis", + "//remoting/base:unit_tests", + "//remoting/client:unit_tests", + "//remoting/protocol:unit_tests", + "//testing/gmock", + "//testing/gtest", + "//third_party/webrtc", + ] + + if (is_android) { + deps += [ "//testing/android:native_test_native_code" ] + } else { + deps += [ "//remoting/client/plugin" ] + } + + if (enable_remoting_host) { + deps += [ + "//remoting/codec:unit_tests", + "//remoting/host:unit_tests", + ] + } + + if (enable_webrtc) { + deps += [ + "//third_party/libjingle:libjingle_webrtc", + "//third_party/libjingle:libpeerconnection", + ] + } + } +} else { + group("remoting_unittests") { + } +}
diff --git a/remoting/app_remoting_webapp.gyp b/remoting/app_remoting_webapp.gyp index de11d0f..e179f1e78 100644 --- a/remoting/app_remoting_webapp.gyp +++ b/remoting/app_remoting_webapp.gyp
@@ -62,6 +62,29 @@ '<@(remoting_webapp_js_proto_files)', ], }, + { + 'action_name': 'Verify >(ar_app_name) feedback_consent.html', + 'variables': { + 'success_stamp': '<(PRODUCT_DIR)/>(_target_name)_feedback_consent_jscompile.stamp', + }, + 'inputs': [ + '<@(ar_feedback_consent_js_files)', + '<@(remoting_webapp_js_proto_files)', + # Include zip as input so that this action is run after the build. + '<(zip_path)', + ], + 'outputs': [ + '<(success_stamp)', + ], + 'action': [ + 'python', '../third_party/closure_compiler/checker.py', + '--strict', + '--no-single-file', + '--success-stamp', '<(success_stamp)', + '<@(ar_feedback_consent_js_files)', + '<@(remoting_webapp_js_proto_files)', + ], + }, ], # actions }], ], # conditions
diff --git a/remoting/app_remoting_webapp_build.gypi b/remoting/app_remoting_webapp_build.gypi index 9e739f7..cdd5ecf5 100644 --- a/remoting/app_remoting_webapp_build.gypi +++ b/remoting/app_remoting_webapp_build.gypi
@@ -6,15 +6,12 @@ 'includes': [ 'remoting_version.gypi', 'remoting_locales.gypi', + 'remoting_options.gypi', 'remoting_webapp_files.gypi', 'app_remoting_webapp_files.gypi', ], 'variables': { - 'chromium_code': 1, - - 'run_jscompile%': 0, - # The ar_service_environment variable is used to define the target # environment for the app being built. # The allowed values are dev, test, staging, and prod. @@ -58,6 +55,7 @@ 'ar_generated_html_files': [ '<(SHARED_INTERMEDIATE_DIR)/>(_target_name)/main.html', '<(SHARED_INTERMEDIATE_DIR)/>(_target_name)/wcs_sandbox.html', + '<(SHARED_INTERMEDIATE_DIR)/>(_target_name)/feedback_consent.html', ], 'ar_webapp_files': [ '<@(ar_app_specific_files)', @@ -189,6 +187,28 @@ '<@(remoting_webapp_wcs_sandbox_html_js_files)', ], }, + { + 'action_name': 'Build ">(ar_app_name)" feedback_consent.html', + 'inputs': [ + '<(DEPTH)/remoting/webapp/build-html.py', + '<(ar_feedback_consent_template)', + '<@(ar_feedback_consent_template_files)', + ], + 'outputs': [ + '<(SHARED_INTERMEDIATE_DIR)/>(_target_name)/feedback_consent.html', + ], + 'action': [ + 'python', '<(DEPTH)/remoting/webapp/build-html.py', + '<(SHARED_INTERMEDIATE_DIR)/>(_target_name)/feedback_consent.html', + '<(ar_feedback_consent_template)', + '--template-dir', + '<(DEPTH)/remoting', + '--templates', + '<@(ar_feedback_consent_template_files)', + '--js', + '<@(ar_feedback_consent_js_files)', + ], + }, ], # actions 'conditions': [ ['buildtype == "Dev"', {
diff --git a/remoting/app_remoting_webapp_files.gypi b/remoting/app_remoting_webapp_files.gypi index cd9bf8c..5df8b8e 100644 --- a/remoting/app_remoting_webapp_files.gypi +++ b/remoting/app_remoting_webapp_files.gypi
@@ -6,13 +6,29 @@ 'variables': { 'ar_shared_resource_files': [ 'webapp/app_remoting/html/ar_dialog.css', + 'webapp/app_remoting/html/ar_main.css', 'webapp/app_remoting/html/feedback_consent.css', - 'webapp/app_remoting/html/feedback_consent.html', 'webapp/app_remoting/html/context_menu.css', 'resources/drag.webp', '<@(remoting_webapp_resource_files)', ], + # Variables for feedback_consent.html. + 'ar_feedback_consent_template': + '<(DEPTH)/remoting/webapp/app_remoting/html/template_feedback_consent.html', + 'ar_feedback_consent_template_files': [ + ], + 'ar_feedback_consent_js_files': [ + 'webapp/app_remoting/js/feedback_consent.js', + 'webapp/base/js/base.js', + 'webapp/crd/js/error.js', + 'webapp/crd/js/oauth2_api.js', + 'webapp/crd/js/oauth2_api_impl.js', + 'webapp/crd/js/plugin_settings.js', + 'webapp/crd/js/l10n.js', + 'webapp/crd/js/xhr.js', + ], + # Variables for main.html. # These template files are used to construct the webapp html files. 'ar_main_template': @@ -74,7 +90,7 @@ 'app_remoting_webapp_localizable_files': [ '<(ar_main_template)', '<@(ar_main_template_files)', - 'webapp/app_remoting/html/feedback_consent.html', + '<(ar_feedback_consent_template)', '<@(ar_all_js_files)', ],
diff --git a/remoting/base/BUILD.gn b/remoting/base/BUILD.gn index 5080599..bb79d52 100644 --- a/remoting/base/BUILD.gn +++ b/remoting/base/BUILD.gn
@@ -2,13 +2,12 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -static_library("base") { - gypi_values = exec_script("//build/gypi_to_gn.py", - [ rebase_path("../remoting_srcs.gypi") ], - "scope", - [ "../remoting_srcs.gypi" ]) +import("//remoting/remoting_srcs.gni") - sources = rebase_path(gypi_values.remoting_base_sources, ".", "//remoting") +source_set("base") { + sources = rebase_path(remoting_srcs_gypi_values.remoting_base_sources, + ".", + "//remoting") configs += [ "//build/config/compiler:wexit_time_destructors" ] @@ -25,10 +24,43 @@ "//remoting/resources", "//third_party/libvpx", "//third_party/libyuv", - "//third_party/opus", "//third_party/webrtc/modules/desktop_capture", "//ui/base", - "//ui/gfx", - "//ui/gfx/geometry", ] } + +source_set("unit_tests") { + testonly = true + + sources = [ + "auto_thread_task_runner_unittest.cc", + "auto_thread_unittest.cc", + "breakpad_win_unittest.cc", + "buffered_socket_writer_unittest.cc", + "capabilities_unittest.cc", + "compound_buffer_unittest.cc", + "rate_counter_unittest.cc", + "rsa_key_pair_unittest.cc", + "run_all_unittests.cc", + "running_average_unittest.cc", + "test_rsa_key_pair.h", + "typed_buffer_unittest.cc", + "util_unittest.cc", + ] + + deps = [ + ":base", + "//base", + "//net:test_support", + "//testing/gmock", + "//testing/gtest", + "//third_party/libyuv", + "//third_party/webrtc/modules/desktop_capture", + ] + + if (is_win || is_mac || is_chromeos) { + sources += [ "resources_unittest.cc" ] + deps += [ "//breakpad:client" ] + } + +}
diff --git a/remoting/base/auth_token_util.cc b/remoting/base/auth_token_util.cc deleted file mode 100644 index 45caa92..0000000 --- a/remoting/base/auth_token_util.cc +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/base/auth_token_util.h" -#include "remoting/base/constants.h" - -namespace remoting { - -void ParseAuthTokenWithService(const std::string& auth_service_with_token, - std::string* auth_token, - std::string* auth_service) { - size_t delimiter_pos = auth_service_with_token.find(':'); - if (delimiter_pos == std::string::npos) { - // Legacy case: there is no delimiter. Assume the whole string is the - // auth_token, and that we're using the default service. - // - // TODO(ajwong): Remove this defaulting once all webclients are migrated. - // BUG:83897 - auth_token->assign(auth_service_with_token); - auth_service->assign(kChromotingTokenDefaultServiceName); - } else { - auth_service->assign(auth_service_with_token.substr(0, delimiter_pos)); - - // Make sure there is *something* after the delimiter before doing substr. - if (delimiter_pos < auth_service_with_token.size()) { - auth_token->assign(auth_service_with_token.substr(delimiter_pos + 1)); - } else { - auth_token->clear(); - } - } -} - -} // namespace remoting
diff --git a/remoting/base/auth_token_util.h b/remoting/base/auth_token_util.h deleted file mode 100644 index 309a888..0000000 --- a/remoting/base/auth_token_util.h +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef REMOTING_BASE_AUTH_TOKEN_UTIL_H_ -#define REMOTING_BASE_AUTH_TOKEN_UTIL_H_ - -#include <string> - -namespace remoting { - -// Given a string of the form "auth_service:auth_token" parses it into its -// component pieces. -void ParseAuthTokenWithService(const std::string& auth_service_with_token, - std::string* auth_token, - std::string* auth_service); - -} // namespace remoting - -#endif // REMOTING_BASE_AUTH_TOKEN_UTIL_H_
diff --git a/remoting/base/auth_token_util_unittest.cc b/remoting/base/auth_token_util_unittest.cc deleted file mode 100644 index 2732b44..0000000 --- a/remoting/base/auth_token_util_unittest.cc +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/base/auth_token_util.h" -#include "remoting/base/constants.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace remoting { -namespace { - -TEST(AuthTokenUtilTest, ParseAuthTokenWithService) { - std::string auth_token; - std::string auth_service; - - ParseAuthTokenWithService("service:token", &auth_token, &auth_service); - EXPECT_EQ("token", auth_token); - EXPECT_EQ("service", auth_service); - - // Check for legacy support. - ParseAuthTokenWithService("token2", &auth_token, &auth_service); - EXPECT_EQ("token2", auth_token); - EXPECT_EQ(std::string(kChromotingTokenDefaultServiceName), auth_service); - - ParseAuthTokenWithService("just_service:", &auth_token, &auth_service); - EXPECT_EQ("", auth_token); - EXPECT_EQ("just_service", auth_service); - - ParseAuthTokenWithService("yay:token:has:colons", &auth_token, &auth_service); - EXPECT_EQ("token:has:colons", auth_token); - EXPECT_EQ("yay", auth_service); -} - -} // namespace - -} // namespace remoting
diff --git a/remoting/base/constants.cc b/remoting/base/constants.cc index 00995702..172c73e 100644 --- a/remoting/base/constants.cc +++ b/remoting/base/constants.cc
@@ -6,8 +6,6 @@ namespace remoting { -const char kChromotingTokenDefaultServiceName[] = "chromiumsync"; - const char kChromotingXmlNamespace[] = "google:remoting"; const char kAudioChannelName[] = "audio";
diff --git a/remoting/base/constants.h b/remoting/base/constants.h index 80c557266..43e35647 100644 --- a/remoting/base/constants.h +++ b/remoting/base/constants.h
@@ -7,11 +7,6 @@ namespace remoting { -// Service name used for authentication. -// TODO(ajwong): Remove this once we've killed off XmppToken usage. -// BUG:83897 -extern const char kChromotingTokenDefaultServiceName[]; - // Namespace used for chromoting XMPP stanzas. extern const char kChromotingXmlNamespace[];
diff --git a/remoting/client/BUILD.gn b/remoting/client/BUILD.gn index 93ae064..b47888a 100644 --- a/remoting/client/BUILD.gn +++ b/remoting/client/BUILD.gn
@@ -2,24 +2,48 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//remoting/remoting_version.gni") +import("//remoting/remoting_srcs.gni") -static_library("client") { - gypi_values = exec_script("//build/gypi_to_gn.py", - [ rebase_path("../remoting_srcs.gypi") ], - "scope", - [ "../remoting_srcs.gypi" ]) +source_set("client") { + sources = rebase_path(remoting_srcs_gypi_values.remoting_client_sources, + ".", + "//remoting") - sources = rebase_path(gypi_values.remoting_client_sources, ".", "//remoting") - - configs += [ "//build/config/compiler:wexit_time_destructors" ] - - defines = [ "VERSION=$version_full" ] + configs += [ + "//build/config/compiler:wexit_time_destructors", + "//remoting:version", + ] deps = [ "//remoting/base", + "//remoting/codec", "//remoting/protocol", "//third_party/libyuv", "//third_party/webrtc/modules/desktop_capture", ] } + +source_set("unit_tests") { + testonly = true + + sources = [ + "audio_player_unittest.cc", + "client_status_logger_unittest.cc", + "key_event_mapper_unittest.cc", + "plugin/empty_cursor_filter_unittest.cc", + "plugin/normalizing_input_filter_mac_unittest.cc", + "server_log_entry_client_unittest.cc", + ] + + if (is_chromeos) { + sources += [ "plugin/normalizing_input_filter_cros_unittest.cc" ] + } + + deps = [ + ":client", + "//remoting/proto", + "//testing/gmock", + "//testing/gtest", + "//third_party/webrtc", + ] +}
diff --git a/remoting/client/jni/chromoting_jni_instance.cc b/remoting/client/jni/chromoting_jni_instance.cc index 2c77fda..6cfc8870e 100644 --- a/remoting/client/jni/chromoting_jni_instance.cc +++ b/remoting/client/jni/chromoting_jni_instance.cc
@@ -63,7 +63,6 @@ xmpp_config_.use_tls = kXmppUseTls; xmpp_config_.username = username; xmpp_config_.auth_token = auth_token; - xmpp_config_.auth_service = "oauth2"; // Initialize |authenticator_|. scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
diff --git a/remoting/client/plugin/BUILD.gn b/remoting/client/plugin/BUILD.gn index 2f45f624..9594824 100644 --- a/remoting/client/plugin/BUILD.gn +++ b/remoting/client/plugin/BUILD.gn
@@ -2,16 +2,22 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -static_library("plugin") { - gypi_values = exec_script("//build/gypi_to_gn.py", - [ rebase_path("../../remoting_srcs.gypi") ], - "scope", - [ "../../remoting_srcs.gypi" ]) +import("//remoting/remoting_srcs.gni") +source_set("plugin") { sources = - rebase_path(gypi_values.remoting_client_plugin_sources, ".", "//remoting") + rebase_path(remoting_srcs_gypi_values.remoting_client_plugin_sources, + ".", + "//remoting") - # TODO(brettw) when a nacl version of this target is made, these files + if (!is_chromeos) { + sources -= [ + "normalizing_input_filter_cros.cc", + "normalizing_input_filter_cros.h", + ] + } + + # TODO(GYP) when a nacl version of this target is made, these files # won't be part of it. sources += [ "pepper_entrypoints.cc", @@ -28,6 +34,7 @@ "//ppapi/cpp/private:internal_module", "//remoting/base", "//remoting/client", + "//remoting/codec", "//remoting/protocol", "//third_party/webrtc/modules/desktop_capture", "//ui/events:dom4_keycode_converter",
diff --git a/remoting/codec/BUILD.gn b/remoting/codec/BUILD.gn new file mode 100644 index 0000000..26bf12b --- /dev/null +++ b/remoting/codec/BUILD.gn
@@ -0,0 +1,47 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//remoting/remoting_srcs.gni") + +source_set("codec") { + sources = rebase_path(remoting_srcs_gypi_values.remoting_codec_sources, + ".", + "//remoting") + + configs += [ "//build/config/compiler:wexit_time_destructors" ] + + deps = [ + "//base/third_party/dynamic_annotations", + "//media", + "//media:shared_memory_support", + "//remoting/proto", + "//remoting/resources", + "//third_party/libvpx", + "//third_party/libyuv", + "//third_party/opus", + "//third_party/webrtc/modules/desktop_capture", + ] +} + +source_set("unit_tests") { + testonly = true + + sources = [ + "audio_encoder_opus_unittest.cc", + "codec_test.cc", + "codec_test.h", + "video_decoder_vpx_unittest.cc", + "video_encoder_helper_unittest.cc", + "video_encoder_verbatim_unittest.cc", + "video_encoder_vpx_unittest.cc", + ] + + deps = [ + ":codec", + "//base", + "//remoting/proto", + "//testing/gtest", + "//third_party/webrtc/modules/desktop_capture", + ] +}
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn index 12c6bd0..417fc010 100644 --- a/remoting/host/BUILD.gn +++ b/remoting/host/BUILD.gn
@@ -4,109 +4,337 @@ import("//build/config/features.gni") import("//build/config/ui.gni") +import("//remoting/remoting_locales.gni") +import("//remoting/remoting_srcs.gni") import("//remoting/remoting_version.gni") +import("//remoting/tools/build/remoting_localize.gni") -static_library("host") { - gypi_values = exec_script("//build/gypi_to_gn.py", - [ rebase_path("../remoting_host_srcs.gypi") ], - "scope", - [ "../remoting_host_srcs.gypi" ]) - - sources = rebase_path(gypi_values.remoting_host_sources, ".", "//remoting") - - libs = [] - - configs += [ "//build/config/compiler:wexit_time_destructors" ] - - defines = [ "WEBRTC_CHROMIUM_BUILD" ] - - deps = [ - "//base:i18n", - "//components/policy:policy", - "//components/policy:policy_component_common", - "//crypto", - "//google_apis", - "//ipc", - "//remoting/base", - "//remoting/protocol", - "//remoting/resources", - "//ui/events/platform", - "//ui/events:dom4_keycode_converter", - ] - - if (is_linux) { - libs += [ "pam" ] +if (is_mac) { # TODO(GYP) Mac build of remoting host. + group("host") { } - - if (use_x11) { - configs += [ - #TODO : (kelvinp) Add GTK to the configs. - "//build/config/linux:x11", - ] - } else { - sources -= [ - "clipboard_x11.cc", - "linux/x_server_clipboard.cc", - "linux/x_server_clipboard.h", - ] + group("test_support") { } + group("unit_tests") { + } +} else { + # This must be a static library instead of a source set because + # remoting_unittests requires that remoting_me2me_host.cc not be pulled in, + # which in turn depends on remoting_me2me_host_static which isn't part of that + # build. + # + # TODO fix this, successful builds should not depend on static libraries + # stripping code. + static_library("host") { + sources = rebase_path(remoting_host_srcs_gypi_values.remoting_host_sources, + ".", + "//remoting") - if (is_chromeos) { - deps += [ - "//cc", - "//ppapi/host", - "//skia", - "//ui/aura", - "//ui/compositor", - "//ui/events", - "//ui/views", + libs = [] + + configs += [ "//build/config/compiler:wexit_time_destructors" ] + + defines = [ "WEBRTC_CHROMIUM_BUILD" ] + + deps = [ + "//base:i18n", + "//components/policy:policy", + "//components/policy:policy_component_common", + "//crypto", + "//google_apis", + "//ipc", + "//remoting/base", + "//remoting/protocol", + "//remoting/resources", + "//ui/events/platform", + "//ui/events:dom4_keycode_converter", ] - if (use_ash) { - deps += [ "//ash" ] + if (is_linux && !is_chromeos) { + libs += [ "pam" ] } - if (use_ozone) { - sources -= [ "input_injector_x11.cc" ] - deps += [ "//ui/ozone" ] + if (use_x11) { + configs += [ + "//build/config/linux:x11", + "//build/config/linux:xrandr", + ] + if (!is_chromeos) { + deps += [ "//build/config/linux/gtk" ] + } } else { sources -= [ "clipboard_x11.cc", - "input_injector_chromeos.cc", - "input_injector_chromeos.h", - "linux/x_server_clipboard.cc", - "linux/x_server_clipboard.h", + "input_injector_x11.cc", + "local_input_monitor_x11.cc", + ] + if (is_linux) { + # These will already be filtered out on non-Linux. + sources -= [ + "linux/x_server_clipboard.cc", + "linux/x_server_clipboard.h", + ] + } + } + + if (is_chromeos) { + deps += [ + "//cc", + "//ppapi/host", + "//skia", + "//ui/aura", + "//ui/compositor", + "//ui/events", + "//ui/views", + ] + + if (use_ash) { + deps += [ "//ash" ] + } + + if (!use_x11) { + sources -= [ "input_injector_x11.cc" ] + } + + if (use_ozone) { + deps += [ "//ui/ozone" ] + } else { + sources -= [ + "clipboard_x11.cc", + "input_injector_chromeos.cc", + "input_injector_chromeos.h", + "linux/x_server_clipboard.cc", + "linux/x_server_clipboard.h", + "local_input_monitor_x11.cc", + ] + } + + sources -= [ + "continue_window_linux.cc", + "disconnect_window_linux.cc", ] } - sources -= [ - "continue_window_linux.cc", - "disconnect_window_linux.cc", - "local_input_monitor_x11.cc", - "remoting_me2me_host.cc", + if (is_mac) { + # TODO(GYP) Mac host_bundle_name and prefpane_bundle_name. + # Note if you are looking at this: It really sucks to have to synchronously + # call into python twice to get these values. They should instead be + # written into a generated header via the process_version template, and we + # change the source files to include that header rather than rely on these + # defines being set in the build. + #defines += [ + # "HOST_BUNDLE_NAME=\"$host_bundle_name\"", + # "PREFPANE_BUNDLE_NAME=\"$prefpane_bundle_name\"", + #] + + libs += [ + "Accelerate.framework", + "libpam.a", + ] + + deps += [ "//third_party/google_toolbox_for_mac" ] + } + + if (is_win) { + deps += [ + ":messages", + ":remoting_lib_idl", + ] + } + + if (enable_webrtc) { + deps += [ + "//third_party/libjingle:libpeerconnection", + "//third_party/webrtc/modules/desktop_capture", + ] + + sources += + rebase_path(remoting_host_srcs_gypi_values.remoting_cast_sources, + ".", + "//remoting") + } + } + + source_set("test_support") { + testonly = true + + sources = [ + "fake_desktop_capturer.cc", + "fake_desktop_capturer.h", + "fake_desktop_environment.cc", + "fake_desktop_environment.h", + "fake_host_extension.cc", + "fake_host_extension.h", + "fake_host_status_monitor.h", + "fake_host_status_monitor.h", + "fake_mouse_cursor_monitor.cc", + "fake_mouse_cursor_monitor.h", + ] + + deps = [ + "//remoting/proto", + "//testing/gtest", + ] + public_deps = [ + ":host", + ] + + if (enable_webrtc) { + public_deps += [ + "//third_party/libjingle:libpeerconnection", + "//third_party/webrtc/modules/desktop_capture", + ] + } + } + + # The host portions of the remoting unit tests. + source_set("unit_tests") { + testonly = true + + sources = [ + "audio_pump_unittest.cc", + "audio_silence_detector_unittest.cc", + "capture_scheduler_unittest.cc", + "chromeos/aura_desktop_capturer_unittest.cc", + "chromeos/clipboard_aura_unittest.cc", + "chromoting_host_context_unittest.cc", + "chromoting_host_unittest.cc", + "client_session_unittest.cc", + "config_file_watcher_unittest.cc", + "daemon_process_unittest.cc", + "desktop_process_unittest.cc", + "desktop_shape_tracker_unittest.cc", + "gnubby_auth_handler_posix_unittest.cc", + "heartbeat_sender_unittest.cc", + "host_change_notification_listener_unittest.cc", + "host_config_unittest.cc", + "host_extension_session_manager_unittest.cc", + "host_mock_objects.cc", + "host_status_logger_unittest.cc", + "ipc_desktop_environment_unittest.cc", + "it2me/it2me_confirmation_dialog_proxy_unittest.cc", + "it2me/it2me_native_messaging_host_unittest.cc", + "linux/audio_pipe_reader_unittest.cc", + "linux/unicode_to_keysym_unittest.cc", + "linux/x_server_clipboard_unittest.cc", + "local_input_monitor_unittest.cc", + "mouse_shape_pump_unittest.cc", + "native_messaging/native_messaging_reader_unittest.cc", + "native_messaging/native_messaging_writer_unittest.cc", + "pairing_registry_delegate_linux_unittest.cc", + "pairing_registry_delegate_win_unittest.cc", + "pin_hash_unittest.cc", + "policy_watcher_unittest.cc", + "register_support_host_request_unittest.cc", + "remote_input_filter_unittest.cc", + "resizing_host_observer_unittest.cc", + "screen_resolution_unittest.cc", + "server_log_entry_host_unittest.cc", + "setup/me2me_native_messaging_host_unittest.cc", + "setup/oauth_helper_unittest.cc", + "setup/pin_validator_unittest.cc", + "shaped_desktop_capturer_unittest.cc", + "token_validator_factory_impl_unittest.cc", + "video_frame_pump_unittest.cc", + "video_frame_recorder_unittest.cc", + "win/rdp_client_unittest.cc", + "win/worker_process_launcher.cc", + "win/worker_process_launcher.h", + "win/worker_process_launcher_unittest.cc", + ] + + if (use_ozone || is_chromeos) { + sources -= [ "local_input_monitor_unittest.cc" ] + } + if (is_chromeos) { + sources -= [ "linux/x_server_clipboard_unittest.cc" ] + } + + deps = [ + ":host", + ":test_support", + "//components/policy:policy_component_test_support", + "//remoting/host/setup", + "//remoting/host/it2me:common", + "//remoting/host/native_messaging", + "//remoting/proto", + "//skia", + "//testing/gmock", + "//testing/gtest", ] } - if (is_mac) { - defines += [ - "HOST_BUNDLE_NAME=\"$host_bundle_name\"", - "PREFPANE_BUNDLE_NAME=\"$prefpane_bundle_name\"", - ] + if (is_win) { + import("//build/toolchain/win/midl.gni") + import("//remoting/tools/build/message_compiler.gni") - libs += [ - "Accelerate.framework", - "libpam.a", - ] + # TODO(brettw) these should not be generated via exec_script. This should be + # part of the build process rather than the metabuild. Instead, a script + # should generate a header containing the #defines for this as well as the + # IDL file with the values. + clsids = exec_script("win/get_clsids.py", + [ + remoting_srcs_gypi_values.daemon_controller_guid, + remoting_srcs_gypi_values.rdp_desktop_session_guid, + version_full, + ], + "value") + daemon_controller_clsid = clsids[0] + rdp_desktop_session_clsid = clsids[1] - deps += [ "//google_toolbox_for_mac" ] - } + action("generate_idl") { + script = "//build/util/version.py" - if (enable_webrtc) { - deps += [ - "//third_party/libjingle:libpeerconnection", - "//third_party/webrtc/modules/desktop_capture", - ] + inputs = [ + "win/chromoting_lib_idl.templ", + ] + outputs = [ + "$target_gen_dir/chromoting_lib.idl", + ] - sources += rebase_path(gypi_values.remoting_cast_sources, ".", "//remoting") + args = [ + "-e", + "DAEMON_CONTROLLER_CLSID='$daemon_controller_clsid'", + "-e", + "RDP_DESKTOP_SESSION_CLSID='$rdp_desktop_session_clsid'", + rebase_path(inputs[0], root_build_dir), + rebase_path(outputs[0], root_build_dir), + ] + } + + midl("remoting_lib_idl") { + sources = get_target_outputs(":generate_idl") + deps = [ + ":generate_idl", + ] + } + + # Makes the .mc file from the .mc.jinja file. + remoting_localize("messages_localizing") { + sources = [ + "win/host_messages.mc.jinja2", + ] + locales = remoting_locales + locale_dir = webapp_locale_dir + encoding = "utf-16" + + # This target is funny. It only produces one file and the output doesn't + # match the input. We want to generate remoting_host_messages.mc from + # host_messages.mg.jinja2. GN complains if it doesn't see a pattern in the + # output, so the following pattern produces the name we want with a template + # based on the input. + # + # TODO: This is for GYP compat. We should just make the names match instead. + output = "$target_gen_dir/remoting_{{source_name_part}}" + } + + # Makes the .h/.rc files from the .mc file. + message_compiler("messages") { + sources = get_target_outputs(":messages_localizing") + deps = [ + ":messages_localizing", + ] + } + + # TODO(GYP) More Windows remoting targets from remoting_host_win.gypi } }
diff --git a/remoting/host/cast_extension_session.cc b/remoting/host/cast_extension_session.cc index 5b592621..4b65545 100644 --- a/remoting/host/cast_extension_session.cc +++ b/remoting/host/cast_extension_session.cc
@@ -141,7 +141,8 @@ for (const auto* report : reports) { VLOG(1) << "Report " << index++ << ":"; for (const auto& v : report->values()) { - VLOG(1) << "Stat: " << v->display_name() << "=" << v->value << "."; + VLOG(1) << "Stat: " << v.second->display_name() << "=" + << v.second->value << "."; } } }
diff --git a/remoting/host/host_config.h b/remoting/host/host_config.h index 198ddbb..1ec35ce9c8 100644 --- a/remoting/host/host_config.h +++ b/remoting/host/host_config.h
@@ -27,12 +27,8 @@ extern const char kHostOwnerEmailConfigPath[]; // Login used to authenticate in XMPP network (could be a service account). extern const char kXmppLoginConfigPath[]; -// Auth token used to authenticate to XMPP network. -extern const char kXmppAuthTokenConfigPath[]; // OAuth refresh token used to fetch an access token for the XMPP network. extern const char kOAuthRefreshTokenConfigPath[]; -// Auth service used to authenticate to XMPP network. -extern const char kXmppAuthServiceConfigPath[]; // Unique identifier of the host used to register the host in directory. // Normally a random UUID. extern const char kHostIdConfigPath[];
diff --git a/remoting/host/host_config_constants.cc b/remoting/host/host_config_constants.cc index c98e182..62631c2c 100644 --- a/remoting/host/host_config_constants.cc +++ b/remoting/host/host_config_constants.cc
@@ -13,9 +13,7 @@ const char kHostOwnerConfigPath[] = "host_owner"; const char kHostOwnerEmailConfigPath[] = "host_owner_email"; const char kXmppLoginConfigPath[] = "xmpp_login"; -const char kXmppAuthTokenConfigPath[] = "xmpp_auth_token"; const char kOAuthRefreshTokenConfigPath[] = "oauth_refresh_token"; -const char kXmppAuthServiceConfigPath[] = "xmpp_auth_service"; const char kHostIdConfigPath[] = "host_id"; const char kHostNameConfigPath[] = "host_name"; const char kHostSecretHashConfigPath[] = "host_secret_hash";
diff --git a/remoting/host/host_config_unittest.cc b/remoting/host/host_config_unittest.cc index 5e6fab6c..3500381 100644 --- a/remoting/host/host_config_unittest.cc +++ b/remoting/host/host_config_unittest.cc
@@ -17,7 +17,7 @@ const char* kTestConfig = "{\n" " \"xmpp_login\" : \"test@gmail.com\",\n" -" \"xmpp_auth_token\" : \"TEST_AUTH_TOKEN\",\n" +" \"oauth_refresh_token\" : \"TEST_REFRESH_TOKEN\",\n" " \"host_id\" : \"TEST_HOST_ID\",\n" " \"host_name\" : \"TEST_MACHINE_NAME\",\n" " \"private_key\" : \"TEST_PRIVATE_KEY\"\n" @@ -57,8 +57,8 @@ std::string value; EXPECT_TRUE(target->GetString(kXmppLoginConfigPath, &value)); EXPECT_EQ("test@gmail.com", value); - EXPECT_TRUE(target->GetString(kXmppAuthTokenConfigPath, &value)); - EXPECT_EQ("TEST_AUTH_TOKEN", value); + EXPECT_TRUE(target->GetString(kOAuthRefreshTokenConfigPath, &value)); + EXPECT_EQ("TEST_REFRESH_TOKEN", value); EXPECT_TRUE(target->GetString(kHostIdConfigPath, &value)); EXPECT_EQ("TEST_HOST_ID", value); EXPECT_TRUE(target->GetString(kHostNameConfigPath, &value)); @@ -77,8 +77,8 @@ scoped_ptr<base::DictionaryValue> target(HostConfigFromJsonFile(test_file)); ASSERT_TRUE(target); - std::string new_auth_token_value = "NEW_AUTH_TOKEN"; - target->SetString(kXmppAuthTokenConfigPath, new_auth_token_value); + std::string new_refresh_token_value = "NEW_REFRESH_TOKEN"; + target->SetString(kOAuthRefreshTokenConfigPath, new_refresh_token_value); ASSERT_TRUE(HostConfigToJsonFile(*target, test_file)); // Now read the file again and check that the value has been written. @@ -88,8 +88,8 @@ std::string value; EXPECT_TRUE(reader->GetString(kXmppLoginConfigPath, &value)); EXPECT_EQ("test@gmail.com", value); - EXPECT_TRUE(reader->GetString(kXmppAuthTokenConfigPath, &value)); - EXPECT_EQ(new_auth_token_value, value); + EXPECT_TRUE(reader->GetString(kOAuthRefreshTokenConfigPath, &value)); + EXPECT_EQ(new_refresh_token_value, value); EXPECT_TRUE(reader->GetString(kHostIdConfigPath, &value)); EXPECT_EQ("TEST_HOST_ID", value); EXPECT_TRUE(reader->GetString(kHostNameConfigPath, &value));
diff --git a/remoting/host/host_event_logger_win.cc b/remoting/host/host_event_logger_win.cc index 050d725..fa58b52 100644 --- a/remoting/host/host_event_logger_win.cc +++ b/remoting/host/host_event_logger_win.cc
@@ -15,10 +15,9 @@ #include "net/base/ip_endpoint.h" #include "remoting/host/host_status_monitor.h" #include "remoting/host/host_status_observer.h" +#include "remoting/host/remoting_host_messages.h" #include "remoting/protocol/transport.h" -#include "remoting_host_messages.h" - namespace remoting { namespace {
diff --git a/remoting/host/host_signaling_manager.cc b/remoting/host/host_signaling_manager.cc index 99ad431b..f9bb941 100644 --- a/remoting/host/host_signaling_manager.cc +++ b/remoting/host/host_signaling_manager.cc
@@ -43,18 +43,14 @@ scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker(new DnsBlackholeChecker( url_request_context_getter, talkgadget_prefix_policy)); + scoped_ptr<OAuthTokenGetter> oauth_token_getter(new OAuthTokenGetter( + oauth_credentials.Pass(), url_request_context_getter, false)); scoped_ptr<SignalingConnector> signaling_connector(new SignalingConnector( signal_strategy.get(), dns_blackhole_checker.Pass(), + oauth_token_getter.Pass(), base::Bind(&Listener::OnAuthFailed, base::Unretained(listener)))); - if (!oauth_credentials->refresh_token.empty()) { - scoped_ptr<OAuthTokenGetter> oauth_token_getter(new OAuthTokenGetter( - oauth_credentials.Pass(), url_request_context_getter, false)); - - signaling_connector->EnableOAuth(oauth_token_getter.Pass()); - } - scoped_ptr<HeartbeatSender> heartbeat_sender(new HeartbeatSender( base::Bind(&Listener::OnHeartbeatSuccessful, base::Unretained(listener)), base::Bind(&Listener::OnUnknownHostIdError, base::Unretained(listener)),
diff --git a/remoting/host/it2me/BUILD.gn b/remoting/host/it2me/BUILD.gn index 744dfe6..77dad43 100644 --- a/remoting/host/it2me/BUILD.gn +++ b/remoting/host/it2me/BUILD.gn
@@ -3,20 +3,18 @@ # found in the LICENSE file. import("//build/config/features.gni") -import("//build/config/ui.gni") -import("//remoting/remoting_version.gni") +import("//remoting/remoting_srcs.gni") -static_library("common") { - gypi_values = exec_script("//build/gypi_to_gn.py", - [ rebase_path("../../remoting_host_srcs.gypi") ], - "scope", - [ "../../remoting_host_srcs.gypi" ]) +source_set("common") { + sources = rebase_path( + remoting_host_srcs_gypi_values.remoting_it2me_host_static_sources, + ".", + "//remoting") - sources = rebase_path(gypi_values.remoting_it2me_host_static_sources, - ".", - "//remoting") - - configs += [ "//build/config/compiler:wexit_time_destructors" ] + configs += [ + "//build/config/compiler:wexit_time_destructors", + "//remoting:version", + ] deps = [ "//base:i18n", @@ -26,6 +24,4 @@ "//remoting/protocol", "//remoting/resources", ] - - defines = [ "VERSION=$version_full" ] }
diff --git a/remoting/host/it2me/it2me_host.cc b/remoting/host/it2me/it2me_host.cc index 22a9790..0ea715f3 100644 --- a/remoting/host/it2me/it2me_host.cc +++ b/remoting/host/it2me/it2me_host.cc
@@ -229,8 +229,10 @@ protocol::NetworkSettings::NAT_TRAVERSAL_FULL : protocol::NetworkSettings::NAT_TRAVERSAL_DISABLED); if (!nat_traversal_enabled_) { - network_settings.min_port = protocol::NetworkSettings::kDefaultMinPort; - network_settings.max_port = protocol::NetworkSettings::kDefaultMaxPort; + network_settings.port_range.min_port = + protocol::NetworkSettings::kDefaultMinPort; + network_settings.port_range.max_port = + protocol::NetworkSettings::kDefaultMaxPort; } // Create the host.
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc index 148dc01..7af2db74 100644 --- a/remoting/host/it2me/it2me_native_messaging_host.cc +++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -12,13 +12,13 @@ #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" #include "base/strings/stringize_macros.h" #include "base/threading/thread.h" #include "base/values.h" #include "media/base/media.h" #include "net/base/net_util.h" #include "net/url_request/url_request_context_getter.h" -#include "remoting/base/auth_token_util.h" #include "remoting/base/service_urls.h" #include "remoting/host/chromoting_host_context.h" #include "remoting/host/host_exit_codes.h" @@ -164,16 +164,19 @@ return; } - ParseAuthTokenWithService(auth_service_with_token, - &xmpp_config.auth_token, - &xmpp_config.auth_service); - if (xmpp_config.auth_token.empty()) { - SendErrorAndExit( - response.Pass(), - "Invalid 'authServiceWithToken': " + auth_service_with_token); + // For backward compatibility the webapp still passes OAuth service as part of + // the authServiceWithToken field. But auth service part is always expected to + // be set to oauth2. + const char kOAuth2ServicePrefix[] = "oauth2:"; + if (!StartsWithASCII(auth_service_with_token, kOAuth2ServicePrefix, true)) { + SendErrorAndExit(response.Pass(), "Invalid 'authServiceWithToken': " + + auth_service_with_token); return; } + xmpp_config.auth_token = + auth_service_with_token.substr(strlen(kOAuth2ServicePrefix)); + #if !defined(NDEBUG) std::string address; if (!message.GetString("xmppServerAddress", &address)) {
diff --git a/remoting/host/native_messaging/BUILD.gn b/remoting/host/native_messaging/BUILD.gn new file mode 100644 index 0000000..afefee1 --- /dev/null +++ b/remoting/host/native_messaging/BUILD.gn
@@ -0,0 +1,19 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//remoting/remoting_srcs.gni") + +# GYP version: remoting/remoting_host.gypi:remoting_native_messaging_base +source_set("native_messaging") { + sources = rebase_path( + remoting_host_srcs_gypi_values.remoting_host_native_messaging_sources, + ".", + "//remoting") + + configs += [ "//build/config/compiler:wexit_time_destructors" ] + + deps = [ + "//base", + ] +}
diff --git a/remoting/host/pairing_registry_delegate_linux.cc b/remoting/host/pairing_registry_delegate_linux.cc index 5082317..7b22721 100644 --- a/remoting/host/pairing_registry_delegate_linux.cc +++ b/remoting/host/pairing_registry_delegate_linux.cc
@@ -46,11 +46,11 @@ for (base::FilePath pairing_file = enumerator.Next(); !pairing_file.empty(); pairing_file = enumerator.Next()) { // Read the JSON containing pairing data. - JSONFileValueSerializer serializer(pairing_file); + JSONFileValueDeserializer deserializer(pairing_file); int error_code; std::string error_message; scoped_ptr<base::Value> pairing_json( - serializer.Deserialize(&error_code, &error_message)); + deserializer.Deserialize(&error_code, &error_message)); if (!pairing_json) { LOG(WARNING) << "Failed to load '" << pairing_file.value() << "' (" << error_code << ")."; @@ -85,11 +85,11 @@ base::FilePath pairing_file = registry_path.Append( base::StringPrintf(kPairingFilenameFormat, client_id.c_str())); - JSONFileValueSerializer serializer(pairing_file); + JSONFileValueDeserializer deserializer(pairing_file); int error_code; std::string error_message; scoped_ptr<base::Value> pairing( - serializer.Deserialize(&error_code, &error_message)); + deserializer.Deserialize(&error_code, &error_message)); if (!pairing) { LOG(WARNING) << "Failed to load pairing information: " << error_message << " (" << error_code << ").";
diff --git a/remoting/host/pairing_registry_delegate_win.cc b/remoting/host/pairing_registry_delegate_win.cc index 1beac2f5..a714e31 100644 --- a/remoting/host/pairing_registry_delegate_win.cc +++ b/remoting/host/pairing_registry_delegate_win.cc
@@ -49,10 +49,10 @@ // Parse the value. std::string value_json_utf8 = base::WideToUTF8(value_json); - JSONStringValueSerializer serializer(&value_json_utf8); + JSONStringValueDeserializer deserializer(value_json_utf8); int error_code; std::string error_message; - scoped_ptr<base::Value> value(serializer.Deserialize(&error_code, + scoped_ptr<base::Value> value(deserializer.Deserialize(&error_code, &error_message)); if (!value) { LOG(ERROR) << "Failed to parse '" << value_name << "': " << error_message
diff --git a/remoting/host/policy_watcher.cc b/remoting/host/policy_watcher.cc index 2cf7be88..60f14c9 100644 --- a/remoting/host/policy_watcher.cc +++ b/remoting/host/policy_watcher.cc
@@ -21,6 +21,8 @@ #include "components/policy/core/common/schema_registry.h" #include "policy/policy_constants.h" #include "remoting/host/dns_blackhole_checker.h" +#include "remoting/host/third_party_auth_config.h" +#include "remoting/protocol/port_range.h" #if !defined(NDEBUG) #include "base/json/json_reader.h" @@ -44,15 +46,15 @@ // Copies all policy values from one dictionary to another, using values from // |default_values| if they are not set in |from|. scoped_ptr<base::DictionaryValue> CopyValuesAndAddDefaults( - const base::DictionaryValue* from, - const base::DictionaryValue* default_values) { - scoped_ptr<base::DictionaryValue> to(default_values->DeepCopy()); - for (base::DictionaryValue::Iterator i(*default_values); !i.IsAtEnd(); + const base::DictionaryValue& from, + const base::DictionaryValue& default_values) { + scoped_ptr<base::DictionaryValue> to(default_values.DeepCopy()); + for (base::DictionaryValue::Iterator i(default_values); !i.IsAtEnd(); i.Advance()) { const base::Value* value = nullptr; // If the policy isn't in |from|, use the default. - if (!from->Get(i.key(), &value)) { + if (!from.Get(i.key(), &value)) { continue; } @@ -63,8 +65,8 @@ #if !defined(NDEBUG) // Replace values with those specified in DebugOverridePolicies, if present. std::string policy_overrides; - if (from->GetString(key::kRemoteAccessHostDebugOverridePolicies, - &policy_overrides)) { + if (from.GetString(key::kRemoteAccessHostDebugOverridePolicies, + &policy_overrides)) { scoped_ptr<base::Value> value(base::JSONReader::Read(policy_overrides)); const base::DictionaryValue* override_values; if (value && value->GetAsDictionary(&override_values)) { @@ -92,6 +94,56 @@ return schema_registry.Pass(); } +scoped_ptr<base::DictionaryValue> CopyChromotingPoliciesIntoDictionary( + const policy::PolicyMap& current) { + const char kPolicyNameSubstring[] = "RemoteAccessHost"; + scoped_ptr<base::DictionaryValue> policy_dict(new base::DictionaryValue()); + for (auto it = current.begin(); it != current.end(); ++it) { + const std::string& key = it->first; + const base::Value* value = it->second.value; + + // Copying only Chromoting-specific policies helps avoid false alarms + // raised by NormalizePolicies below (such alarms shutdown the host). + // TODO(lukasza): Removing this somewhat brittle filtering will be possible + // after having separate, Chromoting-specific schema. + if (key.find(kPolicyNameSubstring) != std::string::npos) { + policy_dict->Set(key, value->DeepCopy()); + } + } + + return policy_dict.Pass(); +} + +// Takes a dictionary containing only 1) recognized policy names and 2) +// well-typed policy values and further verifies policy contents. +bool VerifyWellformedness(const base::DictionaryValue& changed_policies) { + // Verify ThirdPartyAuthConfig policy. + ThirdPartyAuthConfig not_used; + switch (ThirdPartyAuthConfig::Parse(changed_policies, ¬_used)) { + case ThirdPartyAuthConfig::NoPolicy: + case ThirdPartyAuthConfig::ParsingSuccess: + break; // Well-formed. + case ThirdPartyAuthConfig::InvalidPolicy: + return false; // Malformed. + default: + NOTREACHED(); + return false; + } + + // Verify UdpPortRange policy. + std::string udp_port_range_string; + PortRange udp_port_range; + if (changed_policies.GetString(policy::key::kRemoteAccessHostUdpPortRange, + &udp_port_range_string)) { + if (!PortRange::Parse(udp_port_range_string, &udp_port_range)) { + return false; + } + } + + // Report that all the policies were well-formed. + return true; +} + } // namespace void PolicyWatcher::StartWatching( @@ -114,36 +166,6 @@ } } -void PolicyWatcher::UpdatePolicies( - const base::DictionaryValue* new_policies_raw) { - DCHECK(CalledOnValidThread()); - - // Use default values for any missing policies. - scoped_ptr<base::DictionaryValue> new_policies = - CopyValuesAndAddDefaults(new_policies_raw, default_values_.get()); - - // Find the changed policies. - scoped_ptr<base::DictionaryValue> changed_policies( - new base::DictionaryValue()); - base::DictionaryValue::Iterator iter(*new_policies); - while (!iter.IsAtEnd()) { - base::Value* old_policy; - if (!(old_policies_->Get(iter.key(), &old_policy) && - old_policy->Equals(&iter.value()))) { - changed_policies->Set(iter.key(), iter.value().DeepCopy()); - } - iter.Advance(); - } - - // Save the new policies. - old_policies_.swap(new_policies); - - // Notify our client of the changed policies. - if (!changed_policies->empty()) { - policy_updated_callback_.Run(changed_policies.Pass()); - } -} - void PolicyWatcher::SignalPolicyError() { old_policies_->Clear(); policy_error_callback_.Run(); @@ -201,24 +223,7 @@ return owned_schema_registry_->schema_map()->GetSchema(GetPolicyNamespace()); } -void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns, - const policy::PolicyMap& previous, - const policy::PolicyMap& current) { - const char kPolicyNamePrefix[] = "RemoteAccessHost"; - scoped_ptr<base::DictionaryValue> policy_dict(new base::DictionaryValue()); - for (auto it = current.begin(); it != current.end(); ++it) { - const std::string& key = it->first; - const base::Value* value = it->second.value; - - // Copying only Chromoting-specific policies helps avoid false alarms - // raised by Schema::Normalize below (such alarms shutdown the host). - // TODO(lukasza): Removing this somewhat brittle filtering will be possible - // after having separate, Chromoting-specific schema. - if (key.find(kPolicyNamePrefix) != std::string::npos) { - policy_dict->Set(key, value->DeepCopy()); - } - } - +bool PolicyWatcher::NormalizePolicies(base::DictionaryValue* policy_dict) { // Allowing unrecognized policy names allows presence of // 1) comments (i.e. JSON of the form: { "_comment": "blah", ... }), // 2) policies intended for future/newer versions of the host, @@ -231,18 +236,97 @@ std::string error; bool changed = false; const policy::Schema* schema = GetPolicySchema(); - if (schema->Normalize(policy_dict.get(), strategy, &path, &error, &changed)) { + if (schema->Normalize(policy_dict, strategy, &path, &error, &changed)) { if (changed) { LOG(WARNING) << "Unknown (unrecognized or unsupported) policy: " << path << ": " << error; } - UpdatePolicies(policy_dict.get()); + return true; } else { LOG(ERROR) << "Invalid policy contents: " << path << ": " << error; - SignalPolicyError(); + return false; } } +namespace { +void CopyDictionaryValue(const base::DictionaryValue& from, + base::DictionaryValue& to, + std::string key) { + const base::Value* value; + if (from.Get(key, &value)) { + to.Set(key, value->DeepCopy()); + } +} +} // namespace + +scoped_ptr<base::DictionaryValue> +PolicyWatcher::StoreNewAndReturnChangedPolicies( + scoped_ptr<base::DictionaryValue> new_policies) { + // Find the changed policies. + scoped_ptr<base::DictionaryValue> changed_policies( + new base::DictionaryValue()); + base::DictionaryValue::Iterator iter(*new_policies); + while (!iter.IsAtEnd()) { + base::Value* old_policy; + if (!(old_policies_->Get(iter.key(), &old_policy) && + old_policy->Equals(&iter.value()))) { + changed_policies->Set(iter.key(), iter.value().DeepCopy()); + } + iter.Advance(); + } + + // If one of ThirdPartyAuthConfig policies changed, we need to include all. + if (changed_policies->HasKey(key::kRemoteAccessHostTokenUrl) || + changed_policies->HasKey(key::kRemoteAccessHostTokenValidationUrl) || + changed_policies->HasKey( + key::kRemoteAccessHostTokenValidationCertificateIssuer)) { + CopyDictionaryValue(*new_policies, *changed_policies, + key::kRemoteAccessHostTokenUrl); + CopyDictionaryValue(*new_policies, *changed_policies, + key::kRemoteAccessHostTokenValidationUrl); + CopyDictionaryValue(*new_policies, *changed_policies, + key::kRemoteAccessHostTokenValidationCertificateIssuer); + } + + // Save the new policies. + old_policies_.swap(new_policies); + + return changed_policies.Pass(); +} + +void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns, + const policy::PolicyMap& previous, + const policy::PolicyMap& current) { + scoped_ptr<base::DictionaryValue> new_policies = + CopyChromotingPoliciesIntoDictionary(current); + + // Check for mistyped values and get rid of unknown policies. + if (!NormalizePolicies(new_policies.get())) { + SignalPolicyError(); + return; + } + + // Use default values for any missing policies. + scoped_ptr<base::DictionaryValue> filled_policies = + CopyValuesAndAddDefaults(*new_policies, *default_values_); + + // Limit reporting to only the policies that were changed. + scoped_ptr<base::DictionaryValue> changed_policies = + StoreNewAndReturnChangedPolicies(filled_policies.Pass()); + if (changed_policies->empty()) { + return; + } + + // Verify that we are calling the callback with valid policies. + if (!VerifyWellformedness(*changed_policies)) { + SignalPolicyError(); + return; + } + + // Notify our client of the changed policies. + policy_updated_callback_.Run(changed_policies.Pass()); +} + void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain) { policy::PolicyNamespace ns = GetPolicyNamespace(); const policy::PolicyMap& current = policy_service_->GetPolicies(ns);
diff --git a/remoting/host/policy_watcher.h b/remoting/host/policy_watcher.h index 6b690ab..1cd5833 100644 --- a/remoting/host/policy_watcher.h +++ b/remoting/host/policy_watcher.h
@@ -80,13 +80,20 @@ private: friend class PolicyWatcherTest; - // Takes the policy dictionary from the OS specific store and extracts the - // relevant policies. - void UpdatePolicies(const base::DictionaryValue* new_policy); - // Gets Chromoting schema stored inside |owned_schema_registry_|. const policy::Schema* GetPolicySchema() const; + // Simplifying wrapper around Schema::Normalize. + // - Returns false if |dict| is invalid (i.e. contains mistyped policy + // values). + // - Returns true if |dict| was valid or got normalized. + bool NormalizePolicies(base::DictionaryValue* dict); + + // Stores |new_policies| into |old_policies_|. Returns dictionary with items + // from |new_policies| that are different from the old |old_policies_|. + scoped_ptr<base::DictionaryValue> StoreNewAndReturnChangedPolicies( + scoped_ptr<base::DictionaryValue> new_policies); + // Signals policy error to the registered |PolicyErrorCallback|. void SignalPolicyError();
diff --git a/remoting/host/policy_watcher_unittest.cc b/remoting/host/policy_watcher_unittest.cc index c4a8084..9845828 100644 --- a/remoting/host/policy_watcher_unittest.cc +++ b/remoting/host/policy_watcher_unittest.cc
@@ -8,6 +8,7 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/synchronization/waitable_event.h" +#include "base/test/mock_log.h" #include "components/policy/core/common/fake_async_policy_loader.h" #include "policy/policy_constants.h" #include "remoting/host/dns_blackhole_checker.h" @@ -17,6 +18,8 @@ namespace remoting { +namespace key = ::policy::key; + MATCHER_P(IsPolicies, dict, "") { bool equal = arg->Equals(dict); if (!equal) { @@ -56,6 +59,10 @@ PolicyWatcherTest() : message_loop_(base::MessageLoop::TYPE_IO) {} void SetUp() override { + // We expect no callbacks unless explicitly specified by individual tests. + EXPECT_CALL(mock_policy_callback_, OnPolicyUpdatePtr(testing::_)).Times(0); + EXPECT_CALL(mock_policy_callback_, OnPolicyError()).Times(0); + message_loop_proxy_ = base::MessageLoopProxy::current(); // Retaining a raw pointer to keep control over policy contents. @@ -63,96 +70,94 @@ policy_watcher_ = PolicyWatcher::CreateFromPolicyLoader(make_scoped_ptr(policy_loader_)); - nat_true_.SetBoolean(policy::key::kRemoteAccessHostFirewallTraversal, true); - nat_false_.SetBoolean(policy::key::kRemoteAccessHostFirewallTraversal, - false); - nat_one_.SetInteger(policy::key::kRemoteAccessHostFirewallTraversal, 1); - domain_empty_.SetString(policy::key::kRemoteAccessHostDomain, - std::string()); - domain_full_.SetString(policy::key::kRemoteAccessHostDomain, kHostDomain); + nat_true_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, true); + nat_false_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, false); + nat_one_.SetInteger(key::kRemoteAccessHostFirewallTraversal, 1); + nat_one_domain_full_.SetInteger(key::kRemoteAccessHostFirewallTraversal, 1); + nat_one_domain_full_.SetString(key::kRemoteAccessHostDomain, kHostDomain); + domain_empty_.SetString(key::kRemoteAccessHostDomain, std::string()); + domain_full_.SetString(key::kRemoteAccessHostDomain, kHostDomain); SetDefaults(nat_true_others_default_); - nat_true_others_default_.SetBoolean( - policy::key::kRemoteAccessHostFirewallTraversal, true); + nat_true_others_default_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, + true); SetDefaults(nat_false_others_default_); nat_false_others_default_.SetBoolean( - policy::key::kRemoteAccessHostFirewallTraversal, false); + key::kRemoteAccessHostFirewallTraversal, false); SetDefaults(domain_empty_others_default_); - domain_empty_others_default_.SetString(policy::key::kRemoteAccessHostDomain, + domain_empty_others_default_.SetString(key::kRemoteAccessHostDomain, std::string()); SetDefaults(domain_full_others_default_); - domain_full_others_default_.SetString(policy::key::kRemoteAccessHostDomain, + domain_full_others_default_.SetString(key::kRemoteAccessHostDomain, kHostDomain); - nat_true_domain_empty_.SetBoolean( - policy::key::kRemoteAccessHostFirewallTraversal, true); - nat_true_domain_empty_.SetString(policy::key::kRemoteAccessHostDomain, + nat_true_domain_empty_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, + true); + nat_true_domain_empty_.SetString(key::kRemoteAccessHostDomain, std::string()); - nat_true_domain_full_.SetBoolean( - policy::key::kRemoteAccessHostFirewallTraversal, true); - nat_true_domain_full_.SetString(policy::key::kRemoteAccessHostDomain, - kHostDomain); - nat_false_domain_empty_.SetBoolean( - policy::key::kRemoteAccessHostFirewallTraversal, false); - nat_false_domain_empty_.SetString(policy::key::kRemoteAccessHostDomain, + nat_true_domain_full_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, + true); + nat_true_domain_full_.SetString(key::kRemoteAccessHostDomain, kHostDomain); + nat_false_domain_empty_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, + false); + nat_false_domain_empty_.SetString(key::kRemoteAccessHostDomain, std::string()); - nat_false_domain_full_.SetBoolean( - policy::key::kRemoteAccessHostFirewallTraversal, false); - nat_false_domain_full_.SetString(policy::key::kRemoteAccessHostDomain, - kHostDomain); + nat_false_domain_full_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, + false); + nat_false_domain_full_.SetString(key::kRemoteAccessHostDomain, kHostDomain); SetDefaults(nat_true_domain_empty_others_default_); nat_true_domain_empty_others_default_.SetBoolean( - policy::key::kRemoteAccessHostFirewallTraversal, true); + key::kRemoteAccessHostFirewallTraversal, true); nat_true_domain_empty_others_default_.SetString( - policy::key::kRemoteAccessHostDomain, std::string()); + key::kRemoteAccessHostDomain, std::string()); unknown_policies_.SetString("UnknownPolicyOne", std::string()); unknown_policies_.SetString("UnknownPolicyTwo", std::string()); unknown_policies_.SetBoolean("RemoteAccessHostUnknownPolicyThree", true); const char kOverrideNatTraversalToFalse[] = "{ \"RemoteAccessHostFirewallTraversal\": false }"; - nat_true_and_overridden_.SetBoolean( - policy::key::kRemoteAccessHostFirewallTraversal, true); + nat_true_and_overridden_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, + true); nat_true_and_overridden_.SetString( - policy::key::kRemoteAccessHostDebugOverridePolicies, + key::kRemoteAccessHostDebugOverridePolicies, kOverrideNatTraversalToFalse); - pairing_true_.SetBoolean(policy::key::kRemoteAccessHostAllowClientPairing, - true); - pairing_false_.SetBoolean(policy::key::kRemoteAccessHostAllowClientPairing, - false); - gnubby_auth_true_.SetBoolean(policy::key::kRemoteAccessHostAllowGnubbyAuth, - true); - gnubby_auth_false_.SetBoolean(policy::key::kRemoteAccessHostAllowGnubbyAuth, - false); - relay_true_.SetBoolean(policy::key::kRemoteAccessHostAllowRelayedConnection, - true); - relay_false_.SetBoolean( - policy::key::kRemoteAccessHostAllowRelayedConnection, false); - port_range_full_.SetString(policy::key::kRemoteAccessHostUdpPortRange, - kPortRange); - port_range_empty_.SetString(policy::key::kRemoteAccessHostUdpPortRange, + pairing_true_.SetBoolean(key::kRemoteAccessHostAllowClientPairing, true); + pairing_false_.SetBoolean(key::kRemoteAccessHostAllowClientPairing, false); + gnubby_auth_true_.SetBoolean(key::kRemoteAccessHostAllowGnubbyAuth, true); + gnubby_auth_false_.SetBoolean(key::kRemoteAccessHostAllowGnubbyAuth, false); + relay_true_.SetBoolean(key::kRemoteAccessHostAllowRelayedConnection, true); + relay_false_.SetBoolean(key::kRemoteAccessHostAllowRelayedConnection, + false); + port_range_full_.SetString(key::kRemoteAccessHostUdpPortRange, kPortRange); + port_range_empty_.SetString(key::kRemoteAccessHostUdpPortRange, std::string()); - curtain_true_.SetBoolean(policy::key::kRemoteAccessHostRequireCurtain, - true); - curtain_false_.SetBoolean(policy::key::kRemoteAccessHostRequireCurtain, - false); - username_true_.SetBoolean(policy::key::kRemoteAccessHostMatchUsername, - true); - username_false_.SetBoolean(policy::key::kRemoteAccessHostMatchUsername, - false); - talk_gadget_blah_.SetString(policy::key::kRemoteAccessHostTalkGadgetPrefix, - "blah"); - token_url_https_.SetString(policy::key::kRemoteAccessHostTalkGadgetPrefix, - "https://example.com"); - token_validation_url_https_.SetString( - policy::key::kRemoteAccessHostTalkGadgetPrefix, "https://example.com"); - token_certificate_blah_.SetString( - policy::key::kRemoteAccessHostTokenValidationCertificateIssuer, "blah"); + port_range_malformed_.SetString(key::kRemoteAccessHostUdpPortRange, + "malformed"); + port_range_malformed_domain_full_.MergeDictionary(&port_range_malformed_); + port_range_malformed_domain_full_.SetString(key::kRemoteAccessHostDomain, + kHostDomain); + + curtain_true_.SetBoolean(key::kRemoteAccessHostRequireCurtain, true); + curtain_false_.SetBoolean(key::kRemoteAccessHostRequireCurtain, false); + username_true_.SetBoolean(key::kRemoteAccessHostMatchUsername, true); + username_false_.SetBoolean(key::kRemoteAccessHostMatchUsername, false); + talk_gadget_blah_.SetString(key::kRemoteAccessHostTalkGadgetPrefix, "blah"); + third_party_auth_partial_.SetString(key::kRemoteAccessHostTokenUrl, + "https://token.com"); + third_party_auth_partial_.SetString( + key::kRemoteAccessHostTokenValidationUrl, "https://validation.com"); + third_party_auth_full_.MergeDictionary(&third_party_auth_partial_); + third_party_auth_full_.SetString( + key::kRemoteAccessHostTokenValidationCertificateIssuer, + "certificate subject"); + third_party_auth_cert_empty_.MergeDictionary(&third_party_auth_partial_); + third_party_auth_cert_empty_.SetString( + key::kRemoteAccessHostTokenValidationCertificateIssuer, ""); #if !defined(NDEBUG) SetDefaults(nat_false_overridden_others_default_); nat_false_overridden_others_default_.SetBoolean( - policy::key::kRemoteAccessHostFirewallTraversal, false); + key::kRemoteAccessHostFirewallTraversal, false); nat_false_overridden_others_default_.SetString( - policy::key::kRemoteAccessHostDebugOverridePolicies, + key::kRemoteAccessHostDebugOverridePolicies, kOverrideNatTraversalToFalse); #endif } @@ -214,6 +219,7 @@ base::DictionaryValue nat_true_; base::DictionaryValue nat_false_; base::DictionaryValue nat_one_; + base::DictionaryValue nat_one_domain_full_; base::DictionaryValue domain_empty_; base::DictionaryValue domain_full_; base::DictionaryValue nat_true_others_default_; @@ -236,35 +242,34 @@ base::DictionaryValue relay_false_; base::DictionaryValue port_range_full_; base::DictionaryValue port_range_empty_; + base::DictionaryValue port_range_malformed_; + base::DictionaryValue port_range_malformed_domain_full_; base::DictionaryValue curtain_true_; base::DictionaryValue curtain_false_; base::DictionaryValue username_true_; base::DictionaryValue username_false_; base::DictionaryValue talk_gadget_blah_; - base::DictionaryValue token_url_https_; - base::DictionaryValue token_validation_url_https_; - base::DictionaryValue token_certificate_blah_; + base::DictionaryValue third_party_auth_full_; + base::DictionaryValue third_party_auth_partial_; + base::DictionaryValue third_party_auth_cert_empty_; private: void SetDefaults(base::DictionaryValue& dict) { - dict.SetBoolean(policy::key::kRemoteAccessHostFirewallTraversal, true); - dict.SetBoolean(policy::key::kRemoteAccessHostAllowRelayedConnection, true); - dict.SetString(policy::key::kRemoteAccessHostUdpPortRange, ""); - dict.SetString(policy::key::kRemoteAccessHostDomain, std::string()); - dict.SetBoolean(policy::key::kRemoteAccessHostMatchUsername, false); - dict.SetString(policy::key::kRemoteAccessHostTalkGadgetPrefix, + dict.SetBoolean(key::kRemoteAccessHostFirewallTraversal, true); + dict.SetBoolean(key::kRemoteAccessHostAllowRelayedConnection, true); + dict.SetString(key::kRemoteAccessHostUdpPortRange, ""); + dict.SetString(key::kRemoteAccessHostDomain, std::string()); + dict.SetBoolean(key::kRemoteAccessHostMatchUsername, false); + dict.SetString(key::kRemoteAccessHostTalkGadgetPrefix, kDefaultHostTalkGadgetPrefix); - dict.SetBoolean(policy::key::kRemoteAccessHostRequireCurtain, false); - dict.SetString(policy::key::kRemoteAccessHostTokenUrl, std::string()); - dict.SetString(policy::key::kRemoteAccessHostTokenValidationUrl, - std::string()); - dict.SetString( - policy::key::kRemoteAccessHostTokenValidationCertificateIssuer, - std::string()); - dict.SetBoolean(policy::key::kRemoteAccessHostAllowClientPairing, true); - dict.SetBoolean(policy::key::kRemoteAccessHostAllowGnubbyAuth, true); + dict.SetBoolean(key::kRemoteAccessHostRequireCurtain, false); + dict.SetString(key::kRemoteAccessHostTokenUrl, ""); + dict.SetString(key::kRemoteAccessHostTokenValidationUrl, ""); + dict.SetString(key::kRemoteAccessHostTokenValidationCertificateIssuer, ""); + dict.SetBoolean(key::kRemoteAccessHostAllowClientPairing, true); + dict.SetBoolean(key::kRemoteAccessHostAllowGnubbyAuth, true); #if !defined(NDEBUG) - dict.SetString(policy::key::kRemoteAccessHostDebugOverridePolicies, ""); + dict.SetString(key::kRemoteAccessHostDebugOverridePolicies, ""); #endif ASSERT_THAT(&dict, IsPolicies(&GetDefaultValues())) @@ -307,6 +312,26 @@ StartWatching(); } +// This test verifies that a mistyped policy value is still detected +// even though it doesn't change during the second SetPolicies call. +TEST_F(PolicyWatcherTest, NatWrongTypeThenIrrelevantChange) { + EXPECT_CALL(mock_policy_callback_, OnPolicyError()).Times(2); + + SetPolicies(nat_one_); + StartWatching(); + SetPolicies(nat_one_domain_full_); +} + +// This test verifies that a malformed policy value is still detected +// even though it doesn't change during the second SetPolicies call. +TEST_F(PolicyWatcherTest, PortRangeMalformedThenIrrelevantChange) { + EXPECT_CALL(mock_policy_callback_, OnPolicyError()).Times(2); + + SetPolicies(port_range_malformed_); + StartWatching(); + SetPolicies(port_range_malformed_domain_full_); +} + TEST_F(PolicyWatcherTest, DomainEmpty) { EXPECT_CALL(mock_policy_callback_, OnPolicyUpdatePtr(IsPolicies(&domain_empty_others_default_))); @@ -415,6 +440,43 @@ SetPolicies(empty_); } +class MisspelledPolicyTest : public PolicyWatcherTest, + public ::testing::WithParamInterface<const char*> { +}; + +// Verify that a misspelled policy causes a warning written to the log. +TEST_P(MisspelledPolicyTest, WarningLogged) { + const char* misspelled_policy_name = GetParam(); + base::test::MockLog mock_log; + + ON_CALL(mock_log, Log(testing::_, testing::_, testing::_, testing::_, + testing::_)).WillByDefault(testing::Return(true)); + + EXPECT_CALL(mock_log, + Log(logging::LOG_WARNING, testing::_, testing::_, testing::_, + testing::HasSubstr(misspelled_policy_name))).Times(1); + + EXPECT_CALL(mock_policy_callback_, + OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_))); + + base::DictionaryValue misspelled_policies; + misspelled_policies.SetString(misspelled_policy_name, "some test value"); + mock_log.StartCapturingLogs(); + + SetPolicies(misspelled_policies); + StartWatching(); + + mock_log.StopCapturingLogs(); +} + +INSTANTIATE_TEST_CASE_P( + PolicyWatcherTest, + MisspelledPolicyTest, + ::testing::Values("RemoteAccessHostDomainX", + "XRemoteAccessHostDomain", + "RemoteAccessHostdomain", + "RemoteAccessHostPolicyForFutureVersion")); + TEST_F(PolicyWatcherTest, DebugOverrideNatPolicy) { #if !defined(NDEBUG) EXPECT_CALL( @@ -521,40 +583,36 @@ SetPolicies(talk_gadget_blah_); } -TEST_F(PolicyWatcherTest, TokenUrl) { +TEST_F(PolicyWatcherTest, ThirdPartyAuthFull) { testing::InSequence sequence; EXPECT_CALL(mock_policy_callback_, OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_))); EXPECT_CALL(mock_policy_callback_, - OnPolicyUpdatePtr(IsPolicies(&token_url_https_))); + OnPolicyUpdatePtr(IsPolicies(&third_party_auth_full_))); SetPolicies(empty_); StartWatching(); - SetPolicies(token_url_https_); + SetPolicies(third_party_auth_full_); } -TEST_F(PolicyWatcherTest, TokenValidationUrl) { +// This test verifies what happens when only 1 out of 3 third-party auth +// policies changes. Without the other 2 policy values such policy values +// combination is invalid (i.e. cannot have TokenUrl without +// TokenValidationUrl) and can trigger OnPolicyError unless PolicyWatcher +// implementation is careful around this scenario. +TEST_F(PolicyWatcherTest, ThirdPartyAuthPartialToFull) { testing::InSequence sequence; EXPECT_CALL(mock_policy_callback_, OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_))); EXPECT_CALL(mock_policy_callback_, - OnPolicyUpdatePtr(IsPolicies(&token_validation_url_https_))); + OnPolicyUpdatePtr(IsPolicies(&third_party_auth_cert_empty_))); + EXPECT_CALL(mock_policy_callback_, + OnPolicyUpdatePtr(IsPolicies(&third_party_auth_full_))); SetPolicies(empty_); StartWatching(); - SetPolicies(token_validation_url_https_); -} - -TEST_F(PolicyWatcherTest, TokenValidationCertificateIssuer) { - testing::InSequence sequence; - EXPECT_CALL(mock_policy_callback_, - OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_))); - EXPECT_CALL(mock_policy_callback_, - OnPolicyUpdatePtr(IsPolicies(&token_certificate_blah_))); - - SetPolicies(empty_); - StartWatching(); - SetPolicies(token_certificate_blah_); + SetPolicies(third_party_auth_partial_); + SetPolicies(third_party_auth_full_); } TEST_F(PolicyWatcherTest, UdpPortRange) { @@ -587,13 +645,13 @@ #if defined(OS_WIN) // RemoteAccessHostMatchUsername is marked in policy_templates.json as not // supported on Windows and therefore is (by design) excluded from the schema. - expected_schema.erase(policy::key::kRemoteAccessHostMatchUsername); + expected_schema.erase(key::kRemoteAccessHostMatchUsername); #endif #if defined(NDEBUG) // Policy schema / policy_templates.json cannot differ between debug and // release builds so we compensate below to account for the fact that // PolicyWatcher::default_values_ does differ between debug and release. - expected_schema[policy::key::kRemoteAccessHostDebugOverridePolicies] = + expected_schema[key::kRemoteAccessHostDebugOverridePolicies] = base::Value::TYPE_STRING; #endif
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc index 8cf6cce..c426a65 100644 --- a/remoting/host/remoting_me2me_host.cc +++ b/remoting/host/remoting_me2me_host.cc
@@ -64,6 +64,7 @@ #include "remoting/host/shutdown_watchdog.h" #include "remoting/host/signaling_connector.h" #include "remoting/host/single_window_desktop_environment.h" +#include "remoting/host/third_party_auth_config.h" #include "remoting/host/token_validator_factory_impl.h" #include "remoting/host/usage_stats_consent.h" #include "remoting/host/username.h" @@ -71,6 +72,7 @@ #include "remoting/protocol/me2me_host_authenticator_factory.h" #include "remoting/protocol/network_settings.h" #include "remoting/protocol/pairing_registry.h" +#include "remoting/protocol/port_range.h" #include "remoting/protocol/token_validator.h" #include "remoting/signaling/xmpp_signal_strategy.h" @@ -339,8 +341,7 @@ bool host_username_match_required_; bool allow_nat_traversal_; bool allow_relay_; - uint16 min_udp_port_; - uint16 max_udp_port_; + PortRange udp_port_range_; std::string talkgadget_prefix_; bool allow_pairing_; @@ -394,8 +395,6 @@ host_username_match_required_(false), allow_nat_traversal_(true), allow_relay_(true), - min_udp_port_(0), - max_udp_port_(0), allow_pairing_(true), curtain_required_(false), enable_gnubby_auth_(false), @@ -672,7 +671,7 @@ scoped_ptr<protocol::AuthenticatorFactory> factory; - if (third_party_auth_config_.is_empty()) { + if (third_party_auth_config_.is_null()) { scoped_refptr<PairingRegistry> pairing_registry; if (allow_pairing_) { // On Windows |pairing_registry_| is initialized in @@ -696,7 +695,10 @@ host_secret_hash_, pairing_registry); host_->set_pairing_registry(pairing_registry); - } else if (third_party_auth_config_.is_valid()) { + } else { + DCHECK(third_party_auth_config_.token_url.is_valid()); + DCHECK(third_party_auth_config_.token_validation_url.is_valid()); + scoped_ptr<protocol::TokenValidatorFactory> token_validator_factory( new TokenValidatorFactoryImpl( third_party_auth_config_, @@ -704,17 +706,6 @@ factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth( use_service_account_, host_owner_, local_certificate, key_pair_, token_validator_factory.Pass()); - - } else { - // TODO(rmsousa): If the policy is bad the host should not go online. It - // should keep running, but not connected, until the policies are fixed. - // Having it show up as online and then reject all clients is misleading. - LOG(ERROR) << "One of the third-party token URLs is empty or invalid. " - << "Host will reject all clients until policies are corrected. " - << "TokenUrl: " << third_party_auth_config_.token_url << ", " - << "TokenValidationUrl: " - << third_party_auth_config_.token_validation_url; - factory = protocol::Me2MeHostAuthenticatorFactory::CreateRejecting(); } #if defined(OS_POSIX) @@ -947,29 +938,13 @@ return false; } - // Use an XMPP connection to the Talk network for session signalling. + // Use an XMPP connection to the Talk network for session signaling. if (!config.GetString(kXmppLoginConfigPath, &xmpp_server_config_.username) || - !(config.GetString(kXmppAuthTokenConfigPath, - &xmpp_server_config_.auth_token) || - config.GetString(kOAuthRefreshTokenConfigPath, - &oauth_refresh_token_))) { + !config.GetString(kOAuthRefreshTokenConfigPath, &oauth_refresh_token_)) { LOG(ERROR) << "XMPP credentials are not defined in the config."; return false; } - if (!oauth_refresh_token_.empty()) { - // SignalingConnector (inside HostSignalingManager) is responsible for - // getting OAuth token. - xmpp_server_config_.auth_token = ""; - xmpp_server_config_.auth_service = "oauth2"; - } else if (!config.GetString(kXmppAuthServiceConfigPath, - &xmpp_server_config_.auth_service)) { - // For the me2me host, we default to ClientLogin token for chromiumsync - // because earlier versions of the host had no HTTP stack with which to - // request an OAuth2 access token. - xmpp_server_config_.auth_service = kChromotingTokenDefaultServiceName; - } - if (config.GetString(kHostOwnerConfigPath, &host_owner_)) { // Service account configs have a host_owner, different from the xmpp_login. use_service_account_ = true; @@ -1205,34 +1180,15 @@ // Returns true if the host has to be restarted after this policy update. DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); - std::string udp_port_range; + std::string string_value; if (!policies->GetString(policy::key::kRemoteAccessHostUdpPortRange, - &udp_port_range)) { + &string_value)) { return false; } - // Use default values if policy setting is empty or invalid. - uint16 min_udp_port = 0; - uint16 max_udp_port = 0; - if (!udp_port_range.empty() && - !NetworkSettings::ParsePortRange(udp_port_range, &min_udp_port, - &max_udp_port)) { - LOG(WARNING) << "Invalid port range policy: \"" << udp_port_range - << "\". Using default values."; - } - - if (min_udp_port_ != min_udp_port || max_udp_port_ != max_udp_port) { - if (min_udp_port != 0 && max_udp_port != 0) { - HOST_LOG << "Policy restricts UDP port range to [" << min_udp_port - << ", " << max_udp_port << "]"; - } else { - HOST_LOG << "Policy does not restrict UDP port range."; - } - min_udp_port_ = min_udp_port; - max_udp_port_ = max_udp_port; - return true; - } - return false; + DCHECK(PortRange::Parse(string_value, &udp_port_range_)); + HOST_LOG << "Policy restricts UDP port range to: " << udp_port_range_; + return true; } bool HostProcess::OnCurtainPolicyUpdate(base::DictionaryValue* policies) { @@ -1290,39 +1246,18 @@ } bool HostProcess::OnHostTokenUrlPolicyUpdate(base::DictionaryValue* policies) { - // Returns true if the host has to be restarted after this policy update. - DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); - - bool token_policy_changed = false; - std::string token_url_string; - if (policies->GetString(policy::key::kRemoteAccessHostTokenUrl, - &token_url_string)) { - token_policy_changed = true; - third_party_auth_config_.token_url = GURL(token_url_string); + switch (ThirdPartyAuthConfig::Parse(*policies, &third_party_auth_config_)) { + case ThirdPartyAuthConfig::NoPolicy: + return false; + case ThirdPartyAuthConfig::ParsingSuccess: + HOST_LOG << "Policy sets third-party token URLs: " + << third_party_auth_config_; + return true; + case ThirdPartyAuthConfig::InvalidPolicy: + default: + NOTREACHED(); + return false; } - std::string token_validation_url_string; - if (policies->GetString(policy::key::kRemoteAccessHostTokenValidationUrl, - &token_validation_url_string)) { - token_policy_changed = true; - third_party_auth_config_.token_validation_url = - GURL(token_validation_url_string); - } - if (policies->GetString( - policy::key::kRemoteAccessHostTokenValidationCertificateIssuer, - &third_party_auth_config_.token_validation_cert_issuer)) { - token_policy_changed = true; - } - - if (token_policy_changed) { - HOST_LOG << "Policy sets third-party token URLs: " - << "TokenUrl: " - << third_party_auth_config_.token_url << ", " - << "TokenValidationUrl: " - << third_party_auth_config_.token_validation_url << ", " - << "TokenValidationCertificateIssuer: " - << third_party_auth_config_.token_validation_cert_issuer; - } - return token_policy_changed; } bool HostProcess::OnPairingPolicyUpdate(base::DictionaryValue* policies) { @@ -1408,15 +1343,14 @@ NetworkSettings network_settings(network_flags); - if (min_udp_port_ && max_udp_port_) { - network_settings.min_port = min_udp_port_; - network_settings.max_port = max_udp_port_; + if (!udp_port_range_.is_null()) { + network_settings.port_range = udp_port_range_; } else if (!allow_nat_traversal_) { // For legacy reasons we have to restrict the port range to a set of default // values when nat traversal is disabled, even if the port range was not // set in policy. - network_settings.min_port = NetworkSettings::kDefaultMinPort; - network_settings.max_port = NetworkSettings::kDefaultMaxPort; + network_settings.port_range.min_port = NetworkSettings::kDefaultMinPort; + network_settings.port_range.max_port = NetworkSettings::kDefaultMaxPort; } host_.reset(new ChromotingHost(
diff --git a/remoting/host/setup/BUILD.gn b/remoting/host/setup/BUILD.gn new file mode 100644 index 0000000..5fa8a36 --- /dev/null +++ b/remoting/host/setup/BUILD.gn
@@ -0,0 +1,32 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//remoting/remoting_srcs.gni") + +source_set("setup") { + sources = + rebase_path(remoting_host_srcs_gypi_values.remoting_host_setup_sources, + ".", + "//remoting") + + configs += [ + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + "//build/config/compiler:no_size_t_to_int_warning", + "//build/config/compiler:wexit_time_destructors", + "//remoting:version", + ] + + deps = [ + "//base", + "//google_apis", + "//remoting/host", + ] + + if (is_win) { + deps += [ + "//google_update", + "//remoting/host:remoting_lib_idl", + ] + } +}
diff --git a/remoting/host/signaling_connector.cc b/remoting/host/signaling_connector.cc index adc1571..7359e154 100644 --- a/remoting/host/signaling_connector.cc +++ b/remoting/host/signaling_connector.cc
@@ -26,10 +26,12 @@ SignalingConnector::SignalingConnector( XmppSignalStrategy* signal_strategy, scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker, + scoped_ptr<OAuthTokenGetter> oauth_token_getter, const base::Closure& auth_failed_callback) : signal_strategy_(signal_strategy), auth_failed_callback_(auth_failed_callback), dns_blackhole_checker_(dns_blackhole_checker.Pass()), + oauth_token_getter_(oauth_token_getter.Pass()), reconnect_attempts_(0) { DCHECK(!auth_failed_callback_.is_null()); DCHECK(dns_blackhole_checker_.get()); @@ -45,11 +47,6 @@ net::NetworkChangeNotifier::RemoveIPAddressObserver(this); } -void SignalingConnector::EnableOAuth( - scoped_ptr<OAuthTokenGetter> oauth_token_getter) { - oauth_token_getter_ = oauth_token_getter.Pass(); -} - void SignalingConnector::OnSignalStrategyStateChange( SignalStrategy::State state) { DCHECK(CalledOnValidThread()); @@ -110,7 +107,7 @@ DCHECK_EQ(status, OAuthTokenGetter::SUCCESS); HOST_LOG << "Received user info."; - signal_strategy_->SetAuthInfo(user_email, access_token, "oauth2"); + signal_strategy_->SetAuthInfo(user_email, access_token); // Now that we've refreshed the token and verified that it's for the correct // user account, try to connect using the new token.
diff --git a/remoting/host/signaling_connector.h b/remoting/host/signaling_connector.h index acb6921..8a59e903 100644 --- a/remoting/host/signaling_connector.h +++ b/remoting/host/signaling_connector.h
@@ -34,13 +34,10 @@ SignalingConnector( XmppSignalStrategy* signal_strategy, scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker, + scoped_ptr<OAuthTokenGetter> oauth_token_getter, const base::Closure& auth_failed_callback); ~SignalingConnector() override; - // May be called immediately after the constructor to enable OAuth - // access token updating. - void EnableOAuth(scoped_ptr<OAuthTokenGetter> oauth_token_getter); - // OAuthTokenGetter callback. void OnAccessToken(OAuthTokenGetter::Status status, const std::string& user_email,
diff --git a/remoting/host/third_party_auth_config.cc b/remoting/host/third_party_auth_config.cc new file mode 100644 index 0000000..5ed63a86 --- /dev/null +++ b/remoting/host/third_party_auth_config.cc
@@ -0,0 +1,138 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "remoting/host/third_party_auth_config.h" + +#include "base/logging.h" +#include "base/values.h" +#include "policy/policy_constants.h" + +namespace remoting { + +namespace { + +bool ParseUrlPolicy(const std::string& str, GURL* out) { + if (str.empty()) { + *out = GURL(); + return true; + } + + GURL gurl(str); + if (!gurl.is_valid()) { + LOG(ERROR) << "Not a valid URL: " << str; + return false; + } +// We validate https-vs-http only on Release builds to help with manual testing. +#if defined(NDEBUG) + if (!gurl.SchemeIsSecure()) { + LOG(ERROR) << "Not a secure URL: " << str; + return false; + } +#endif + + *out = gurl; + return true; +} + +} // namespace + +bool ThirdPartyAuthConfig::ParseStrings( + const std::string& token_url, + const std::string& token_validation_url, + const std::string& token_validation_cert_issuer, + ThirdPartyAuthConfig* result) { + ThirdPartyAuthConfig tmp; + + // Extract raw values for the 3 individual fields. + bool urls_valid = true; + urls_valid &= ParseUrlPolicy(token_url, &tmp.token_url); + urls_valid &= ParseUrlPolicy(token_validation_url, &tmp.token_validation_url); + if (!urls_valid) { + return false; + } + tmp.token_validation_cert_issuer = token_validation_cert_issuer; + + // Validate inter-dependencies between the 3 fields. + if (tmp.token_url.is_empty() ^ tmp.token_validation_url.is_empty()) { + LOG(ERROR) << "TokenUrl and TokenValidationUrl " + << "have to be specified together."; + return false; + } + if (!tmp.token_validation_cert_issuer.empty() && tmp.token_url.is_empty()) { + LOG(ERROR) << "TokenValidationCertificateIssuer cannot be used " + << "without TokenUrl and TokenValidationUrl."; + return false; + } + + *result = tmp; + return true; +} + +namespace { + +void ExtractHelper(const base::DictionaryValue& policy_dict, + const std::string& policy_name, + bool* policy_present, + std::string* policy_value) { + if (policy_dict.GetString(policy_name, policy_value)) { + *policy_present = true; + } else { + policy_value->clear(); + } +} + +} // namespace + +bool ThirdPartyAuthConfig::ExtractStrings( + const base::DictionaryValue& policy_dict, + std::string* token_url, + std::string* token_validation_url, + std::string* token_validation_cert_issuer) { + bool policies_present = false; + ExtractHelper(policy_dict, policy::key::kRemoteAccessHostTokenUrl, + &policies_present, token_url); + ExtractHelper(policy_dict, policy::key::kRemoteAccessHostTokenValidationUrl, + &policies_present, token_validation_url); + ExtractHelper(policy_dict, + policy::key::kRemoteAccessHostTokenValidationCertificateIssuer, + &policies_present, token_validation_cert_issuer); + return policies_present; +} + +ThirdPartyAuthConfig::ParseStatus ThirdPartyAuthConfig::Parse( + const base::DictionaryValue& policy_dict, + ThirdPartyAuthConfig* result) { + // Extract 3 individial policy values. + std::string token_url; + std::string token_validation_url; + std::string token_validation_cert_issuer; + if (!ThirdPartyAuthConfig::ExtractStrings(policy_dict, &token_url, + &token_validation_url, + &token_validation_cert_issuer)) { + return NoPolicy; + } + + // Parse the policy value. + if (!ThirdPartyAuthConfig::ParseStrings(token_url, token_validation_url, + token_validation_cert_issuer, + result)) { + return InvalidPolicy; + } + + return ParsingSuccess; +} + +std::ostream& operator<<(std::ostream& os, const ThirdPartyAuthConfig& cfg) { + if (cfg.is_null()) { + os << "<no 3rd party auth config specified>"; + } else { + os << "TokenUrl = <" << cfg.token_url << ">, "; + os << "TokenValidationUrl = <" << cfg.token_validation_url << ">, "; + os << "TokenValidationCertificateIssuer = <" + << cfg.token_validation_cert_issuer << ">"; + } + return os; +} + +} // namespace remoting
diff --git a/remoting/host/third_party_auth_config.h b/remoting/host/third_party_auth_config.h new file mode 100644 index 0000000..b9e9c92 --- /dev/null +++ b/remoting/host/third_party_auth_config.h
@@ -0,0 +1,76 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REMOTING_HOST_THIRD_PARTY_AUTH_CONFIG_H_ +#define REMOTING_HOST_THIRD_PARTY_AUTH_CONFIG_H_ + +#include <ostream> +#include <string> + +#include "base/gtest_prod_util.h" +#include "url/gurl.h" + +namespace base { +class DictionaryValue; +} // namespace base + +namespace remoting { + +struct ThirdPartyAuthConfig { + GURL token_url; + GURL token_validation_url; + std::string token_validation_cert_issuer; + + inline bool is_null() const { + return token_url.is_empty() && token_validation_url.is_empty(); + } + + // Status of Parse method call. + enum ParseStatus { + // |policy_dict| contains invalid entries (i.e. malformed urls). + // |result| has not been modified. + InvalidPolicy, + + // |policy_dict| doesn't contain any ThirdPartyAuthConfig-related entries. + // |result| has not been modified. + NoPolicy, + + // |policy_dict| contains valid entries that have been stored into |result|. + ParsingSuccess, + }; + static ParseStatus Parse(const base::DictionaryValue& policy_dict, + ThirdPartyAuthConfig* result); + + private: + // Returns false and doesn't modify |result| if parsing fails (i.e. some input + // values are invalid). + static bool ParseStrings(const std::string& token_url, + const std::string& token_validation_url, + const std::string& token_validation_cert_issuer, + ThirdPartyAuthConfig* result); + FRIEND_TEST_ALL_PREFIXES(InvalidUrlTest, ParseInvalidUrl); + FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ParseEmpty); + FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ParseValidAll); + FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ParseValidNoCert); + FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ParseInvalidCombination); + FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ParseHttp); + + // Extracts raw (raw = as strings) policy values from |policy_dict|. + // Missing policy values are set to an empty string. + // Returns false if no ThirdPartyAuthConfig-related policies were present. + static bool ExtractStrings(const base::DictionaryValue& policy_dict, + std::string* token_url, + std::string* token_validation_url, + std::string* token_validation_cert_issuer); + FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ExtractEmpty); + FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ExtractUnknown); + FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ExtractAll); + FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ExtractPartial); +}; + +std::ostream& operator<<(std::ostream& os, const ThirdPartyAuthConfig& cfg); + +} // namespace remoting + +#endif // REMOTING_HOST_THIRD_PARTY_AUTH_CONFIG_H_
diff --git a/remoting/host/third_party_auth_config_unittest.cc b/remoting/host/third_party_auth_config_unittest.cc new file mode 100644 index 0000000..002fd81 --- /dev/null +++ b/remoting/host/third_party_auth_config_unittest.cc
@@ -0,0 +1,194 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "remoting/host/third_party_auth_config.h" + +#include <sstream> + +#include "base/values.h" +#include "policy/policy_constants.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace remoting { + +namespace key = ::policy::key; + +TEST(ThirdPartyAuthConfig, ParseEmpty) { + ThirdPartyAuthConfig third_party_auth_config; + + EXPECT_TRUE( + ThirdPartyAuthConfig::ParseStrings("", "", "", &third_party_auth_config)); + EXPECT_TRUE(third_party_auth_config.is_null()); +} + +TEST(ThirdPartyAuthConfig, ParseValidAll) { + ThirdPartyAuthConfig third_party_auth_config; + + EXPECT_TRUE(ThirdPartyAuthConfig::ParseStrings( + "https://token.com/", "https://validation.com/", "certificate subject", + &third_party_auth_config)); + EXPECT_FALSE(third_party_auth_config.is_null()); + EXPECT_EQ("https://token.com/", third_party_auth_config.token_url.spec()); + EXPECT_EQ("https://validation.com/", + third_party_auth_config.token_validation_url.spec()); + EXPECT_EQ("certificate subject", + third_party_auth_config.token_validation_cert_issuer); +} + +TEST(ThirdPartyAuthConfig, ParseValidNoCert) { + ThirdPartyAuthConfig third_party_auth_config; + + EXPECT_TRUE(ThirdPartyAuthConfig::ParseStrings("https://token.com/", + "https://validation.com/", "", + &third_party_auth_config)); + EXPECT_FALSE(third_party_auth_config.is_null()); + EXPECT_EQ("https://token.com/", third_party_auth_config.token_url.spec()); + EXPECT_EQ("https://validation.com/", + third_party_auth_config.token_validation_url.spec()); + EXPECT_EQ("", third_party_auth_config.token_validation_cert_issuer); +} + +// We validate https-vs-http only on Release builds to help with manual testing. +#if !defined(NDEBUG) +TEST(ThirdPartyAuthConfig, ParseHttp) { + ThirdPartyAuthConfig third_party_auth_config; + + EXPECT_TRUE(ThirdPartyAuthConfig::ParseStrings("http://token.com/", + "http://validation.com/", "", + &third_party_auth_config)); + EXPECT_FALSE(third_party_auth_config.is_null()); + EXPECT_EQ("http://token.com/", third_party_auth_config.token_url.spec()); + EXPECT_EQ("http://validation.com/", + third_party_auth_config.token_validation_url.spec()); +} +#endif + +namespace { + +const std::string valid_url("https://valid.com"); +const std::string valid_cert("certificate subject"); + +} // namespace + +class InvalidUrlTest : public ::testing::TestWithParam<const char*> {}; + +TEST_P(InvalidUrlTest, ParseInvalidUrl) { + const std::string& invalid_url(GetParam()); + + // Populate |config| with some known data - we will use this for validating + // that |config| doesn't get modified by ParseStrings during subsequent + // parsing + // failure tests. + ThirdPartyAuthConfig config; + EXPECT_TRUE(ThirdPartyAuthConfig::ParseStrings( + "https://token.com/", "https://validation.com/", "certificate subject", + &config)); + + // Test for parsing failure. + EXPECT_FALSE(ThirdPartyAuthConfig::ParseStrings(invalid_url, valid_url, + valid_cert, &config)); + EXPECT_FALSE(ThirdPartyAuthConfig::ParseStrings(valid_url, invalid_url, + valid_cert, &config)); + EXPECT_FALSE( + ThirdPartyAuthConfig::ParseStrings(invalid_url, "", "", &config)); + EXPECT_FALSE( + ThirdPartyAuthConfig::ParseStrings("", invalid_url, "", &config)); + + // Validate that ParseStrings doesn't modify its output upon parsing failure. + EXPECT_EQ("https://token.com/", config.token_url.spec()); + EXPECT_EQ("https://validation.com/", config.token_validation_url.spec()); + EXPECT_EQ("certificate subject", config.token_validation_cert_issuer); +} + +// We validate https-vs-http only on Release builds to help with manual testing. +#if defined(NDEBUG) +INSTANTIATE_TEST_CASE_P(ThirdPartyAuthConfig, + InvalidUrlTest, + ::testing::Values("http://insecure.com", + "I am not a URL")); +#else +INSTANTIATE_TEST_CASE_P(ThirdPartyAuthConfig, + InvalidUrlTest, + ::testing::Values("I am not a URL")); +#endif + +TEST(ThirdPartyAuthConfig, ParseInvalidCombination) { + // Populate |config| with some known data - we will use this for validating + // that |config| doesn't get modified by ParseStrings during subsequent + // parsing + // failure tests. + ThirdPartyAuthConfig config; + EXPECT_TRUE(ThirdPartyAuthConfig::ParseStrings( + "https://token.com/", "https://validation.com/", "certificate subject", + &config)); + + // Only one of TokenUrl and TokenValidationUrl + EXPECT_FALSE( + ThirdPartyAuthConfig::ParseStrings("", valid_url, valid_cert, &config)); + EXPECT_FALSE( + ThirdPartyAuthConfig::ParseStrings(valid_url, "", valid_cert, &config)); + + // CertSubject when no TokenUrl and TokenValidationUrl + EXPECT_FALSE(ThirdPartyAuthConfig::ParseStrings("", "", valid_cert, &config)); + + // Validate that ParseStrings doesn't modify its output upon parsing failure. + EXPECT_EQ("https://token.com/", config.token_url.spec()); + EXPECT_EQ("https://validation.com/", config.token_validation_url.spec()); + EXPECT_EQ("certificate subject", config.token_validation_cert_issuer); +} + +TEST(ThirdPartyAuthConfig, ExtractEmpty) { + base::DictionaryValue dict; + std::string url1, url2, cert; + EXPECT_FALSE(ThirdPartyAuthConfig::ExtractStrings(dict, &url1, &url2, &cert)); +} + +TEST(ThirdPartyAuthConfig, ExtractUnknown) { + base::DictionaryValue dict; + dict.SetString("unknownName", "someValue"); + + std::string url1, url2, cert; + EXPECT_FALSE(ThirdPartyAuthConfig::ExtractStrings(dict, &url1, &url2, &cert)); +} + +TEST(ThirdPartyAuthConfig, ExtractAll) { + base::DictionaryValue dict; + dict.SetString(key::kRemoteAccessHostTokenUrl, "test1"); + dict.SetString(key::kRemoteAccessHostTokenValidationUrl, "test2"); + dict.SetString(key::kRemoteAccessHostTokenValidationCertificateIssuer, "t3"); + + std::string url1, url2, cert; + EXPECT_TRUE(ThirdPartyAuthConfig::ExtractStrings(dict, &url1, &url2, &cert)); + EXPECT_EQ("test1", url1); + EXPECT_EQ("test2", url2); + EXPECT_EQ("t3", cert); +} + +TEST(ThirdPartyAuthConfig, ExtractPartial) { + base::DictionaryValue dict; + dict.SetString(key::kRemoteAccessHostTokenValidationUrl, "test2"); + + std::string url1, url2, cert; + EXPECT_TRUE(ThirdPartyAuthConfig::ExtractStrings(dict, &url1, &url2, &cert)); + EXPECT_EQ("", url1); + EXPECT_EQ("test2", url2); + EXPECT_EQ("", cert); +} + +TEST(ThirdPartyAuthConfig, Output) { + ThirdPartyAuthConfig third_party_auth_config; + third_party_auth_config.token_url = GURL("https://token.com"); + third_party_auth_config.token_validation_url = GURL("https://validation.com"); + third_party_auth_config.token_validation_cert_issuer = "certificate subject"; + + std::ostringstream str; + str << third_party_auth_config; + + EXPECT_THAT(str.str(), testing::HasSubstr("token")); + EXPECT_THAT(str.str(), testing::HasSubstr("validation")); + EXPECT_THAT(str.str(), testing::HasSubstr("certificate subject")); +} + +} // namespace remoting
diff --git a/remoting/host/token_validator_base.h b/remoting/host/token_validator_base.h index b5c7d20..c59d15d 100644 --- a/remoting/host/token_validator_base.h +++ b/remoting/host/token_validator_base.h
@@ -9,6 +9,7 @@ #include "base/memory/weak_ptr.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_context_getter.h" +#include "remoting/host/third_party_auth_config.h" #include "remoting/protocol/token_validator.h" #include "url/gurl.h" @@ -19,20 +20,6 @@ namespace remoting { -struct ThirdPartyAuthConfig { - inline bool is_empty() const { - return token_url.is_empty() && token_validation_url.is_empty(); - } - - inline bool is_valid() const { - return token_url.is_valid() && token_validation_url.is_valid(); - } - - GURL token_url; - GURL token_validation_url; - std::string token_validation_cert_issuer; -}; - class TokenValidatorBase : public net::URLRequest::Delegate, public protocol::TokenValidator {
diff --git a/remoting/host/win/get_clsids.py b/remoting/host/win/get_clsids.py new file mode 100644 index 0000000..e4899d3 --- /dev/null +++ b/remoting/host/win/get_clsids.py
@@ -0,0 +1,29 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Each CLSID is a hash of the current version string salted with an +# arbitrary GUID. This ensures that the newly installed COM classes will +# be used during/after upgrade even if there are old instances running +# already. +# The IDs are not random to avoid rebuilding host when it's not +# necessary. + +import uuid +import sys + +if len(sys.argv) != 4: + print """Expecting 3 args: +<daemon_controller_guid> <rdp_desktop_session_guid> <version>""" + sys.exit(1) + +daemon_controller_guid = sys.argv[1] +rdp_desktop_session_guid = sys.argv[2] +version_full = sys.argv[3] + +# Output a GN list of 2 strings. +print '["' + \ + str(uuid.uuid5(uuid.UUID(daemon_controller_guid), version_full)) + '", ' +print '"' + \ + str(uuid.uuid5(uuid.UUID(rdp_desktop_session_guid), version_full)) + '"]' +
diff --git a/remoting/protocol/BUILD.gn b/remoting/protocol/BUILD.gn index 34b38af02..b7bf4bf 100644 --- a/remoting/protocol/BUILD.gn +++ b/remoting/protocol/BUILD.gn
@@ -2,14 +2,12 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -static_library("protocol") { - gypi_values = exec_script("//build/gypi_to_gn.py", - [ rebase_path("../remoting_srcs.gypi") ], - "scope", - [ "../remoting_srcs.gypi" ]) +import("//remoting/remoting_srcs.gni") - sources = - rebase_path(gypi_values.remoting_protocol_sources, ".", "//remoting") +source_set("protocol") { + sources = rebase_path(remoting_srcs_gypi_values.remoting_protocol_sources, + ".", + "//remoting") configs += [ "//build/config/compiler:no_size_t_to_int_warning", @@ -17,6 +15,7 @@ ] public_deps = [ + "//remoting/proto", "//third_party/libjingle", ] deps = [ @@ -26,5 +25,66 @@ "//jingle:notifier", "//net", "//remoting/base", + "//remoting/codec", + ] +} + +source_set("test_support") { + testonly = true + + sources = [ + "fake_authenticator.cc", + "fake_authenticator.h", + "fake_datagram_socket.cc", + "fake_datagram_socket.h", + "fake_session.cc", + "fake_session.h", + "fake_stream_socket.cc", + "fake_stream_socket.h", + "protocol_mock_objects.cc", + "protocol_mock_objects.h", + ] + + public_deps = [ + ":protocol", + "//testing/gmock", + ] +} + +source_set("unit_tests") { + testonly = true + + sources = [ + "authenticator_test_base.cc", + "authenticator_test_base.h", + "channel_multiplexer_unittest.cc", + "chromium_socket_factory_unittest.cc", + "client_video_dispatcher_unittest.cc", + "clipboard_echo_filter_unittest.cc", + "clipboard_filter_unittest.cc", + "connection_tester.cc", + "connection_tester.h", + "connection_to_client_unittest.cc", + "content_description_unittest.cc", + "input_event_tracker_unittest.cc", + "input_filter_unittest.cc", + "jingle_messages_unittest.cc", + "jingle_session_unittest.cc", + "message_decoder_unittest.cc", + "message_reader_unittest.cc", + "monitored_video_stub_unittest.cc", + "mouse_input_filter_unittest.cc", + "negotiating_authenticator_unittest.cc", + "pairing_registry_unittest.cc", + "ppapi_module_stub.cc", + "ssl_hmac_channel_authenticator_unittest.cc", + "third_party_authenticator_unittest.cc", + "v2_authenticator_unittest.cc", + ] + + deps = [ + ":test_support", + "//testing/gmock", + "//testing/gtest", ] }
diff --git a/remoting/protocol/chromium_port_allocator.cc b/remoting/protocol/chromium_port_allocator.cc index 013be85..fb8a3e0 100644 --- a/remoting/protocol/chromium_port_allocator.cc +++ b/remoting/protocol/chromium_port_allocator.cc
@@ -156,8 +156,8 @@ flags |= cricket::PORTALLOCATOR_DISABLE_RELAY; result->set_flags(flags); - result->SetPortRange(network_settings.min_port, - network_settings.max_port); + result->SetPortRange(network_settings.port_range.min_port, + network_settings.port_range.max_port); return result.Pass(); }
diff --git a/remoting/protocol/me2me_host_authenticator_factory.cc b/remoting/protocol/me2me_host_authenticator_factory.cc index 422a2bb..bdf2bee5 100644 --- a/remoting/protocol/me2me_host_authenticator_factory.cc +++ b/remoting/protocol/me2me_host_authenticator_factory.cc
@@ -97,12 +97,6 @@ return result.Pass(); } -// static -scoped_ptr<AuthenticatorFactory> - Me2MeHostAuthenticatorFactory::CreateRejecting() { - return make_scoped_ptr(new Me2MeHostAuthenticatorFactory()); -} - Me2MeHostAuthenticatorFactory::Me2MeHostAuthenticatorFactory() { }
diff --git a/remoting/protocol/me2me_host_authenticator_factory.h b/remoting/protocol/me2me_host_authenticator_factory.h index d97b474..13b8346 100644 --- a/remoting/protocol/me2me_host_authenticator_factory.h +++ b/remoting/protocol/me2me_host_authenticator_factory.h
@@ -43,10 +43,6 @@ scoped_refptr<RsaKeyPair> key_pair, scoped_ptr<TokenValidatorFactory> token_validator_factory); - // Create a factory that dispenses rejecting authenticators (used when the - // host config/policy is inconsistent) - static scoped_ptr<AuthenticatorFactory> CreateRejecting(); - Me2MeHostAuthenticatorFactory(); ~Me2MeHostAuthenticatorFactory() override;
diff --git a/remoting/protocol/network_settings.cc b/remoting/protocol/network_settings.cc deleted file mode 100644 index 65068ef..0000000 --- a/remoting/protocol/network_settings.cc +++ /dev/null
@@ -1,47 +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 "remoting/protocol/network_settings.h" - -#include <limits.h> -#include <stdlib.h> - -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" - -namespace remoting { -namespace protocol { - -// static - bool NetworkSettings::ParsePortRange(const std::string& port_range, - uint16* out_min_port, - uint16* out_max_port) { - size_t separator_index = port_range.find('-'); - if (separator_index == std::string::npos) - return false; - - std::string min_port_string, max_port_string; - base::TrimWhitespaceASCII(port_range.substr(0, separator_index), - base::TRIM_ALL, - &min_port_string); - base::TrimWhitespaceASCII(port_range.substr(separator_index + 1), - base::TRIM_ALL, - &max_port_string); - - unsigned min_port, max_port; - if (!base::StringToUint(min_port_string, &min_port) || - !base::StringToUint(max_port_string, &max_port)) { - return false; - } - - if (min_port == 0 || min_port > max_port || max_port > USHRT_MAX) - return false; - - *out_min_port = static_cast<uint16>(min_port); - *out_max_port = static_cast<uint16>(max_port); - return true; -} - -} // namespace protocol -} // namespace remoting
diff --git a/remoting/protocol/network_settings.h b/remoting/protocol/network_settings.h index f64958a..83d7507 100644 --- a/remoting/protocol/network_settings.h +++ b/remoting/protocol/network_settings.h
@@ -9,6 +9,7 @@ #include "base/basictypes.h" #include "base/logging.h" +#include "remoting/protocol/port_range.h" namespace remoting { namespace protocol { @@ -42,32 +43,17 @@ NAT_TRAVERSAL_OUTGOING }; - NetworkSettings() - : flags(NAT_TRAVERSAL_DISABLED), - min_port(0), - max_port(0) { + NetworkSettings() : flags(NAT_TRAVERSAL_DISABLED) { DCHECK(!(flags & (NAT_TRAVERSAL_STUN | NAT_TRAVERSAL_RELAY)) || (flags & NAT_TRAVERSAL_OUTGOING)); } - explicit NetworkSettings(uint32 flags) - : flags(flags), - min_port(0), - max_port(0) { - } - - // Parse string in the form "<min_port>-<max_port>". E.g. "12400-12409". - // Returns true if string was parsed successfuly. - static bool ParsePortRange(const std::string& port_range, - uint16* out_min_port, - uint16* out_max_port); + explicit NetworkSettings(uint32 flags) : flags(flags) {} uint32 flags; - // |min_port| and |max_port| specify range (inclusive) of ports used by - // P2P sessions. Any port can be used when both values are set to 0. - uint16 min_port; - uint16 max_port; + // Range of ports used by P2P sessions. + PortRange port_range; }; } // namespace protocol
diff --git a/remoting/protocol/network_settings_unittest.cc b/remoting/protocol/network_settings_unittest.cc deleted file mode 100644 index 398d5593..0000000 --- a/remoting/protocol/network_settings_unittest.cc +++ /dev/null
@@ -1,44 +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 "remoting/protocol/network_settings.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace remoting { -namespace protocol { - -TEST(ParsePortRange, Basic) { - uint16 min, max; - - // Valid range - EXPECT_TRUE(NetworkSettings::ParsePortRange("1-65535", &min, &max)); - EXPECT_EQ(1u, min); - EXPECT_EQ(65535u, max); - - EXPECT_TRUE(NetworkSettings::ParsePortRange(" 1 - 65535 ", &min, &max)); - EXPECT_EQ(1u, min); - EXPECT_EQ(65535u, max); - - EXPECT_TRUE(NetworkSettings::ParsePortRange("12400-12400", &min, &max)); - EXPECT_EQ(12400u, min); - EXPECT_EQ(12400u, max); - - // Invalid - EXPECT_FALSE(NetworkSettings::ParsePortRange("", &min, &max)); - EXPECT_FALSE(NetworkSettings::ParsePortRange("-65535", &min, &max)); - EXPECT_FALSE(NetworkSettings::ParsePortRange("1-", &min, &max)); - EXPECT_FALSE(NetworkSettings::ParsePortRange("-", &min, &max)); - EXPECT_FALSE(NetworkSettings::ParsePortRange("-1-65535", &min, &max)); - EXPECT_FALSE(NetworkSettings::ParsePortRange("1--65535", &min, &max)); - EXPECT_FALSE(NetworkSettings::ParsePortRange("1-65535-", &min, &max)); - EXPECT_FALSE(NetworkSettings::ParsePortRange("0-65535", &min, &max)); - EXPECT_FALSE(NetworkSettings::ParsePortRange("1-65536", &min, &max)); - EXPECT_FALSE(NetworkSettings::ParsePortRange("1-4294967295", &min, &max)); - EXPECT_FALSE(NetworkSettings::ParsePortRange("10-1", &min, &max)); - EXPECT_FALSE(NetworkSettings::ParsePortRange("1foo-2bar", &min, &max)); -} - -} // namespace protocol -} // namespace remoting
diff --git a/remoting/protocol/port_range.cc b/remoting/protocol/port_range.cc new file mode 100644 index 0000000..ca640899 --- /dev/null +++ b/remoting/protocol/port_range.cc
@@ -0,0 +1,57 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "remoting/protocol/port_range.h" + +#include <limits.h> +#include <stdlib.h> + +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" + +namespace remoting { + +bool PortRange::Parse(const std::string& port_range, PortRange* result) { + DCHECK(result); + + if (port_range.empty()) { + result->min_port = 0; + result->max_port = 0; + return true; + } + + size_t separator_index = port_range.find('-'); + if (separator_index == std::string::npos) + return false; + + std::string min_port_string, max_port_string; + base::TrimWhitespaceASCII(port_range.substr(0, separator_index), + base::TRIM_ALL, &min_port_string); + base::TrimWhitespaceASCII(port_range.substr(separator_index + 1), + base::TRIM_ALL, &max_port_string); + + unsigned min_port, max_port; + if (!base::StringToUint(min_port_string, &min_port) || + !base::StringToUint(max_port_string, &max_port)) { + return false; + } + + if (min_port == 0 || min_port > max_port || max_port > USHRT_MAX) + return false; + + result->min_port = static_cast<uint16>(min_port); + result->max_port = static_cast<uint16>(max_port); + return true; +} + +std::ostream& operator<<(std::ostream& os, const PortRange& port_range) { + if (port_range.is_null()) { + os << "<no port range specified>"; + } else { + os << "[" << port_range.min_port << ", " << port_range.max_port << "]"; + } + return os; +} + +} // namespace remoting
diff --git a/remoting/protocol/port_range.h b/remoting/protocol/port_range.h new file mode 100644 index 0000000..1ec5b20 --- /dev/null +++ b/remoting/protocol/port_range.h
@@ -0,0 +1,39 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REMOTING_PROTOCOL_PORT_RANGE_H_ +#define REMOTING_PROTOCOL_PORT_RANGE_H_ + +#include <ostream> +#include <string> + +#include "base/basictypes.h" + +namespace remoting { + +// Wrapper for a value of UdpPortRange policy. +struct PortRange { + // Both |min_port| and |max_port| are inclusive. + uint16 min_port; + uint16 max_port; + + // Returns true if |port_range| passed to Parse was an empty string + // (or if |this| has been initialized by the default constructor below). + inline bool is_null() const { return (min_port == 0) && (max_port == 0); } + + // Parse string in the form "<min_port>-<max_port>". E.g. "12400-12409". + // Returns true if string was parsed successfuly. + // + // Returns false and doesn't modify |result| if parsing fails (i.e. when + // |port_range| doesn't represent a valid port range). + static bool Parse(const std::string& port_range, PortRange* result); + + PortRange() : min_port(0), max_port(0) {} +}; + +std::ostream& operator<<(std::ostream& os, const PortRange& port_range); + +} // namespace remoting + +#endif // REMOTING_PROTOCOL_PORT_RANGE_H_
diff --git a/remoting/protocol/port_range_unittest.cc b/remoting/protocol/port_range_unittest.cc new file mode 100644 index 0000000..f0fc3759 --- /dev/null +++ b/remoting/protocol/port_range_unittest.cc
@@ -0,0 +1,73 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "remoting/protocol/port_range.h" + +#include <sstream> + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace remoting { + +TEST(PortRange, ParseEmpty) { + PortRange port_range; + + EXPECT_TRUE(PortRange::Parse("", &port_range)); + EXPECT_TRUE(port_range.is_null()); +} + +TEST(PortRange, ParseValid) { + PortRange port_range; + + EXPECT_TRUE(PortRange::Parse("1-65535", &port_range)); + EXPECT_FALSE(port_range.is_null()); + EXPECT_EQ(1u, port_range.min_port); + EXPECT_EQ(65535u, port_range.max_port); + + EXPECT_TRUE(PortRange::Parse(" 1 - 65535 ", &port_range)); + EXPECT_FALSE(port_range.is_null()); + EXPECT_EQ(1u, port_range.min_port); + EXPECT_EQ(65535u, port_range.max_port); + + EXPECT_TRUE(PortRange::Parse("12400-12400", &port_range)); + EXPECT_FALSE(port_range.is_null()); + EXPECT_EQ(12400u, port_range.min_port); + EXPECT_EQ(12400u, port_range.max_port); +} + +TEST(PortRange, ParseInvalid) { + PortRange port_range; + port_range.min_port = 123; + port_range.max_port = 456; + + EXPECT_FALSE(PortRange::Parse("-65535", &port_range)); + EXPECT_FALSE(PortRange::Parse("1-", &port_range)); + EXPECT_FALSE(PortRange::Parse("-", &port_range)); + EXPECT_FALSE(PortRange::Parse("-1-65535", &port_range)); + EXPECT_FALSE(PortRange::Parse("1--65535", &port_range)); + EXPECT_FALSE(PortRange::Parse("1-65535-", &port_range)); + EXPECT_FALSE(PortRange::Parse("0-65535", &port_range)); + EXPECT_FALSE(PortRange::Parse("1-65536", &port_range)); + EXPECT_FALSE(PortRange::Parse("1-4294967295", &port_range)); + EXPECT_FALSE(PortRange::Parse("10-1", &port_range)); + EXPECT_FALSE(PortRange::Parse("1foo-2bar", &port_range)); + + // Unsuccessful parses should NOT modify their output. + EXPECT_EQ(123, port_range.min_port); + EXPECT_EQ(456, port_range.max_port); +} + +TEST(PortRange, Output) { + PortRange port_range; + port_range.min_port = 123; + port_range.max_port = 456; + + std::ostringstream str; + str << port_range; + + EXPECT_THAT(str.str(), testing::MatchesRegex(".*123.*456.*")); +} + +} // namespace remoting
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index 0f40d356..61e260b4 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp
@@ -4,27 +4,6 @@ { 'variables': { - 'chromium_code': 1, - - # Set this to run the jscompile checks after building the webapp. - 'run_jscompile%': 1, - - # Set this to enable cast mode on the android client. - 'enable_cast%': 0, - - 'variables': { - 'conditions': [ - # Enable the multi-process host on Windows by default. - ['OS=="win"', { - 'remoting_multi_process%': 1, - }, { - 'remoting_multi_process%': 0, - }], - ], - }, - - 'remoting_multi_process%': '<(remoting_multi_process)', - 'remoting_rdp_session%': 1, 'branding_path': '../remoting/branding_<(branding)', @@ -41,14 +20,9 @@ # The IDs are not random to avoid rebuilding host when it's not # necessary. 'daemon_controller_clsid': - '<!(python -c "import uuid; print uuid.uuid5(uuid.UUID(\'655bd819-c08c-4b04-80c2-f160739ff6ef\'), \'<(version_full)\')")', + '<!(python -c "import uuid; print uuid.uuid5(uuid.UUID(\'<(daemon_controller_guid)\'), \'<(version_full)\')")', 'rdp_desktop_session_clsid': - '<!(python -c "import uuid; print uuid.uuid5(uuid.UUID(\'6a7699f0-ee43-43e7-aa30-a6738f9bd470\'), \'<(version_full)\')")', - - # Java is not available on Windows bots, so we need to disable - # JScompile checks. - 'run_jscompile': 0, - + '<!(python -c "import uuid; print uuid.uuid5(uuid.UUID(\'<(rdp_desktop_session_guid)\'), \'<(version_full)\')")', }], ], }, @@ -61,6 +35,7 @@ 'remoting_host_srcs.gypi', 'remoting_key_tester.gypi', 'remoting_locales.gypi', + 'remoting_options.gypi', 'remoting_srcs.gypi', 'remoting_test.gypi', 'remoting_version.gypi', @@ -213,7 +188,7 @@ }, # end of target 'remoting_resources' { - # GN version: //remoting/base + # GN version: //remoting/base and //remoting/codec 'target_name': 'remoting_base', 'type': 'static_library', 'variables': { 'enable_wexit_time_destructors': 1, }, @@ -245,6 +220,7 @@ 'hard_dependency': 1, 'sources': [ '<@(remoting_base_sources)', + '<@(remoting_codec_sources)', ], }, # end of target 'remoting_base'
diff --git a/remoting/remoting_host.gypi b/remoting/remoting_host.gypi index e818a971..1c6d44a 100644 --- a/remoting/remoting_host.gypi +++ b/remoting/remoting_host.gypi
@@ -75,11 +75,6 @@ ], }] ], - 'link_settings': { - 'libraries': [ - '-lpam', - ], - }, }], ['chromeos==1', { 'dependencies' : [ @@ -102,7 +97,6 @@ 'host/linux/x_server_clipboard.cc', 'host/linux/x_server_clipboard.h', 'host/local_input_monitor_x11.cc', - 'host/remoting_me2me_host.cc', ], 'conditions': [ ['use_ash==1', { @@ -144,7 +138,6 @@ 'link_settings': { 'libraries': [ '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework', - 'libpam.a', ], }, }], @@ -211,6 +204,7 @@ }, # end of target 'remoting_host' { + # GN version: //remoting/host/native_messaging 'target_name': 'remoting_native_messaging_base', 'type': 'static_library', 'variables': { 'enable_wexit_time_destructors': 1, }, @@ -218,18 +212,12 @@ '../base/base.gyp:base', ], 'sources': [ - 'host/native_messaging/native_messaging_pipe.cc', - 'host/native_messaging/native_messaging_pipe.h', - 'host/native_messaging/native_messaging_reader.cc', - 'host/native_messaging/native_messaging_reader.h', - 'host/native_messaging/native_messaging_writer.cc', - 'host/native_messaging/native_messaging_writer.h', - 'host/native_messaging/pipe_messaging_channel.cc', - 'host/native_messaging/pipe_messaging_channel.h', + '<@(remoting_host_native_messaging_sources)', ], }, # end of target 'remoting_native_messaging_base' { + # GN version: //remoting/host/setup 'target_name': 'remoting_host_setup_base', 'type': 'static_library', 'variables': { 'enable_wexit_time_destructors': 1, }, @@ -242,28 +230,7 @@ 'VERSION=<(version_full)', ], 'sources': [ - 'host/setup/daemon_controller.cc', - 'host/setup/daemon_controller.h', - 'host/setup/daemon_controller_delegate_linux.cc', - 'host/setup/daemon_controller_delegate_linux.h', - 'host/setup/daemon_controller_delegate_mac.h', - 'host/setup/daemon_controller_delegate_mac.mm', - 'host/setup/daemon_controller_delegate_win.cc', - 'host/setup/daemon_controller_delegate_win.h', - 'host/setup/me2me_native_messaging_host.cc', - 'host/setup/me2me_native_messaging_host.h', - 'host/setup/oauth_client.cc', - 'host/setup/oauth_client.h', - 'host/setup/oauth_helper.cc', - 'host/setup/oauth_helper.h', - 'host/setup/pin_validator.cc', - 'host/setup/pin_validator.h', - 'host/setup/service_client.cc', - 'host/setup/service_client.h', - 'host/setup/test_util.cc', - 'host/setup/test_util.h', - 'host/setup/win/auth_code_getter.cc', - 'host/setup/win/auth_code_getter.h', + '<@(remoting_host_setup_sources)', ], 'conditions': [ ['OS=="win"', { @@ -420,6 +387,8 @@ 'dependencies': [ '../base/base.gyp:base', '../base/base.gyp:base_i18n', + '../components/components.gyp:policy', + '../components/components.gyp:policy_component_common', '../net/net.gyp:net', '../third_party/webrtc/modules/modules.gyp:desktop_capture', 'remoting_base', @@ -435,14 +404,26 @@ 'host/curtain_mode_linux.cc', 'host/curtain_mode_mac.cc', 'host/curtain_mode_win.cc', + 'host/pam_authorization_factory_posix.cc', + 'host/pam_authorization_factory_posix.h', 'host/posix/signal_handler.cc', 'host/posix/signal_handler.h', + 'host/remoting_me2me_host.cc', ], 'conditions': [ - ['os_posix != 1', { - 'sources/': [ - ['exclude', '^host/posix/'], - ], + ['OS=="linux"', { + 'link_settings': { + 'libraries': [ + '-lpam', + ], + }, + }], + ['OS=="mac"', { + 'link_settings': { + 'libraries': [ + 'libpam.a', + ], + }, }], ], # end of 'conditions' }, # end of target 'remoting_me2me_host_static'
diff --git a/remoting/remoting_host_linux.gypi b/remoting/remoting_host_linux.gypi index 5ef7418..f9b89ea 100644 --- a/remoting/remoting_host_linux.gypi +++ b/remoting/remoting_host_linux.gypi
@@ -41,6 +41,18 @@ ], 'action': [ 'zip', '-j', '-0', '<@(_outputs)', '<@(_inputs)' ], }, + { + # Copy the debian package file, which has version info in it, + # to a consistent filename for use on Chromoting swarming bots. + 'action_name': 'Copy debian package.', + 'inputs': [ + '<@(deb_filename)', + ], + 'outputs': [ + '<(PRODUCT_DIR)/remoting-me2me-host.deb', + ], + 'action': [ 'cp', '<@(_inputs)', '<@(_outputs)'], + }, ], }, { 'target_name': 'remoting_me2me_host_deb_installer',
diff --git a/remoting/remoting_host_srcs.gypi b/remoting/remoting_host_srcs.gypi index fbdfc71..81ecafb 100644 --- a/remoting/remoting_host_srcs.gypi +++ b/remoting/remoting_host_srcs.gypi
@@ -187,8 +187,6 @@ 'host/pairing_registry_delegate_mac.cc', 'host/pairing_registry_delegate_win.cc', 'host/pairing_registry_delegate_win.h', - 'host/pam_authorization_factory_posix.cc', - 'host/pam_authorization_factory_posix.h', 'host/pin_hash.cc', 'host/pin_hash.h', 'host/policy_watcher.cc', @@ -197,7 +195,6 @@ 'host/register_support_host_request.h', 'host/remote_input_filter.cc', 'host/remote_input_filter.h', - 'host/remoting_me2me_host.cc', 'host/resizing_host_observer.cc', 'host/resizing_host_observer.h', 'host/sas_injector.h', @@ -221,6 +218,8 @@ 'host/single_window_input_injector_linux.cc', 'host/single_window_input_injector_mac.cc', 'host/single_window_input_injector_win.cc', + 'host/third_party_auth_config.cc', + 'host/third_party_auth_config.h', 'host/token_validator_base.cc', 'host/token_validator_base.h', 'host/token_validator_factory_impl.cc', @@ -259,7 +258,41 @@ 'host/win/wts_terminal_monitor.h', 'host/win/wts_terminal_observer.h', ], - 'remoting_cast_sources' : [ + 'remoting_host_setup_sources': [ + 'host/setup/daemon_controller.cc', + 'host/setup/daemon_controller.h', + 'host/setup/daemon_controller_delegate_linux.cc', + 'host/setup/daemon_controller_delegate_linux.h', + 'host/setup/daemon_controller_delegate_mac.h', + 'host/setup/daemon_controller_delegate_mac.mm', + 'host/setup/daemon_controller_delegate_win.cc', + 'host/setup/daemon_controller_delegate_win.h', + 'host/setup/me2me_native_messaging_host.cc', + 'host/setup/me2me_native_messaging_host.h', + 'host/setup/oauth_client.cc', + 'host/setup/oauth_client.h', + 'host/setup/oauth_helper.cc', + 'host/setup/oauth_helper.h', + 'host/setup/pin_validator.cc', + 'host/setup/pin_validator.h', + 'host/setup/service_client.cc', + 'host/setup/service_client.h', + 'host/setup/test_util.cc', + 'host/setup/test_util.h', + 'host/setup/win/auth_code_getter.cc', + 'host/setup/win/auth_code_getter.h', + ], + 'remoting_host_native_messaging_sources': [ + 'host/native_messaging/native_messaging_pipe.cc', + 'host/native_messaging/native_messaging_pipe.h', + 'host/native_messaging/native_messaging_reader.cc', + 'host/native_messaging/native_messaging_reader.h', + 'host/native_messaging/native_messaging_writer.cc', + 'host/native_messaging/native_messaging_writer.h', + 'host/native_messaging/pipe_messaging_channel.cc', + 'host/native_messaging/pipe_messaging_channel.h', + ], + 'remoting_cast_sources': [ 'host/cast_extension.cc', 'host/cast_extension.h', 'host/cast_extension_session.cc',
diff --git a/remoting/remoting_host_win.gypi b/remoting/remoting_host_win.gypi index 54074d16..8a796a0 100644 --- a/remoting/remoting_host_win.gypi +++ b/remoting/remoting_host_win.gypi
@@ -27,6 +27,7 @@ ], }, # end of target 'remoting_breakpad_tester' { + # GN version: //remoting/host:remoting_lib_idl 'target_name': 'remoting_lib_idl', 'type': 'static_library', 'sources': [ @@ -50,6 +51,7 @@ }, 'rules': [ { + # GN version: //remoting/host:generate_idl 'rule_name': 'generate_idl', 'extension': 'templ', 'outputs': [ @@ -381,6 +383,7 @@ }, }, # end of target 'remoting_it2me_native_messaging_host' { + # GN version: //remoting/host:messages 'target_name': 'remoting_host_messages', 'type': 'none', 'dependencies': [
diff --git a/remoting/remoting_key_tester.gypi b/remoting/remoting_key_tester.gypi index d85a321..68db9b0 100644 --- a/remoting/remoting_key_tester.gypi +++ b/remoting/remoting_key_tester.gypi
@@ -55,7 +55,8 @@ 'action_name': 'jscompile remoting_key_tester', 'inputs': [ '<@(remoting_key_tester_js_files)', - 'webapp/js_proto/chrome_proto.js' + 'webapp/js_proto/chrome_proto.js', + 'webapp/js_proto/chrome_event_proto.js', ], 'outputs': [ '<(success_stamp)', @@ -66,7 +67,8 @@ '--no-single-file', '--success-stamp', '<(success_stamp)', '<@(remoting_key_tester_js_files)', - 'webapp/js_proto/chrome_proto.js' + 'webapp/js_proto/chrome_proto.js', + 'webapp/js_proto/chrome_event_proto.js', ], }, ], # actions
diff --git a/remoting/remoting_locales.gni b/remoting/remoting_locales.gni new file mode 100644 index 0000000..0bd0536 --- /dev/null +++ b/remoting/remoting_locales.gni
@@ -0,0 +1,104 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +webapp_locale_dir = "$root_gen_dir/remoting/webapp/_locales" + +# See also remoting_locales_with_underscores below. +remoting_locales = [ + "am", + "ar", + "bg", + "bn", + "ca", + "cs", + "da", + "de", + "el", + "en", + "en-GB", + "es", + "es-419", + "et", + "fa", + "fake-bidi", + "fi", + "fil", + "fr", + "gu", + "he", + "hi", + "hr", + "hu", + "id", + "it", + "ja", + "kn", + "ko", + "lt", + "lv", + "ml", + "mr", + "ms", + "nb", + "nl", + "pl", + "pt-BR", + "pt-PT", + "ro", + "ru", + "sk", + "sl", + "sr", + "sv", + "sw", + "ta", + "te", + "th", + "tr", + "uk", + "vi", + "zh-CN", + "zh-TW", +] + +# Some locales have hyphens in the names but for some uses underscores are +# needed. +remoting_locales_with_underscores = remoting_locales +remoting_locales_with_underscores -= [ + "en-GB", + "es-419", + "fake-bidi", + "pt-BR", + "pt-PT", + "zh-CN", + "zh-TW", +] +remoting_locales_with_underscores += [ + "en_GB", + "es_419", + "fake_bidi", + "pt_BR", + "pt_PT", + "zh_CN", + "zh_TW", +] + +if (is_chromeos) { + remoting_locales += [ "en-US" ] + remoting_locales_with_underscores += [ "en_US" ] +} + +messages_locales = remoting_locales_with_underscores +if (!is_chromeos) { + # The messages output includes a separate one for en-US that the pak ones + # don't have. We don't need to do this on ChromeOS since en_US is in the + # locales list be default there. + messages_locales += [ "en_US" ] +} + +# The list of .json files generated by remoting_strings.grd. +remoting_webapp_locale_files = + process_file_template( + messages_locales, + [ "remoting/webapp/_locales/{{source_name_part}}/messages.json" ])
diff --git a/remoting/remoting_locales.gypi b/remoting/remoting_locales.gypi index 28c84f3..a007dd5 100644 --- a/remoting/remoting_locales.gypi +++ b/remoting/remoting_locales.gypi
@@ -9,7 +9,7 @@ 'webapp_locale_dir': '<(SHARED_INTERMEDIATE_DIR)/remoting/webapp/_locales', 'remoting_locales': [ - # Note: list duplicated in GN build. See //remoting/resources/BUILD.gn + # Note: list duplicated in GN build. See //remoting/remoting_locales.gni 'ar', 'bg', 'ca', 'cs', 'da', 'de', 'el', 'en', 'en-GB', 'es', 'es-419', 'et', 'fi', 'fil', 'fr', 'he', 'hi', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'lt', 'lv', 'nb', 'nl', 'pl', 'pt-BR', 'pt-PT',
diff --git a/remoting/remoting_nacl.gyp b/remoting/remoting_nacl.gyp index f642734..14af09a5 100644 --- a/remoting/remoting_nacl.gyp +++ b/remoting/remoting_nacl.gyp
@@ -116,6 +116,7 @@ 'sources': [ '../ui/events/keycodes/dom4/keycode_converter.cc', '<@(remoting_base_sources)', + '<@(remoting_codec_sources)', '<@(remoting_client_plugin_sources)', '<@(remoting_client_sources)', '<@(remoting_protocol_sources)',
diff --git a/remoting/remoting_options.gypi b/remoting/remoting_options.gypi new file mode 100644 index 0000000..56d339e --- /dev/null +++ b/remoting/remoting_options.gypi
@@ -0,0 +1,40 @@ +# 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. + +{ + 'variables': { + 'chromium_code': 1, + + # Set this to run the jscompile checks after building the webapp. + 'run_jscompile%': 1, + + # Set this to enable cast mode on the android client. + 'enable_cast%': 0, + + 'variables': { + 'conditions': [ + # Enable the multi-process host on Windows by default. + ['OS=="win"', { + 'remoting_multi_process%': 1, + }, { + 'remoting_multi_process%': 0, + }], + ], + }, + 'remoting_multi_process%': '<(remoting_multi_process)', + + 'remoting_rdp_session%': 1, + + 'branding_path': '../remoting/branding_<(branding)', + + 'conditions': [ + ['OS=="win"', { + # Java is not available on Windows bots, so we need to disable + # JScompile checks. + 'run_jscompile': 0, + }], + ], + }, + +}
diff --git a/remoting/remoting_srcs.gni b/remoting/remoting_srcs.gni new file mode 100644 index 0000000..fe87adf6 --- /dev/null +++ b/remoting/remoting_srcs.gni
@@ -0,0 +1,14 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +remoting_srcs_gypi_values = exec_script("//build/gypi_to_gn.py", + [ rebase_path("remoting_srcs.gypi") ], + "scope", + [ "remoting_srcs.gypi" ]) + +remoting_host_srcs_gypi_values = + exec_script("//build/gypi_to_gn.py", + [ rebase_path("remoting_host_srcs.gypi") ], + "scope", + [ "remoting_host_srcs.gypi" ])
diff --git a/remoting/remoting_srcs.gypi b/remoting/remoting_srcs.gypi index df1fbc7..9be7597 100644 --- a/remoting/remoting_srcs.gypi +++ b/remoting/remoting_srcs.gypi
@@ -4,9 +4,9 @@ { 'variables': { + 'daemon_controller_guid': '655bd819-c08c-4b04-80c2-f160739ff6ef', + 'rdp_desktop_session_guid': '6a7699f0-ee43-43e7-aa30-a6738f9bd470', 'remoting_base_sources': [ - 'base/auth_token_util.cc', - 'base/auth_token_util.h', 'base/auto_thread.cc', 'base/auto_thread.h', 'base/auto_thread_task_runner.cc', @@ -43,6 +43,8 @@ 'base/util.h', 'base/vlog_net_log.cc', 'base/vlog_net_log.h', + ], + 'remoting_codec_sources': [ 'codec/audio_decoder.cc', 'codec/audio_decoder.h', 'codec/audio_decoder_opus.cc', @@ -154,7 +156,6 @@ 'protocol/negotiating_client_authenticator.h', 'protocol/negotiating_host_authenticator.cc', 'protocol/negotiating_host_authenticator.h', - 'protocol/network_settings.cc', 'protocol/network_settings.h', 'protocol/pairing_authenticator_base.cc', 'protocol/pairing_authenticator_base.h', @@ -164,6 +165,8 @@ 'protocol/pairing_host_authenticator.h', 'protocol/pairing_registry.cc', 'protocol/pairing_registry.h', + 'protocol/port_range.cc', + 'protocol/port_range.h', 'protocol/pseudotcp_channel_factory.cc', 'protocol/pseudotcp_channel_factory.h', 'protocol/secure_channel_factory.cc',
diff --git a/remoting/remoting_test.gypi b/remoting/remoting_test.gypi index 7d3c50b..3889e9b 100644 --- a/remoting/remoting_test.gypi +++ b/remoting/remoting_test.gypi
@@ -5,6 +5,7 @@ { 'targets': [ { + # GN version: //remoting:test_support 'target_name': 'remoting_test_common', 'type': 'static_library', 'dependencies': [ @@ -20,6 +21,7 @@ 'remoting_resources', ], 'sources': [ + # Note: sources list duplicated in GN build. 'host/fake_desktop_capturer.cc', 'host/fake_desktop_capturer.h', 'host/fake_desktop_environment.cc', @@ -71,6 +73,9 @@ # Remoting unit tests { + # GN version: //remoting:remoting_unittests + # Note that many of the sources are broken out into subdir-specific unit + # test source set targets that then GN version then brings together. 'target_name': 'remoting_unittests', 'type': '<(gtest_target_type)', 'dependencies': [ @@ -107,7 +112,7 @@ '../testing/gmock/include', ], 'sources': [ - 'base/auth_token_util_unittest.cc', + # Note: sources list duplicated in GN build. 'base/auto_thread_task_runner_unittest.cc', 'base/auto_thread_unittest.cc', 'base/breakpad_win_unittest.cc', @@ -188,6 +193,7 @@ 'host/setup/oauth_helper_unittest.cc', 'host/setup/pin_validator_unittest.cc', 'host/shaped_desktop_capturer_unittest.cc', + 'host/third_party_auth_config_unittest.cc', 'host/token_validator_factory_impl_unittest.cc', 'host/video_frame_pump_unittest.cc', 'host/video_frame_recorder_unittest.cc', @@ -215,8 +221,8 @@ 'protocol/monitored_video_stub_unittest.cc', 'protocol/mouse_input_filter_unittest.cc', 'protocol/negotiating_authenticator_unittest.cc', - 'protocol/network_settings_unittest.cc', 'protocol/pairing_registry_unittest.cc', + 'protocol/port_range_unittest.cc', 'protocol/ppapi_module_stub.cc', 'protocol/ssl_hmac_channel_authenticator_unittest.cc', 'protocol/third_party_authenticator_unittest.cc',
diff --git a/remoting/remoting_webapp.gypi b/remoting/remoting_webapp.gypi index 7d72c67..e7b00fd 100644 --- a/remoting/remoting_webapp.gypi +++ b/remoting/remoting_webapp.gypi
@@ -24,6 +24,7 @@ 'variables': { 'success_stamp': '<(PRODUCT_DIR)/<(_target_name)_jscompile.stamp', 'success_stamp_bt': '<(PRODUCT_DIR)/<(_target_name)_bt_jscompile.stamp', + 'success_stamp_ut': '<(PRODUCT_DIR)/<(_target_name)_ut_jscompile.stamp', }, 'actions': [ { @@ -49,7 +50,7 @@ 'inputs': [ '<@(remoting_webapp_crd_js_files)', '<@(remoting_webapp_browsertest_all_js_files)', - '<@(remoting_webapp_js_proto_files)', + '<@(remoting_webapp_browsertest_js_proto_files)', ], 'outputs': [ '<(success_stamp_bt)', @@ -61,7 +62,27 @@ '--success-stamp', '<(success_stamp_bt)', '<@(remoting_webapp_crd_js_files)', '<@(remoting_webapp_browsertest_all_js_files)', - '<@(remoting_webapp_js_proto_files)', + '<@(remoting_webapp_browsertest_js_proto_files)', + ], + }, + { + 'action_name': 'Verify remoting webapp unittests', + 'inputs': [ + '<@(remoting_webapp_crd_js_files)', + '<@(remoting_webapp_unittest_all_js_files)', + '<@(remoting_webapp_unittest_js_proto_files)', + ], + 'outputs': [ + '<(success_stamp_ut)', + ], + 'action': [ + 'python', '../third_party/closure_compiler/checker.py', + '--strict', + '--no-single-file', + '--success-stamp', '<(success_stamp_ut)', + '<@(remoting_webapp_crd_js_files)', + '<@(remoting_webapp_unittest_all_js_files)', + '<@(remoting_webapp_unittest_js_proto_files)', ], }, ], # actions
diff --git a/remoting/remoting_webapp_files.gypi b/remoting/remoting_webapp_files.gypi index 129f198b..26cb5912 100644 --- a/remoting/remoting_webapp_files.gypi +++ b/remoting/remoting_webapp_files.gypi
@@ -14,19 +14,16 @@ # These provide type information for jscompile. 'remoting_webapp_js_proto_files': [ 'webapp/js_proto/chrome_proto.js', + 'webapp/js_proto/chrome_cast_proto.js', + 'webapp/js_proto/chrome_event_proto.js', 'webapp/js_proto/dom_proto.js', 'webapp/js_proto/remoting_proto.js', - 'webapp/js_proto/test_proto.js', ], # - # Webapp browsertest and unittest JavaScript files. + # Webapp browsertest JavaScript files. # - # Shared files for tests. - 'remoting_webapp_test_js_common_files': [ - 'webapp/unittests/mock_signal_strategy.js', - ], # Browser test files. 'remoting_webapp_browsertest_js_files': [ 'webapp/browser_test/browser_test.js', @@ -34,21 +31,34 @@ 'webapp/browser_test/cancel_pin_browser_test.js', 'webapp/browser_test/invalid_pin_browser_test.js', 'webapp/browser_test/it2me_browser_test.js', - 'webapp/browser_test/mock_client_plugin.js', - 'webapp/browser_test/mock_host_list_api.js', - 'webapp/browser_test/mock_identity.js', - 'webapp/browser_test/mock_oauth2_api.js', - 'webapp/browser_test/mock_session_connector.js', 'webapp/browser_test/scrollbar_browser_test.js', 'webapp/browser_test/timeout_waiter.js', 'webapp/browser_test/unauthenticated_browser_test.js', 'webapp/browser_test/update_pin_browser_test.js', ], + # Browser test files. + 'remoting_webapp_browsertest_js_mock_files': [ + 'webapp/browser_test/mock_client_plugin.js', + 'webapp/browser_test/mock_host_list_api.js', + 'webapp/browser_test/mock_identity.js', + 'webapp/browser_test/mock_oauth2_api.js', + 'webapp/browser_test/mock_session_connector.js', + 'webapp/unittests/mock_signal_strategy.js', + ], + 'remoting_webapp_browsertest_js_proto_files': [ + 'webapp/js_proto/sinon_proto.js', + 'webapp/js_proto/test_proto.js', + '<@(remoting_webapp_js_proto_files)', + ], 'remoting_webapp_browsertest_all_js_files': [ '<@(remoting_webapp_browsertest_js_files)', - '<@(remoting_webapp_test_js_common_files)', + '<@(remoting_webapp_browsertest_js_mock_files)', ], + # + # Webapp unittest JavaScript files. + # + # These product files are excluded from our JavaScript unittest 'remoting_webapp_unittest_exclude_js_files': [ # background.js is where the onLoad handler is defined, which @@ -57,18 +67,14 @@ ], # The unit test cases for the webapp 'remoting_webapp_unittest_js_files': [ - 'webapp/unittests/chrome_mocks.js', - 'webapp/js_proto/chrome_proto.js', 'webapp/unittests/apps_v2_migration_unittest.js', 'webapp/unittests/base_unittest.js', 'webapp/unittests/desktop_viewport_unittest.js', 'webapp/unittests/dns_blackhole_checker_unittest.js', 'webapp/unittests/event_hook_unittest.js', 'webapp/unittests/fallback_signal_strategy_unittest.js', + 'webapp/unittests/host_table_entry_unittest.js', 'webapp/unittests/ipc_unittest.js', - 'webapp/unittests/it2me_helpee_channel_unittest.js', - 'webapp/unittests/it2me_helper_channel_unittest.js', - 'webapp/unittests/it2me_service_unittest.js', 'webapp/unittests/l10n_unittest.js', 'webapp/unittests/menu_button_unittest.js', 'webapp/unittests/xhr_unittest.js', @@ -76,10 +82,29 @@ 'webapp/unittests/xmpp_login_handler_unittest.js', 'webapp/unittests/xmpp_stream_parser_unittest.js', ], + 'remoting_webapp_unittest_js_mock_files': [ + # Some proto files can be repurposed as simple mocks for the unittests. + # Note that some defs in chrome_proto are overwritten by chrome_mocks. + 'webapp/js_proto/chrome_proto.js', + 'webapp/unittests/chrome_mocks.js', + 'webapp/unittests/mock_signal_strategy.js', + 'webapp/unittests/sinon_helpers.js', + 'webapp/unittests/test_start.js', + ], + # Prototypes for objects that are not mocked. + 'remoting_webapp_unittest_js_proto_files': [ + 'webapp/js_proto/chrome_cast_proto.js', + 'webapp/js_proto/dom_proto.js', + 'webapp/js_proto/remoting_proto.js', + 'webapp/js_proto/qunit_proto.js', + 'webapp/js_proto/sinon_proto.js', + 'webapp/js_proto/sinon_stub_proto.js', + ], 'remoting_webapp_unittest_all_js_files': [ '<@(remoting_webapp_unittest_js_files)', - '<@(remoting_webapp_test_js_common_files)', + '<@(remoting_webapp_unittest_js_mock_files)', ], + # All the files needed to run the unittests. 'remoting_webapp_unittest_all_files': [ 'webapp/crd/html/menu_button.css', '<@(remoting_webapp_unittest_all_js_files)', @@ -121,14 +146,10 @@ 'webapp/crd/js/client_plugin.js', 'webapp/crd/js/client_plugin_impl.js', 'webapp/crd/js/client_plugin_host_desktop_impl.js', - # TODO(garykac) For client_screen: - # * Split out pin/access code stuff into separate file. - # * Move client logic into session_connector - 'webapp/crd/js/client_screen.js', 'webapp/crd/js/client_session.js', 'webapp/crd/js/clipboard.js', + 'webapp/crd/js/credentials_provider.js', 'webapp/crd/js/desktop_connected_view.js', - 'webapp/crd/js/hangout_session.js', 'webapp/crd/js/host_desktop.js', 'webapp/crd/js/session_connector.js', 'webapp/crd/js/session_connector_impl.js', @@ -178,6 +199,7 @@ 'webapp/crd/js/host_list_api.js', 'webapp/crd/js/host_list_api_impl.js', 'webapp/crd/js/host_table_entry.js', + 'webapp/crd/js/local_host_section.js', ], # Logging and stats JavaScript files. 'remoting_webapp_js_logging_files': [ @@ -263,14 +285,10 @@ 'webapp/crd/js/background.js', 'webapp/crd/js/client_session.js', 'webapp/crd/js/error.js', - 'webapp/crd/js/hangout_consent_dialog.js', 'webapp/crd/js/host_installer.js', 'webapp/crd/js/host_session.js', 'webapp/crd/js/identity.js', - 'webapp/crd/js/it2me_helpee_channel.js', - 'webapp/crd/js/it2me_helper_channel.js', 'webapp/crd/js/it2me_host_facade.js', - 'webapp/crd/js/it2me_service.js', 'webapp/crd/js/l10n.js', 'webapp/crd/js/oauth2.js', 'webapp/crd/js/oauth2_api.js', @@ -294,8 +312,6 @@ '<@(remoting_webapp_background_js_files)', # JS files for message_window.html 'webapp/base/js/message_window.js', - # JS files for dialog_hangout_consent.html - 'webapp/crd/js/hangout_consent_dialog_main.js', # JS files for wcs_sandbox.html. # Use r_w_js_wcs_sandbox_files instead of r_w_wcs_sandbox_html_js_files # so that we don't double include error.js and plugin_settings.js. @@ -339,8 +355,6 @@ 'webapp/base/resources/open_sans.woff', 'webapp/base/resources/spinner.gif', 'webapp/crd/html/butter_bar.css', - 'webapp/crd/html/dialog_hangout_consent.html', - 'webapp/crd/html/dialog_hangout_consent.css', 'webapp/crd/html/toolbar.css', 'webapp/crd/html/menu_button.css', 'webapp/crd/html/window_frame.css',
diff --git a/remoting/resources/BUILD.gn b/remoting/resources/BUILD.gn index 848f9c2..05aab92 100644 --- a/remoting/resources/BUILD.gn +++ b/remoting/resources/BUILD.gn
@@ -2,93 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//remoting/remoting_locales.gni") import("//tools/grit/grit_rule.gni") -# See also remoting_locales_with_underscores below. -remoting_locales = [ - "am", - "ar", - "bg", - "bn", - "ca", - "cs", - "da", - "de", - "el", - "en", - "en-GB", - "es", - "es-419", - "et", - "fa", - "fake-bidi", - "fi", - "fil", - "fr", - "gu", - "he", - "hi", - "hr", - "hu", - "id", - "it", - "ja", - "kn", - "ko", - "lt", - "lv", - "ml", - "mr", - "ms", - "nb", - "nl", - "pl", - "pt-BR", - "pt-PT", - "ro", - "ru", - "sk", - "sl", - "sr", - "sv", - "sw", - "ta", - "te", - "th", - "tr", - "uk", - "vi", - "zh-CN", - "zh-TW", -] - -# Some locales have hyphens in the names but for some uses underscores are -# needed. -remoting_locales_with_underscores = remoting_locales -remoting_locales_with_underscores -= [ - "en-GB", - "es-419", - "fake-bidi", - "pt-BR", - "pt-PT", - "zh-CN", - "zh-TW", -] -remoting_locales_with_underscores += [ - "en_GB", - "es_419", - "fake_bidi", - "pt_BR", - "pt_PT", - "zh_CN", - "zh_TW", -] - -if (is_chromeos) { - remoting_locales += [ "en-US" ] - remoting_locales_with_underscores += [ "en_US" ] -} - group("resources") { deps = [ ":copy_locales", @@ -166,16 +82,7 @@ process_file_template(remoting_locales, [ "remoting/resources/{{source_name_part}}.pak" ]) - messages_locales = remoting_locales_with_underscores - if (!is_chromeos) { - # The messages output includes a separate one for en-US that the pak ones - # don't have. We don't need to do this on ChromeOS since en_US is in the - # locales list be default there. - messages_locales += [ "en_US" ] - } - outputs += process_file_template( - messages_locales, - [ "remoting/webapp/_locales/{{source_name_part}}/messages.json" ]) + outputs += remoting_webapp_locale_files } action("copy_locales") {
diff --git a/remoting/resources/remoting_strings.grd b/remoting/resources/remoting_strings.grd index cf1c2c0..8419ef9 100644 --- a/remoting/resources/remoting_strings.grd +++ b/remoting/resources/remoting_strings.grd
@@ -769,6 +769,9 @@ <message desc="Button displayed when the current computer is not accepting remote connections. Clicking this button causes it to start accepting remote connections." name="IDS_HOME_DAEMON_START_BUTTON"> Enable remote connections </message> + <message desc="Message displayed in the application to indicate that this computer is remotely accessible, but only from a different account than the one that the user is currently signed in as." name="IDS_HOME_DAEMON_HOST_ENABLED_OTHER_ACCOUNT"> + This computer is currently shared under a different account. + </message> <message desc="Explanatory text displayed when the user enables remote access or changes the PIN." name="IDS_HOST_SETUP_DIALOG_DESCRIPTION"> To protect access to this computer, please choose a PIN of <ph name="BOLD_START">$1<ex><b></ex></ph>at least six digits<ph name="BOLD_END">$2<ex></b></ex></ph>. This PIN will be required when connecting from another location. </message> @@ -996,9 +999,6 @@ <message desc="Check-box displayed when the user enters their PIN to connect to a host allowing them to 'pair' the client and host, avoiding the need to enter the PIN each time." name="IDS_REMEMBER_PIN" formatter_data="android_java"> Don't ask for a PIN again when connecting to this host from this device. </message> - <message name="IDS_HANGOUTS_INVITATION" desc="Text for the invitation to try Remote Desktop app in Hangouts."> - Want to help someone while having a video chat with them too? Try <ph name="LINK_BEGIN">$1<ex><a href=https://plus.google.com/hangouts></ex></ph> Remote Desktop in Google Hangouts<ph name="LINK_END">$2<ex></a></ex></ph>. - </message> <message name="IDS_REMOTING_CORE_DESCRIPTION" desc="The file description specified in the version information of remoting_core.dll."> Core Library </message> @@ -1077,15 +1077,6 @@ <message desc="Label for the Feedback button displayed in the Android Help screen. Pressing this button causes the Feedback screen to be shown." name="IDS_ACTIONBAR_FEEDBACK" formatter_data="android_java"> Feedback </message> - <message desc="Message displayed in the Hangouts confirm dialog. This message is shown to the Hangouts participant receiving remote assistance before the access code is generated. The dialog informs the user of the implications of accepting remote assistance. It also provides a way for the user to decline the assistance." name="IDS_HANGOUTS_CONFIRM_DIALOG_MESSAGE_1" > - A participant in this hangout has offered to help you by controlling your computer. If you accept: - </message> - <message desc="Message displayed in the Hangouts confirm dialog. This message is shown to the Hangouts participant receiving remote assistance before the access code is generated. The dialog informs the user of the implications of accepting remote assistance. It also provides a way for the user to decline the assistance." name="IDS_HANGOUTS_CONFIRM_DIALOG_MESSAGE_2" > - The person helping you will be able to control your mouse and keyboard. - </message> - <message desc="Message displayed in the Hangouts confirm dialog. This message is shown to the Hangouts participant receiving remote assistance before the access code is generated. The dialog informs the user of the implications of accepting remote assistance. It also provides a way for the user to decline the assistance." name="IDS_HANGOUTS_CONFIRM_DIALOG_MESSAGE_3" > - You can end at any time. - </message> <message desc="Label for button to accept remote assistance. This button appears in the Hangouts confirm dialog." name="IDS_HANGOUTS_CONFIRM_DIALOG_ACCEPT" > Accept </message>
diff --git a/remoting/signaling/xmpp_signal_strategy.cc b/remoting/signaling/xmpp_signal_strategy.cc index 806852e..5ad0c03 100644 --- a/remoting/signaling/xmpp_signal_strategy.cc +++ b/remoting/signaling/xmpp_signal_strategy.cc
@@ -83,7 +83,7 @@ settings.set_user(login_jid.node()); settings.set_host(login_jid.domain()); settings.set_resource(resource_name_); - settings.set_token_service(xmpp_server_config_.auth_service); + settings.set_token_service("oauth2"); settings.set_auth_token(buzz::AUTH_MECHANISM_GOOGLE_TOKEN, xmpp_server_config_.auth_token); @@ -203,12 +203,10 @@ } void XmppSignalStrategy::SetAuthInfo(const std::string& username, - const std::string& auth_token, - const std::string& auth_service) { + const std::string& auth_token) { DCHECK(CalledOnValidThread()); xmpp_server_config_.username = username; xmpp_server_config_.auth_token = auth_token; - xmpp_server_config_.auth_service = auth_service; } void XmppSignalStrategy::SetResourceName(const std::string &resource_name) { @@ -269,13 +267,8 @@ buzz::PreXmppAuth* XmppSignalStrategy::CreatePreXmppAuth( const buzz::XmppClientSettings& settings) { buzz::Jid jid(settings.user(), settings.host(), buzz::STR_EMPTY); - std::string mechanism = notifier::kDefaultGaiaAuthMechanism; - if (settings.token_service() == "oauth2") { - mechanism = "X-OAUTH2"; - } - return new notifier::GaiaTokenPreXmppAuth( - jid.Str(), settings.auth_token(), settings.token_service(), mechanism); + jid.Str(), settings.auth_token(), settings.token_service(), "X-OAUTH2"); } } // namespace remoting
diff --git a/remoting/signaling/xmpp_signal_strategy.h b/remoting/signaling/xmpp_signal_strategy.h index 18ae841..2d8268b786 100644 --- a/remoting/signaling/xmpp_signal_strategy.h +++ b/remoting/signaling/xmpp_signal_strategy.h
@@ -50,7 +50,6 @@ std::string username; std::string auth_token; - std::string auth_service; }; XmppSignalStrategy( @@ -77,8 +76,7 @@ // access token is renewed). It is OK to call this even when we are in the // CONNECTED state. It will be used on the next Connect() call. void SetAuthInfo(const std::string& username, - const std::string& auth_token, - const std::string& auth_service); + const std::string& auth_token); // Use this method to override the default resource name used (optional). // This will be used on the next Connect() call.
diff --git a/remoting/tools/build/message_compiler.gni b/remoting/tools/build/message_compiler.gni new file mode 100644 index 0000000..20eae139 --- /dev/null +++ b/remoting/tools/build/message_compiler.gni
@@ -0,0 +1,51 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_win, "This only runs on Windows.") + +# Runs mc.exe over a list of sources. +# +# sources +# List of .mc files to process. +template("message_compiler") { + action_name = "${target_name}_mc" + source_set_name = target_name + + action_foreach(action_name) { + visibility = [ ":$source_set_name" ] + script = "//remoting/tools/build/message_compiler.py" + + sources = invoker.sources + + outputs = [ + "$target_gen_dir/{{source_name_part}}.h", + "$target_gen_dir/{{source_name_part}}.rc", + ] + + args = [ + # Where to put the header. + "-h", + rebase_path(target_gen_dir, root_build_dir), + + # Where to put the .rc file. + "-r", + rebase_path(target_gen_dir, root_build_dir), + + # Input is Unicode. + "-u", + "{{source}}", + ] + + if (defined(invoker.deps)) { + deps = invoker.deps + } + } + + source_set(source_set_name) { + sources = get_target_outputs(":$action_name") + deps = [ + ":$action_name", + ] + } +}
diff --git a/remoting/tools/build/message_compiler.py b/remoting/tools/build/message_compiler.py new file mode 100644 index 0000000..60b0eaa5 --- /dev/null +++ b/remoting/tools/build/message_compiler.py
@@ -0,0 +1,16 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Runs the Microsoft Message Compiler (mc.exe). This Python adapter is for the +# GYP build, which can only run Python and not native binaries. + +import subprocess +import sys + +# mc writes to stderr, so this explicily redirects to stdout and eats it. +try: + subprocess.check_output(["mc.exe"] + sys.argv[1:], stderr=subprocess.STDOUT) +except subprocess.CalledProcessError as e: + print e.output + sys.exit(e.returncode)
diff --git a/remoting/tools/build/remoting_localize.gni b/remoting/tools/build/remoting_localize.gni new file mode 100644 index 0000000..54ff46e2 --- /dev/null +++ b/remoting/tools/build/remoting_localize.gni
@@ -0,0 +1,113 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Calls the remoting_localize script with a jinja2 template. +# +# Arguments +# +# sources (required) +# List of jinja2 files to load. This is the template. +# +# locales (required) +# List of locales. +# +# locale_dir (optional) +# +# defines (optional) +# List of defines to pass to script. +# Example: defines = [ "FOO_HOST_PATH=bar" ] +# +# variables (optional) +# List of variables to pass to script. +# +# output (optiona) +# Substitution pattern for the output. Defaults to a file in the target +# gen dir with the extension stripped (normally the extension is ".jinja2" +# which then leaves the non-tempaltized file name). +# TODO(brettw) Need locale_output. This is a per-locale output file. +# +# encoding (optional) +# String. +# +# deps (optional) +# visibility (optional) +template("remoting_localize") { + action_foreach(target_name) { + if (defined(invoker.visibility)) { + visibility = invoker.visibility + } + + script = "//remoting/tools/build/remoting_localize.py" + + sources = invoker.sources + + if (defined(invoker.output)) { + outputs = [ + invoker.output, + ] + } else { + outputs = [ + "$target_gen_dir/{{source_name_part}}", + ] + } + + args = [] + + if (defined(invoker.locale_dir)) { + args += [ + "--locale_dir", + rebase_path(invoker.locale_dir, root_build_dir), + ] + } + + # Add defines to command line. + if (defined(invoker.defines)) { + foreach(i, invoker.defines) { + args += [ + "--define", + i, + ] + } + } + + # Add variables to command line. + if (defined(invoker.variables)) { + foreach(i, invoker.variables) { + args += [ + "--variables", + i, + ] + } + } + + # The template file is required. + args += [ + "--template", + "{{source}}", + ] + + args += [ + "--output", + rebase_path(outputs[0], root_build_dir), + ] + + if (defined(invoker.encoding)) { + args += [ + "--encoding", + invoker.encoding, + ] + } + + args += invoker.locales + + if (defined(invoker.deps)) { + deps = invoker.deps + } else { + deps = [] + } + + # This script reads the messages strings from the generated resource files. + deps += [ "//remoting/resources:strings" ] + } +}
diff --git a/remoting/webapp/app_remoting/html/ar_main.css b/remoting/webapp/app_remoting/html/ar_main.css new file mode 100644 index 0000000..56cd979 --- /dev/null +++ b/remoting/webapp/app_remoting/html/ar_main.css
@@ -0,0 +1,8 @@ +/* Copyright 2015 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +html { + background-image: radial-gradient(#444, #111); +} \ No newline at end of file
diff --git a/remoting/webapp/app_remoting/html/feedback_consent.html b/remoting/webapp/app_remoting/html/feedback_consent.html deleted file mode 100644 index adaf745f8..0000000 --- a/remoting/webapp/app_remoting/html/feedback_consent.html +++ /dev/null
@@ -1,68 +0,0 @@ -<!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> - <head> - <meta charset="utf-8"> - <link rel="icon" type="image/png" href="icon16.png"> - <link rel="stylesheet" href="open_sans.css"> - <link rel="stylesheet" href="feedback_consent.css"> - <link rel="stylesheet" href="main.css"> - <link rel="stylesheet" href="message_window.css"> - <script src="error.js"></script> - <script src="feedback_consent.js"></script> - <script src="oauth2_api_impl.js"></script> - <script src="plugin_settings.js"></script> - <script src="l10n.js"></script> - <script src="xhr.js"></script> - <title i18n-content="FEEDBACK_CONSENT_TITLE"></title> - </head> - <body> - <h2 i18n-content="FEEDBACK_CONSENT_TITLE"></h2> - <p i18n-content="FEEDBACK_CONSENT" - class="message"></p> - <div id="form-body"> - <label class="checkbox-label" - id="abandon-host-label"> - <input id="abandon-host" - type="checkbox"> - <span i18n-content="FEEDBACK_ABANDON_HOST"></span> - </label> - <label class="checkbox-label checkbox-indent disabled" - id="include-logs-label"> - <input id="include-logs" - type="checkbox" - disabled> - <span i18n-content="FEEDBACK_INCLUDE_LOGS"></span> - <a id="learn-more" - i18n-content="LEARN_MORE" - class="disabled"></a> - </label> - <div id="privacy-info" - class="information-box" - hidden> - <p i18n-content="FEEDBACK_PRIVACY_INFORMATION1"></p> - <p i18n-content="FEEDBACK_PRIVACY_INFORMATION2"></p> - </div> - </div> <!-- form-body --> - <div id="abandon-failed" - class="message error-state multi-line-error-state" - i18n-content="FEEDBACK_ABANDON_FAILED" - hidden></div> - <div class="button-row"> - <span id="working" - class="waiting" - i18n-content="WORKING" - hidden></span> - <button id="feedback-consent-ok" - i18n-content="OK" - autofocus="autofocus"></button> - <button id="feedback-consent-cancel" - i18n-content="CANCEL"></button> - </div> - </body> -</html>
diff --git a/remoting/webapp/app_remoting/html/template_feedback_consent.html b/remoting/webapp/app_remoting/html/template_feedback_consent.html new file mode 100644 index 0000000..a0cb8da --- /dev/null +++ b/remoting/webapp/app_remoting/html/template_feedback_consent.html
@@ -0,0 +1,65 @@ +<!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> + <head> + <meta charset="utf-8"> + <link rel="icon" type="image/png" href="icon16.png"> + <link rel="stylesheet" href="open_sans.css"> + <link rel="stylesheet" href="feedback_consent.css"> + <link rel="stylesheet" href="main.css"> + <link rel="stylesheet" href="message_window.css"> + + <meta-include type="javascript"/> + + <title i18n-content="FEEDBACK_CONSENT_TITLE"></title> + </head> + <body> + <h2 i18n-content="FEEDBACK_CONSENT_TITLE"></h2> + <p i18n-content="FEEDBACK_CONSENT" + class="message"></p> + <div id="form-body"> + <label class="checkbox-label" + id="abandon-host-label"> + <input id="abandon-host" + type="checkbox"> + <span i18n-content="FEEDBACK_ABANDON_HOST"></span> + </label> + <label class="checkbox-label checkbox-indent disabled" + id="include-logs-label"> + <input id="include-logs" + type="checkbox" + disabled> + <span i18n-content="FEEDBACK_INCLUDE_LOGS"></span> + <a id="learn-more" + i18n-content="LEARN_MORE" + class="disabled"></a> + </label> + <div id="privacy-info" + class="information-box" + hidden> + <p i18n-content="FEEDBACK_PRIVACY_INFORMATION1"></p> + <p i18n-content="FEEDBACK_PRIVACY_INFORMATION2"></p> + </div> + </div> <!-- form-body --> + <div id="abandon-failed" + class="message error-state multi-line-error-state" + i18n-content="FEEDBACK_ABANDON_FAILED" + hidden></div> + <div class="button-row"> + <span id="working" + class="waiting" + i18n-content="WORKING" + hidden></span> + <button id="feedback-consent-ok" + i18n-content="OK" + autofocus="autofocus"></button> + <button id="feedback-consent-cancel" + i18n-content="CANCEL"></button> + </div> + </body> +</html>
diff --git a/remoting/webapp/app_remoting/html/template_lg.html b/remoting/webapp/app_remoting/html/template_lg.html index 9b666acfa..32bb369 100644 --- a/remoting/webapp/app_remoting/html/template_lg.html +++ b/remoting/webapp/app_remoting/html/template_lg.html
@@ -9,11 +9,12 @@ <head> <meta charset="utf-8"> <link rel="icon" type="image/png" href="icon16.png"> - <link rel="stylesheet" href="open_sans.css"> + <link rel="stylesheet" href="ar_main.css"> <link rel="stylesheet" href="connection_stats.css"> <link rel="stylesheet" href="context_menu.css"> <link rel="stylesheet" href="main.css"> <link rel="stylesheet" href="menu_button.css"> + <link rel="stylesheet" href="open_sans.css"> <meta-include type="javascript"/>
diff --git a/remoting/webapp/app_remoting/js/app_remoting.js b/remoting/webapp/app_remoting/js/app_remoting.js index 2aab7393..950b6f7 100644 --- a/remoting/webapp/app_remoting/js/app_remoting.js +++ b/remoting/webapp/app_remoting/js/app_remoting.js
@@ -144,7 +144,7 @@ var idleDetector = new remoting.IdleDetector( document.getElementById('idle-dialog'), - remoting.disconnect); + remoting.app.disconnect.bind(remoting.app)); /** * @param {string} tokenUrl Token-issue URL received from the host. @@ -190,7 +190,7 @@ method: 'POST', url: that.runApplicationUrl(), onDone: parseAppHostResponse, - oauthToken: token, + oauthToken: token }); }; @@ -238,9 +238,12 @@ * @return {void} Nothing. */ remoting.AppRemoting.prototype.handleConnected = function(clientSession) { - remoting.clientSession.sendClientMessage( - 'setUserDisplayInfo', - JSON.stringify({fullName: remoting.identity.getCachedUserFullName()})); + remoting.identity.getUserInfo().then( + function(userInfo) { + remoting.clientSession.sendClientMessage( + 'setUserDisplayInfo', + JSON.stringify({fullName: userInfo.name})); + }); // Set up a ping at 10-second intervals to test the connection speed. function ping() {
diff --git a/remoting/webapp/app_remoting/js/feedback_consent.js b/remoting/webapp/app_remoting/js/feedback_consent.js index 6691ed2..f792376 100644 --- a/remoting/webapp/app_remoting/js/feedback_consent.js +++ b/remoting/webapp/app_remoting/js/feedback_consent.js
@@ -15,7 +15,7 @@ * @type {string} The network stats at the time the feedback consent dialog * was shown. */ -var connectionStats = null; +var connectionStats = ''; /** * @type {string} "no" => user did not request a VM reset; "yes" => VM was @@ -102,8 +102,8 @@ */ function generateId() { var idArray = new Uint8Array(20); - crypto.getRandomValues(idArray); - return btoa(String.fromCharCode.apply(null, idArray)); + window.crypto.getRandomValues(idArray); + return window.btoa(String.fromCharCode.apply(null, idArray)); } /** @@ -123,10 +123,6 @@ 'abandonHost': 'true', 'crashServiceReportId': crashServiceReportId }; - var headers = { - 'Authorization': 'OAuth ' + token, - 'Content-type': 'application/json' - }; var uri = remoting.settings.APP_REMOTING_API_BASE_URL + '/applications/' + remoting.settings.getAppRemotingApplicationId() + '/hosts/' + hostId + @@ -139,7 +135,13 @@ showError(); } }; - remoting.xhr.post(uri, onDone, JSON.stringify(body), headers); + remoting.xhr.start({ + method: 'POST', + url: uri, + onDone: onDone, + jsonContent: body, + oauthToken: token + }); } else { getUserInfo(); } @@ -184,6 +186,7 @@ } } +/** @param {Event} event */ function onLearnMore(event) { event.preventDefault(); // Clicking the link should not tick the checkbox. var learnMoreLink = document.getElementById('learn-more');
diff --git a/remoting/webapp/base/html/main.css b/remoting/webapp/base/html/main.css index cd463e7e..19f426f 100644 --- a/remoting/webapp/base/html/main.css +++ b/remoting/webapp/base/html/main.css
@@ -360,16 +360,15 @@ display: flex; -webkit-align-items: center; padding: 10px 0; - border-top: 1px solid #EBEBEB; + border-bottom: 1px solid #EBEBEB; } .section-row button { margin-__MSG_@@bidi_start_edge__: 20px; } -.section-row:first-child, -.section-row.no-non-local-hosts { - border-top: none; +.daemon-control .section-row { + border-bottom: none; } .editbox-label { @@ -442,6 +441,7 @@ font-weight: bold; } +#this-host-connect:hover, .host-online.clickable:hover, .host-online.clickable.child-focused { background-color: #f2f2f2; @@ -474,7 +474,7 @@ padding: 0 5px; } -.host-list-label, .host-list-label:visited, .host-list-label:active { +.host-name-label, .host-name-label:visited, .host-name-label:active { color: inherit; cursor: inherit; } @@ -495,11 +495,21 @@ right: -10px; } -.host-offline .host-list-label, +.host-offline .host-name-label, .host-offline .host-list-main-icon { opacity: 0.5; } +#this-host-connect, +.host-enabled-other-account { + -webkit-align-items: center; + display: flex; +} + +#this-host-connect .host-entry { + flex: 1; +} + button { white-space:nowrap; } @@ -727,7 +737,3 @@ position: absolute; pointer-events: none; } - -body.hangout-remote-desktop .home-screen { - display: none; -}
diff --git a/remoting/webapp/base/js/application.js b/remoting/webapp/base/js/application.js index e31fb50..d270cc9 100644 --- a/remoting/webapp/base/js/application.js +++ b/remoting/webapp/base/js/application.js
@@ -13,6 +13,19 @@ var remoting = remoting || {}; /** + * @type {remoting.ClientSession} The client session object, set once the + * connector has invoked its onOk callback. + * TODO(garykac): Make clientSession a member var of Application. + */ +remoting.clientSession = null; + +/** + * @type {remoting.DesktopConnectedView} The client session view object, set + * once the connector has invoked its onOk callback. + */ +remoting.desktopConnectedView = null; + +/** * @param {Array<string>} app_capabilities Array of application capabilities. * @constructor */ @@ -40,6 +53,9 @@ * @private */ this.session_connector_ = null; + + /** @private {base.Disposable} */ + this.sessionConnectedHooks_ = null; }; /** @@ -93,6 +109,14 @@ this.delegate_.init(this.getSessionConnector()); }; +/** Disconnect the remoting client. */ +remoting.Application.prototype.disconnect = function() { + if (remoting.clientSession) { + remoting.clientSession.disconnect(remoting.Error.NONE); + console.log('Disconnected.'); + } +}; + /** * Called when a new session has been connected. * @@ -100,16 +124,13 @@ * @return {void} Nothing. */ remoting.Application.prototype.onConnected = function(clientSession) { - // TODO(garykac): Make clientSession a member var of Application. remoting.clientSession = clientSession; - remoting.clientSession.addEventListener('stateChanged', onClientStateChange_); - - remoting.clipboard.startSession(); - updateStatistics_(); - remoting.hangoutSessionEvents.raiseEvent( - remoting.hangoutSessionEvents.sessionStateChanged, - remoting.ClientSession.State.CONNECTED + this.sessionConnectedHooks_ = new base.Disposables( + new base.EventHook( + clientSession, 'stateChanged', this.onClientStateChange_.bind(this)), + new base.RepeatingTimer(this.updateStatistics_.bind(this), 1000) ); + remoting.clipboard.startSession(); this.delegate_.handleConnected(clientSession); }; @@ -196,6 +217,48 @@ return this.session_connector_; }; +/** + * Callback function called when the state of the client plugin changes. The + * current and previous states are available via the |state| member variable. + * + * @param {remoting.ClientSession.StateEvent=} state + * @private + */ +remoting.Application.prototype.onClientStateChange_ = function(state) { + switch (state.current) { + case remoting.ClientSession.State.CLOSED: + console.log('Connection closed by host'); + this.onDisconnected(); + break; + case remoting.ClientSession.State.FAILED: + var error = remoting.clientSession.getError(); + console.error('Client plugin reported connection failed: ' + error); + if (error === null) { + error = remoting.Error.UNEXPECTED; + } + this.onError(error); + break; + + default: + console.error('Unexpected client plugin state: ' + state.current); + // This should only happen if the web-app and client plugin get out of + // sync, so MISSING_PLUGIN is a suitable error. + this.onError(remoting.Error.MISSING_PLUGIN); + break; + } + + base.dispose(this.sessionConnectedHooks_); + this.sessionConnectedHooks_= null; + remoting.clientSession.dispose(); + remoting.clientSession = null; +}; + +/** @private */ +remoting.Application.prototype.updateStatistics_ = function() { + var perfstats = remoting.clientSession.getPerfStats(); + remoting.stats.update(perfstats); + remoting.clientSession.logStatistics(perfstats); +}; /** * @interface
diff --git a/remoting/webapp/base/js/auth_init.js b/remoting/webapp/base/js/auth_init.js index c67e454..009edd14 100644 --- a/remoting/webapp/base/js/auth_init.js +++ b/remoting/webapp/base/js/auth_init.js
@@ -42,12 +42,14 @@ } } - remoting.identity.getUserInfo().then(function(userInfo) { - onUserInfoAvailable(userInfo.email, userInfo.name); - }).catch(function(error) { - onGetIdentityInfoError( - /** @type {remoting.Error} */ (error)); - }); + remoting.identity.getUserInfo().then( + /** @param {{email:string, name:string}} userInfo */ + function(userInfo) { + onUserInfoAvailable(userInfo.email, userInfo.name); + }).catch(function(error) { + onGetIdentityInfoError( + /** @type {remoting.Error} */ (error)); + }); }; /** @@ -64,4 +66,4 @@ window.location.reload(); } }); -}; \ No newline at end of file +};
diff --git a/remoting/webapp/base/js/base.js b/remoting/webapp/base/js/base.js index bbf2910..35012ea 100644 --- a/remoting/webapp/base/js/base.js +++ b/remoting/webapp/base/js/base.js
@@ -74,6 +74,35 @@ this.disposables_ = Array.prototype.slice.call(arguments, 0); }; +/** + * @param {...base.Disposable} var_args + */ +base.Disposables.prototype.add = function(var_args) { + var disposables = Array.prototype.slice.call(arguments, 0); + for (var i = 0; i < disposables.length; i++) { + var current = /** @type {base.Disposable} */ (disposables[i]); + if (this.disposables_.indexOf(current) === -1) { + this.disposables_.push(current); + } + } +}; + +/** + * @param {...base.Disposable} var_args Dispose |var_args| and remove + * them from the current object. + */ +base.Disposables.prototype.remove = function(var_args) { + var disposables = Array.prototype.slice.call(arguments, 0); + for (var i = 0; i < disposables.length; i++) { + var disposable = /** @type {base.Disposable} */ (disposables[i]); + var index = this.disposables_.indexOf(disposable); + if(index !== -1) { + this.disposables_.splice(index, 1); + disposable.dispose(); + } + } +}; + base.Disposables.prototype.dispose = function() { for (var i = 0; i < this.disposables_.length; i++) { this.disposables_[i].dispose(); @@ -505,7 +534,7 @@ * * @param {base.EventSource} src * @param {string} eventName - * @param {function(...?)} listener + * @param {Function} listener * * @constructor * @implements {base.Disposable} @@ -524,9 +553,9 @@ /** * An event hook implementation for DOM Events. * - * @param {HTMLElement|Element} src + * @param {HTMLElement|Element|Window|HTMLDocument} src * @param {string} eventName - * @param {function(...?)} listener + * @param {Function} listener * @param {boolean} capture * * @constructor @@ -549,7 +578,7 @@ * An event hook implementation for Chrome Events. * * @param {chrome.Event} src - * @param {function(...?)} listener + * @param {Function} listener * * @constructor * @implements {base.Disposable} @@ -564,6 +593,21 @@ this.src_.removeListener(this.listener_); }; +/** + * A disposable repeating timer. + * + * @constructor + * @implements {base.Disposable} + */ +base.RepeatingTimer = function(/** Function */callback, /** number */interval) { + /** @private */ + this.intervalId_ = window.setInterval(callback, interval); +}; + +base.RepeatingTimer.prototype.dispose = function() { + window.clearInterval(this.intervalId_); + this.intervalId_ = null; +}; /** * Converts UTF-8 string to ArrayBuffer.
diff --git a/remoting/webapp/base/js/ipc.js b/remoting/webapp/base/js/ipc.js index a940a28..955d150 100644 --- a/remoting/webapp/base/js/ipc.js +++ b/remoting/webapp/base/js/ipc.js
@@ -89,7 +89,7 @@ /** * @param {string} methodName - * @param {function(...?)} handler The handler can be invoked by calling + * @param {Function} handler The handler can be invoked by calling * base.Ipc.invoke(|methodName|, arg1, arg2, ...) * Async handlers that return promises are currently not supported. * @return {boolean} Whether the handler is successfully registered. @@ -145,8 +145,8 @@ * * @param {string} methodName * @param {...} var_args - * @return A Promise that would resolve to the return value of the handler or - * reject if the handler throws an exception. + * @return {Promise} A Promise that would resolve to the return value of the + * handler or reject if the handler throws an exception. */ base.Ipc.invoke = function(methodName, var_args) { var params = Array.prototype.slice.call(arguments, 1);
diff --git a/remoting/webapp/browser_test/browser_test.js b/remoting/webapp/browser_test/browser_test.js index 88f9ee44..db6078a0 100644 --- a/remoting/webapp/browser_test/browser_test.js +++ b/remoting/webapp/browser_test/browser_test.js
@@ -130,11 +130,14 @@ }; /** - * @param {string} id + * @param {string} id The id or the selector of the element. * @return {void} */ browserTest.clickOnControl = function(id) { var element = document.getElementById(id); + if (!element) { + element = document.querySelector(id); + } browserTest.expect(element, 'No such element: ' + id); element.click(); }; @@ -193,7 +196,7 @@ // The one second timeout is necessary because the click handler of // 'this-host-connect' is registered asynchronously. return base.Promise.sleep(1000).then(function() { - browserTest.clickOnControl('this-host-connect'); + browserTest.clickOnControl('local-host-connect-button'); }).then(function(){ return browserTest.onUIMode(AppMode.CLIENT_HOST_NEEDS_UPGRADE); }).then(function() { @@ -220,7 +223,7 @@ finishedButton = 'client-finished-it2me-button'; } - remoting.disconnect(); + remoting.app.disconnect(); return browserTest.onUIMode(finishedMode).then(function() { browserTest.clickOnControl(finishedButton); @@ -408,11 +411,11 @@ function(started){ if (!started) { console.log('browserTest: Enabling remote connection.'); - browserTest.clickOnControl('start-daemon'); + browserTest.clickOnControl('.start-daemon'); } else { console.log('browserTest: Changing the PIN of the host to: ' + pin + '.'); - browserTest.clickOnControl('change-daemon-pin'); + browserTest.clickOnControl('.change-daemon-pin'); } return browserTest.setupPIN(pin); });
diff --git a/remoting/webapp/browser_test/mock_client_plugin.js b/remoting/webapp/browser_test/mock_client_plugin.js index 09858e0a1..8a8dafa 100644 --- a/remoting/webapp/browser_test/mock_client_plugin.js +++ b/remoting/webapp/browser_test/mock_client_plugin.js
@@ -46,10 +46,9 @@ window.setTimeout(onDone.bind(null, true), 0); }; -remoting.MockClientPlugin.prototype.connect = function( - hostJid, hostPublicKey, localJid, sharedSecret, - authenticationMethods, authenticationTag, - clientPairingId, clientPairedSecret) { + +remoting.MockClientPlugin.prototype.connect = + function(host, localJid, credentialsProvider) { base.debug.assert(this.connectionStatusUpdateHandler_ != null); window.setTimeout( this.connectionStatusUpdateHandler_.bind( @@ -79,16 +78,9 @@ remoting.MockClientPlugin.prototype.sendClipboardItem = function(mimeType, item) {}; -remoting.MockClientPlugin.prototype.useAsyncPinDialog = function() {}; - remoting.MockClientPlugin.prototype.requestPairing = function(clientName, onDone) {}; -remoting.MockClientPlugin.prototype.onPinFetched = function(pin) {}; - -remoting.MockClientPlugin.prototype.onThirdPartyTokenFetched = - function(token, sharedSecret) {}; - remoting.MockClientPlugin.prototype.pauseAudio = function(pause) {}; remoting.MockClientPlugin.prototype.pauseVideo = function(pause) {}; @@ -142,12 +134,6 @@ remoting.MockClientPlugin.prototype.setMouseCursorHandler = function(handler) {}; -remoting.MockClientPlugin.prototype.setFetchThirdPartyTokenHandler = - function(handler) {}; - -remoting.MockClientPlugin.prototype.setFetchPinHandler = - function(handler) {}; - /** * @constructor * @implements {remoting.HostDesktop}
diff --git a/remoting/webapp/browser_test/update_pin_browser_test.js b/remoting/webapp/browser_test/update_pin_browser_test.js index 9646841..8f4e4e8 100644 --- a/remoting/webapp/browser_test/update_pin_browser_test.js +++ b/remoting/webapp/browser_test/update_pin_browser_test.js
@@ -62,6 +62,6 @@ browserTest.Update_PIN.prototype.changePIN_ = function(newPin) { var AppMode = remoting.AppMode; var HOST_RESTART_WAIT = 10000; - browserTest.clickOnControl('change-daemon-pin'); + browserTest.clickOnControl('.change-daemon-pin'); return browserTest.setupPIN(newPin); };
diff --git a/remoting/webapp/crd/html/dialog_hangout_consent.css b/remoting/webapp/crd/html/dialog_hangout_consent.css deleted file mode 100644 index 7bd4378f..0000000 --- a/remoting/webapp/crd/html/dialog_hangout_consent.css +++ /dev/null
@@ -1,103 +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. - */ - -html, div, span, body, ul, li { - border: 0; - margin: 0; - padding: 0; - font-family: "Arial", "Helvetica", sans-serif; - font-weight: normal; - /* Allows the user to move the window by dragging its content. */ - -webkit-app-region: drag; -} - -.header { - height: 46px; - background: #1c91c0; - padding: 15px; -} - -.header .title { - color: white; - float: left; - font-size: 24px; - line-height: 46px; - padding-left: 15px; -} - -.header .logo { - float: left; - height: 46px; - width: 46px; - background: url('chromoting48.webp'); -} - -.content { - text-align: center; - margin: auto; - width: 70%; -} - -.content .message { - padding: 30px; - font-size: 20px; -} - -.content ul { - list-style: none; - border-width: 0px 0px 1px 0px; - border-style: solid; - border-color: #f0f0f0; -} - -.content li { - border-width: 1px 0px 0px 0px; - border-style: solid; - border-color: #f0f0f0; - padding: 15px; - text-align: left; - font-size: 14px; -} - -.button { - padding: 0px 20px; - border: 1px solid #f0f0f0; - border-radius: 5px; - font-size: 14px; - font-weight: bold; - line-height: 36px; - color: #737373; - -webkit-app-region: no-drag; -} - -.footer { - padding-top: 30px; - padding-bottom: 30px; - /* Clear the float of its children. */ - overflow: auto; - width: 100% -} - -.button.default { - background: #427fed; - color: white; -} - -.button:hover { - border-color: #cecece; -} - -.button.default:active { - background: #2c56b1; -} - -.ok-button { - float: right; - margin-left: 10px; -} - -.cancel-button { - float: right; -}
diff --git a/remoting/webapp/crd/html/dialog_hangout_consent.html b/remoting/webapp/crd/html/dialog_hangout_consent.html deleted file mode 100644 index 3ad7ebd..0000000 --- a/remoting/webapp/crd/html/dialog_hangout_consent.html +++ /dev/null
@@ -1,36 +0,0 @@ -<!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> - <head> - <meta charset="utf-8"> - <link rel="stylesheet" href="dialog_hangout_consent.css"> - <script type="text/javascript" src="base.js"></script> - <script type="text/javascript" src="hangout_consent_dialog_main.js"></script> - <script type="text/javascript" src="ipc.js"></script> - <script type="text/javascript" src="l10n.js"></script> - <script type="text/javascript" src="typecheck.js"></script> - </head> - <body> - <div class="header"> - <div class="logo"></div> - <div class="title" i18n-content="MODE_IT2ME"></div> - </div> - <div class="content"> - <div class="message" i18n-content="HANGOUTS_CONFIRM_DIALOG_MESSAGE_1"></div> - <ul> - <li i18n-content="HANGOUTS_CONFIRM_DIALOG_MESSAGE_2"></li> - <li i18n-content="HANGOUTS_CONFIRM_DIALOG_MESSAGE_3"></li> - <li i18n-content="DESCRIPTION_AUTHORIZE" class='auth-message'></li> - </ul> - <div class="footer"> - <div class="button default ok-button" i18n-content="HANGOUTS_CONFIRM_DIALOG_ACCEPT"></div> - <div class="button cancel-button" i18n-content="HANGOUTS_CONFIRM_DIALOG_DECLINE"></div> - </div> - </div> - </body> -</html>
diff --git a/remoting/webapp/crd/html/template_unittest.html b/remoting/webapp/crd/html/template_unittest.html index eb99c5c2..cce27c7 100644 --- a/remoting/webapp/crd/html/template_unittest.html +++ b/remoting/webapp/crd/html/template_unittest.html
@@ -22,6 +22,7 @@ <script src="blanketjs/qunit_adapter.js"></script> <script src="sinonjs/sinon.js"></script> <script src="sinonjs/sinon-qunit.js"></script> + <script src="test_start.js"></script> <!-- product files and unit test files--> <meta-include type="javascript"/>
diff --git a/remoting/webapp/crd/html/ui_me2me.html b/remoting/webapp/crd/html/ui_me2me.html index ca7b835a..e7642d4 100644 --- a/remoting/webapp/crd/html/ui_me2me.html +++ b/remoting/webapp/crd/html/ui_me2me.html
@@ -45,43 +45,41 @@ class="host-list-empty-instructions" hidden> </div> - <div id="daemon-control" data-daemon-state="enabled disabled" hidden> - <div class="section-row no-non-local-hosts" + <div class="daemon-control" + data-daemon-state="enabled disabled enabled-other-account" hidden> + <div class="section-row daemon-disabled" data-daemon-state="disabled"> <img src="icon_host.webp" class="host-list-main-icon"> - <div class="box-spacer host-list-label" - id="start-daemon-message" + <div class="box-spacer" + class="no-daemon-message" i18n-content="HOME_DAEMON_START_MESSAGE"></div> <button type="button" - id="start-daemon" + class="start-daemon" i18n-content="HOME_DAEMON_START_BUTTON"> </button> </div> <!-- disabled --> - <div id="this-host-connect" - class="section-row clickable no-non-local-hosts" - data-daemon-state="enabled"> - <div class="host-list-main-icon"> - <span id="this-host-warning" hidden></span> - <img id="this-host-icon" - src="icon_host.webp"> - </div> - <div id="this-host-name" class="box-spacer"></div> - <span id="this-host-rename" - class="host-list-edit" - tabIndex="0" - i18n-title="TOOLTIP_RENAME"> - <img class="host-list-rename-icon" - src="icon_pencil.webp"> - </span> + <div class="section-row host-enabled-other-account" + data-daemon-state="enabled-other-account"> + <img src="icon_host.webp" class="host-list-main-icon"> + <div class="box-spacer" + i18n-content="HOME_DAEMON_HOST_ENABLED_OTHER_ACCOUNT"></div> <button type="button" - id="stop-daemon" + class="stop-daemon" + i18n-content="HOME_DAEMON_STOP_BUTTON"> + </button> + </div> <!-- enabled-other-account --> + <div id="this-host-connect" + data-daemon-state="enabled"> + <div class="host-entry"></div> + <button type="button" + class="stop-local-daemon" i18n-content="HOME_DAEMON_STOP_BUTTON"> </button> </div> <!-- this-host-connect --> <div data-daemon-state="enabled"> <div> <span i18n-content="HOME_DAEMON_ACTIVE_MESSAGE"></span> - <a id="change-daemon-pin" + <a class="change-daemon-pin" href="#" i18n-content="HOME_DAEMON_CHANGE_PIN_LINK"></a> </div>
diff --git a/remoting/webapp/crd/js/apps_v2_migration.js b/remoting/webapp/crd/js/apps_v2_migration.js index 3f49883f..aab9994 100644 --- a/remoting/webapp/crd/js/apps_v2_migration.js +++ b/remoting/webapp/crd/js/apps_v2_migration.js
@@ -22,9 +22,9 @@ var MIGRATION_KEY_ = 'remoting-v2-migration'; /** - * @constructor * @param {string} email * @param {string} fullName + * @constructor */ remoting.MigrationSettings = function(email, fullName) { this.email = email; @@ -88,16 +88,14 @@ if (base.isAppsV2()) { chrome.storage.local.remove(MIGRATION_KEY_); } else { - /** - * @param {string} email - * @param {string} fullName - */ - remoting.identity.getUserInfo().then(function(userInfo) { - var preference = {}; - preference[MIGRATION_KEY_] = - new remoting.MigrationSettings(userInfo.email, userInfo.name); - chrome.storage.local.set(preference); - }).catch(base.doNothing); + remoting.identity.getUserInfo().then( + /** @param {{email:string, name:string}} userInfo */ + function(userInfo) { + var preference = {}; + preference[MIGRATION_KEY_] = + new remoting.MigrationSettings(userInfo.email, userInfo.name); + chrome.storage.local.set(preference); + }).catch(base.doNothing); } };
diff --git a/remoting/webapp/crd/js/background.js b/remoting/webapp/crd/js/background.js index 96f2833d..12bc56f6 100644 --- a/remoting/webapp/crd/js/background.js +++ b/remoting/webapp/crd/js/background.js
@@ -9,8 +9,6 @@ 'use strict'; -var ENABLE_HANGOUT_REMOTE_ASSISTANCE = true; - /** * @constructor */ @@ -19,16 +17,7 @@ this.appLauncher_ = null; /** @private {remoting.ActivationHandler} */ this.activationHandler_ = null; - /** @private {remoting.It2MeService} */ - this.it2meService_ = null; - /** @private {base.Disposables} */ - this.disposables_ = null; - this.preInit_(); - this.onResumed_(); - - chrome.runtime.onSuspendCanceled.addListener(this.onResumed_.bind(this)); - chrome.runtime.onSuspend.addListener(this.onSuspended_.bind(this)); }; /** @@ -56,21 +45,6 @@ } }; -/** @private */ -BackgroundPage.prototype.onResumed_ = function() { - if (ENABLE_HANGOUT_REMOTE_ASSISTANCE) { - this.it2meService_ = new remoting.It2MeService(this.appLauncher_); - this.it2meService_.init(); - this.disposables_ = new base.Disposables(this.it2meService_); - } -}; - -/** @private */ -BackgroundPage.prototype.onSuspended_ = function() { - this.it2meService_ = null; - base.dispose(this.disposables_); - this.disposables_ = null; -}; window.addEventListener('load', function() { remoting.backgroundPage = new BackgroundPage();
diff --git a/remoting/webapp/crd/js/butter_bar.js b/remoting/webapp/crd/js/butter_bar.js index 3334c7f..b63db1f 100644 --- a/remoting/webapp/crd/js/butter_bar.js +++ b/remoting/webapp/crd/js/butter_bar.js
@@ -19,20 +19,9 @@ remoting.ButterBar = function() { this.storageKey_ = ''; - /** @type{remoting.ButterBar} */ - var that = this; - - /** @param {Object} syncValues */ - var onSyncDataLoaded = function(syncValues) { - chrome.storage.local.get( - remoting.kIT2MeVisitedStorageKey, - that.onStateLoaded_.bind(that, syncValues)); - }; - chrome.storage.sync.get( - [remoting.ButterBar.kSurveyStorageKey_, - remoting.ButterBar.kHangoutsStorageKey_], - onSyncDataLoaded); + [remoting.ButterBar.kSurveyStorageKey_], + this.onStateLoaded_.bind(this)); } /** @@ -63,42 +52,16 @@ /** * @param {Object} syncValues - * @param {Object} localValues * @private */ -remoting.ButterBar.prototype.onStateLoaded_ = - function(syncValues, localValues) { +remoting.ButterBar.prototype.onStateLoaded_ = function(syncValues) { /** @type {boolean} */ var surveyDismissed = !!syncValues[remoting.ButterBar.kSurveyStorageKey_]; - /** @type {boolean} */ - var hangoutsDismissed = - !!syncValues[remoting.ButterBar.kHangoutsStorageKey_]; - /** @type {boolean} */ - var it2meExpanded = !!localValues[remoting.kIT2MeVisitedStorageKey]; - var showSurvey = !surveyDismissed; - var showHangouts = it2meExpanded && !hangoutsDismissed; - - // If both messages can be shown choose only one randomly. - if (showSurvey && showHangouts) { - if (Math.random() > 0.5) { - showSurvey = false; - } else { - showHangouts = false; - } - } - - if (showSurvey) { + if (!surveyDismissed) { this.show_(/*i18n-content*/'SURVEY_INVITATION', ['<a href="http://goo.gl/njH2q" target="_blank">', '</a>'], remoting.ButterBar.kSurveyStorageKey_); - } else if (showHangouts) { - this.show_(/*i18n-content*/'HANGOUTS_INVITATION', - ['<a id="hangouts-accept" ' + - 'href="https://plus.google.com/hangouts/_?gid=818572447316" ' + - 'target="_blank">', - '</a>'], - remoting.ButterBar.kHangoutsStorageKey_); } }; @@ -112,8 +75,6 @@ /** @const @private */ remoting.ButterBar.kSurveyStorageKey_ = 'feedback-survey-dismissed'; -/** @const @private */ -remoting.ButterBar.kHangoutsStorageKey_ = 'hangouts-notice-dismissed'; /** * Hide the butter bar request and record some basic information about the
diff --git a/remoting/webapp/crd/js/client_plugin.js b/remoting/webapp/crd/js/client_plugin.js index a7fdd34..cf4360d 100644 --- a/remoting/webapp/crd/js/client_plugin.js +++ b/remoting/webapp/crd/js/client_plugin.js
@@ -34,25 +34,12 @@ remoting.ClientPlugin.prototype.initialize = function(onDone) {}; /** - * @param {string} hostJid The jid of the host to connect to. - * @param {string} hostPublicKey The base64 encoded version of the host's - * public key. + * @param {remoting.Host} host The host to connect to. * @param {string} localJid Local jid. - * @param {string} sharedSecret The access code for IT2Me or the PIN - * for Me2Me. - * @param {string} authenticationMethods Comma-separated list of - * authentication methods the client should attempt to use. - * @param {string} authenticationTag A host-specific tag to mix into - * authentication hashes. - * @param {string} clientPairingId For paired Me2Me connections, the - * pairing id for this client, as issued by the host. - * @param {string} clientPairedSecret For paired Me2Me connections, the - * paired secret for this client, as issued by the host. + * @param {remoting.CredentialsProvider} credentialsProvider */ -remoting.ClientPlugin.prototype.connect = function( - hostJid, hostPublicKey, localJid, sharedSecret, - authenticationMethods, authenticationTag, - clientPairingId, clientPairedSecret) {}; +remoting.ClientPlugin.prototype.connect = + function(host, localJid, credentialsProvider) {}; /** * @param {number} key The keycode to inject. @@ -98,11 +85,6 @@ function(mimeType, item) {}; /** - * Tell the plugin to request a PIN asynchronously. - */ -remoting.ClientPlugin.prototype.useAsyncPinDialog = function() {}; - -/** * Request that this client be paired with the current host. * * @param {string} clientName The human-readable name of the client. @@ -113,27 +95,11 @@ function(clientName, onDone) {}; /** - * Called when a PIN is obtained from the user. - * - * @param {string} pin The PIN. - */ -remoting.ClientPlugin.prototype.onPinFetched = function(pin) {}; - -/** * Allows automatic mouse-lock. */ remoting.ClientPlugin.prototype.allowMouseLock = function() {}; /** - * Sets the third party authentication token and shared secret. - * - * @param {string} token The token received from the token URL. - * @param {string} sharedSecret Shared secret received from the token URL. - */ -remoting.ClientPlugin.prototype.onThirdPartyTokenFetched = - function(token, sharedSecret) {}; - -/** * @param {boolean} pause True to pause the audio stream; false to resume it. */ remoting.ClientPlugin.prototype.pauseAudio = function(pause) {}; @@ -223,23 +189,6 @@ function(handler) {}; /** - * @param {function(string, string, string):void} handler Callback for - * fetching third-party tokens. The first parameter is the token URL; the - * second is the public key of the host; the third is the OAuth2 scope - * being requested. - */ -remoting.ClientPlugin.prototype.setFetchThirdPartyTokenHandler = - function(handler) {}; - -/** - * @param {function(boolean):void} handler Callback for fetching a PIN from - * the user. The parameter is true if PIN pairing is supported by the - * host, or false otherwise. - */ -remoting.ClientPlugin.prototype.setFetchPinHandler = - function(handler) {}; - -/** * @param {function({rects:Array<Array<number>>}):void|null} handler Callback * to receive dirty region information for each video frame, for debugging. */
diff --git a/remoting/webapp/crd/js/client_plugin_impl.js b/remoting/webapp/crd/js/client_plugin_impl.js index 2d3efe0..1528c8c7 100644 --- a/remoting/webapp/crd/js/client_plugin_impl.js +++ b/remoting/webapp/crd/js/client_plugin_impl.js
@@ -77,22 +77,11 @@ * @private */ this.onConnectionReadyHandler_ = function(ready) {}; - - /** - * @param {string} tokenUrl Token-request URL, received from the host. - * @param {string} hostPublicKey Public key for the host. - * @param {string} scope OAuth scope to request the token for. - * @private - */ - this.fetchThirdPartyTokenHandler_ = function( - tokenUrl, hostPublicKey, scope) {}; /** * @param {!Array<string>} capabilities The negotiated capabilities. * @private */ this.onSetCapabilitiesHandler_ = function (capabilities) {}; - /** @private */ - this.fetchPinHandler_ = function (supportsPairing) {}; /** * @param {string} data Remote gnubbyd data. * @private @@ -168,6 +157,9 @@ this.hostDesktop_ = new remoting.ClientPlugin.HostDesktopImpl( this, this.postMessage_.bind(this)); + + /** @private {remoting.CredentialsProvider} */ + this.credentials_ = null; }; /** @@ -282,21 +274,6 @@ }; /** - * @param {function(string, string, string):void} handler - */ -remoting.ClientPluginImpl.prototype.setFetchThirdPartyTokenHandler = - function(handler) { - this.fetchThirdPartyTokenHandler_ = handler; -}; - -/** - * @param {function(boolean):void} handler - */ -remoting.ClientPluginImpl.prototype.setFetchPinHandler = function(handler) { - this.fetchPinHandler_ = handler; -}; - -/** * @param {?function({rects:Array<Array<number>>}):void} handler */ remoting.ClientPluginImpl.prototype.setDebugDirtyRegionHandler = @@ -436,9 +413,10 @@ // client and host support pairing. If the client doesn't support pairing, // then the value won't be there at all, so give it a default of false. var pairingSupported = getBooleanAttr(message.data, 'pairingSupported', - false) - this.fetchPinHandler_(pairingSupported); - + false); + this.credentials_.getPIN(pairingSupported).then( + this.onPinFetched_.bind(this) + ); } else if (message.method == 'setCapabilities') { /** @type {!Array<string>} */ var capabilities = tokenize(getStringAttr(message.data, 'capabilities')); @@ -448,8 +426,9 @@ var tokenUrl = getStringAttr(message.data, 'tokenUrl'); var hostPublicKey = getStringAttr(message.data, 'hostPublicKey'); var scope = getStringAttr(message.data, 'scope'); - this.fetchThirdPartyTokenHandler_(tokenUrl, hostPublicKey, scope); - + this.credentials_.getThirdPartyToken(tokenUrl, hostPublicKey, scope).then( + this.onThirdPartyTokenFetched_.bind(this) + ); } else if (message.method == 'pairingResponse') { var clientId = getStringAttr(message.data, 'clientId'); var sharedSecret = getStringAttr(message.data, 'sharedSecret'); @@ -590,50 +569,39 @@ }; /** - * @param {string} hostJid The jid of the host to connect to. - * @param {string} hostPublicKey The base64 encoded version of the host's - * public key. + * @param {remoting.Host} host The host to connect to. * @param {string} localJid Local jid. - * @param {string} sharedSecret The access code for IT2Me or the PIN - * for Me2Me. - * @param {string} authenticationMethods Comma-separated list of - * authentication methods the client should attempt to use. - * @param {string} authenticationTag A host-specific tag to mix into - * authentication hashes. - * @param {string} clientPairingId For paired Me2Me connections, the - * pairing id for this client, as issued by the host. - * @param {string} clientPairedSecret For paired Me2Me connections, the - * paired secret for this client, as issued by the host. + * @param {remoting.CredentialsProvider} credentialsProvider */ -remoting.ClientPluginImpl.prototype.connect = function( - hostJid, hostPublicKey, localJid, sharedSecret, - authenticationMethods, authenticationTag, - clientPairingId, clientPairedSecret) { +remoting.ClientPluginImpl.prototype.connect = + function(host, localJid, credentialsProvider) { var keyFilter = ''; if (remoting.platformIsMac()) { keyFilter = 'mac'; } else if (remoting.platformIsChromeOS()) { keyFilter = 'cros'; } - // Use PPB_VideoDecoder API only in Chrome 42 and above. It is broken in - // previous versions of Chrome, see http://crbug.com/447403 . - // Currently PPAPI doesn't provide a way for plugins to check the Chrome - // version, so this check needs to be in the webapp. + + // Use PPB_VideoDecoder API only in Chrome 43 and above. It is broken in + // previous versions of Chrome, see crbug.com/459103 and crbug.com/463577 . var enableVideoDecodeRenderer = - parseInt((remoting.getChromeVersion() || '0').split('.')[0], 10) >= 42; + parseInt((remoting.getChromeVersion() || '0').split('.')[0], 10) >= 43; this.plugin_.postMessage(JSON.stringify( { method: 'delegateLargeCursors', data: {} })); + var methods = 'third_party,spake2_pair,spake2_hmac,spake2_plain'; + this.credentials_ = credentialsProvider; + this.useAsyncPinDialog_(); this.plugin_.postMessage(JSON.stringify( { method: 'connect', data: { - hostJid: hostJid, - hostPublicKey: hostPublicKey, + hostJid: host.jabberId, + hostPublicKey: host.publicKey, localJid: localJid, - sharedSecret: sharedSecret, - authenticationMethods: authenticationMethods, - authenticationTag: authenticationTag, + sharedSecret: '', + authenticationMethods: methods, + authenticationTag: host.hostId, capabilities: this.capabilities_.join(" "), - clientPairingId: clientPairingId, - clientPairedSecret: clientPairedSecret, + clientPairingId: credentialsProvider.getPairingInfo().id, + clientPairedSecret: credentialsProvider.getPairingInfo().secret, keyFilter: keyFilter, enableVideoDecodeRenderer: enableVideoDecodeRenderer } @@ -790,8 +758,9 @@ * Called when a PIN is obtained from the user. * * @param {string} pin The PIN. + * @private */ -remoting.ClientPluginImpl.prototype.onPinFetched = +remoting.ClientPluginImpl.prototype.onPinFetched_ = function(pin) { if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) { return; @@ -802,8 +771,9 @@ /** * Tells the plugin to ask for the PIN asynchronously. + * @private */ -remoting.ClientPluginImpl.prototype.useAsyncPinDialog = +remoting.ClientPluginImpl.prototype.useAsyncPinDialog_ = function() { if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) { return; @@ -823,14 +793,14 @@ /** * Sets the third party authentication token and shared secret. * - * @param {string} token The token received from the token URL. - * @param {string} sharedSecret Shared secret received from the token URL. + * @param {remoting.ThirdPartyToken} token + * @private */ -remoting.ClientPluginImpl.prototype.onThirdPartyTokenFetched = function( - token, sharedSecret) { +remoting.ClientPluginImpl.prototype.onThirdPartyTokenFetched_ = function( + token) { this.plugin_.postMessage(JSON.stringify( { method: 'onThirdPartyTokenFetched', - data: { token: token, sharedSecret: sharedSecret}})); + data: { token: token.token, sharedSecret: token.secret}})); }; /**
diff --git a/remoting/webapp/crd/js/client_screen.js b/remoting/webapp/crd/js/client_screen.js deleted file mode 100644 index 1700c70..0000000 --- a/remoting/webapp/crd/js/client_screen.js +++ /dev/null
@@ -1,123 +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. - -/** - * @fileoverview - * Functions related to the 'client screen' for Chromoting. - */ - -'use strict'; - -/** @suppress {duplicate} */ -var remoting = remoting || {}; - -/** - * @type {remoting.ClientSession} The client session object, set once the - * connector has invoked its onOk callback. - */ -remoting.clientSession = null; - -/** - * @type {remoting.DesktopConnectedView} The client session object, set once the - * connector has invoked its onOk callback. - */ -remoting.desktopConnectedView = null; - -/** - * Update the remoting client layout in response to a resize event. - * - * @return {void} Nothing. - */ -remoting.onResize = function() { - if (remoting.desktopConnectedView) { - remoting.desktopConnectedView.onResize(); - } -}; - -/** - * Handle changes in the visibility of the window, for example by pausing video. - * - * @return {void} Nothing. - */ -remoting.onVisibilityChanged = function() { - if (remoting.desktopConnectedView) { - remoting.desktopConnectedView.pauseVideo( - ('hidden' in document) ? document.hidden : document.webkitHidden); - } -}; - -/** - * Disconnect the remoting client. - * - * @return {void} Nothing. - */ -remoting.disconnect = function() { - if (!remoting.clientSession) { - return; - } - remoting.clientSession.disconnect(remoting.Error.NONE); - console.log('Disconnected.'); -}; - -/** - * Callback function called when the state of the client plugin changes. The - * current and previous states are available via the |state| member variable. - * - * @param {remoting.ClientSession.StateEvent=} state - */ -function onClientStateChange_(state) { - switch (state.current) { - case remoting.ClientSession.State.CLOSED: - console.log('Connection closed by host'); - if (remoting.desktopConnectedView.getMode() == - remoting.DesktopConnectedView.Mode.IT2ME) { - remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_IT2ME); - remoting.hangoutSessionEvents.raiseEvent( - remoting.hangoutSessionEvents.sessionStateChanged, - remoting.ClientSession.State.CLOSED); - } else { - remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME); - } - remoting.app.onDisconnected(); - break; - - case remoting.ClientSession.State.FAILED: - var error = remoting.clientSession.getError(); - console.error('Client plugin reported connection failed: ' + error); - if (error == null) { - error = remoting.Error.UNEXPECTED; - } - remoting.app.onError(error); - break; - - default: - console.error('Unexpected client plugin state: ' + state.current); - // This should only happen if the web-app and client plugin get out of - // sync, so MISSING_PLUGIN is a suitable error. - remoting.app.onError(remoting.Error.MISSING_PLUGIN); - break; - } - - remoting.clientSession.removeEventListener('stateChanged', - onClientStateChange_); - remoting.clientSession.cleanup(); - remoting.clientSession = null; - remoting.desktopConnectedView = null; -} - -/** - * Timer callback to update the statistics panel. - */ -function updateStatistics_() { - if (!remoting.clientSession || - remoting.clientSession.getState() != - remoting.ClientSession.State.CONNECTED) { - return; - } - var perfstats = remoting.clientSession.getPerfStats(); - remoting.stats.update(perfstats); - remoting.clientSession.logStatistics(perfstats); - // Update the stats once per second. - window.setTimeout(updateStatistics_, 1000); -}
diff --git a/remoting/webapp/crd/js/client_session.js b/remoting/webapp/crd/js/client_session.js index dc2a2a9..4fa47c9 100644 --- a/remoting/webapp/crd/js/client_session.js +++ b/remoting/webapp/crd/js/client_session.js
@@ -34,31 +34,18 @@ /** * @param {remoting.Host} host The host to connect to. * @param {remoting.SignalStrategy} signalStrategy Signal strategy. + * @param {remoting.CredentialsProvider} credentialsProvider + * The credentialsProvider to authenticate the client with the host. * @param {HTMLElement} container Container element for the client view. - * @param {string} accessCode The IT2Me access code. Blank for Me2Me. - * @param {function(boolean, function(string): void): void} fetchPin - * Called by Me2Me connections when a PIN needs to be obtained - * interactively. - * @param {function(string, string, string, - * function(string, string): void): void} - * fetchThirdPartyToken Called by Me2Me connections when a third party - * authentication token must be obtained. - * @param {string} authenticationMethods Comma-separated list of - * authentication methods the client should attempt to use. * @param {remoting.DesktopConnectedView.Mode} mode The mode of this connection. - * @param {string} clientPairingId For paired Me2Me connections, the - * pairing id for this client, as issued by the host. - * @param {string} clientPairedSecret For paired Me2Me connections, the - * paired secret for this client, as issued by the host. * @param {string} defaultRemapKeys The default set of remap keys, to use * when the client doesn't define any. * @constructor * @extends {base.EventSourceImpl} + * @implements {base.Disposable} */ -remoting.ClientSession = function(host, signalStrategy, container, accessCode, - fetchPin, fetchThirdPartyToken, - authenticationMethods, mode, clientPairingId, - clientPairedSecret, defaultRemapKeys) { +remoting.ClientSession = function(host, signalStrategy, credentialsProvider, + container, mode, defaultRemapKeys) { /** @private */ this.state_ = remoting.ClientSession.State.CREATED; @@ -67,18 +54,9 @@ /** @private */ this.host_ = host; + /** @private */ - this.accessCode_ = accessCode; - /** @private */ - this.fetchPin_ = fetchPin; - /** @private */ - this.fetchThirdPartyToken_ = fetchThirdPartyToken; - /** @private */ - this.authenticationMethods_ = authenticationMethods; - /** @private */ - this.clientPairingId_ = clientPairingId; - /** @private */ - this.clientPairedSecret_ = clientPairedSecret; + this.credentialsProvider_ = credentialsProvider; /** @private */ this.uiHandler_ = new remoting.DesktopConnectedView( @@ -310,7 +288,8 @@ plugin.setCastExtensionHandler( this.processCastExtensionMessage_.bind(this)); - this.initiateConnection_(); + this.plugin_.connect( + this.host_, this.signalStrategy_.getJid(), this.credentialsProvider_); }; /** @@ -321,7 +300,7 @@ this.removePlugin(); this.error_ = error; this.setState_(remoting.ClientSession.State.FAILED); -} +}; /** * Deletes the <embed> element from the container, without sending a @@ -333,12 +312,13 @@ remoting.ClientSession.prototype.removePlugin = function() { this.uiHandler_.removePlugin(); this.plugin_ = null; + remoting.desktopConnectedView = null; }; /** * Disconnect the current session with a particular |error|. The session will * raise a |stateChanged| event in response to it. The caller should then call - * |cleanup| to remove and destroy the <embed> element. + * dispose() to remove and destroy the <embed> element. * * @param {remoting.Error} error The reason for the disconnection. Use * remoting.Error.NONE if there is no error. @@ -361,7 +341,7 @@ * * @return {void} Nothing. */ -remoting.ClientSession.prototype.cleanup = function() { +remoting.ClientSession.prototype.dispose = function() { this.sendIq_( '<cli:iq ' + 'to="' + this.host_.jabberId + '" ' + @@ -460,64 +440,6 @@ }; /** - * @private - */ -remoting.ClientSession.prototype.initiateConnection_ = function() { - /** @type {remoting.ClientSession} */ - var that = this; - - /** @param {string} sharedSecret Shared secret. */ - function onSharedSecretReceived(sharedSecret) { - that.plugin_.connect(that.host_.jabberId, that.host_.publicKey, - that.signalStrategy_.getJid(), sharedSecret, - that.authenticationMethods_, that.host_.hostId, - that.clientPairingId_, that.clientPairedSecret_); - } - - this.getSharedSecret_(onSharedSecretReceived); -}; - -/** - * Gets shared secret to be used for connection. - * - * @param {function(string)} callback Callback called with the shared secret. - * @return {void} Nothing. - * @private - */ -remoting.ClientSession.prototype.getSharedSecret_ = function(callback) { - /** @type remoting.ClientSession */ - var that = this; - if (this.plugin_.hasFeature(remoting.ClientPlugin.Feature.THIRD_PARTY_AUTH)) { - /** @type{function(string, string, string): void} */ - var fetchThirdPartyToken = function(tokenUrl, hostPublicKey, scope) { - that.fetchThirdPartyToken_( - tokenUrl, hostPublicKey, scope, - that.plugin_.onThirdPartyTokenFetched.bind(that.plugin_)); - }; - this.plugin_.setFetchThirdPartyTokenHandler(fetchThirdPartyToken); - } - if (this.accessCode_) { - // Shared secret was already supplied before connecting (It2Me case). - callback(this.accessCode_); - } else if (this.plugin_.hasFeature( - remoting.ClientPlugin.Feature.ASYNC_PIN)) { - // Plugin supports asynchronously asking for the PIN. - this.plugin_.useAsyncPinDialog(); - /** @param {boolean} pairingSupported */ - var fetchPin = function(pairingSupported) { - that.fetchPin_(pairingSupported, - that.plugin_.onPinFetched.bind(that.plugin_)); - }; - this.plugin_.setFetchPinHandler(fetchPin); - callback(''); - } else { - // Clients that don't support asking for a PIN asynchronously also don't - // support pairing, so request the PIN now without offering to remember it. - this.fetchPin_(false, callback); - } -}; - -/** * Callback that the plugin invokes to indicate that the connection * status has changed. *
diff --git a/remoting/webapp/crd/js/crd_event_handlers.js b/remoting/webapp/crd/js/crd_event_handlers.js index b730db4..fb96ee0 100644 --- a/remoting/webapp/crd/js/crd_event_handlers.js +++ b/remoting/webapp/crd/js/crd_event_handlers.js
@@ -37,11 +37,6 @@ remoting.setMode(remoting.AppMode.CLIENT_CONNECTING); remoting.app.getSessionConnector().reconnect(); }; - /** @param {Event} event The event. */ - var stopDaemon = function(event) { - remoting.hostSetupDialog.showForStop(); - event.stopPropagation(); - }; var cancelAccessCode = function() { remoting.setMode(remoting.AppMode.HOME); document.getElementById('access-code-entry').value = ''; @@ -60,16 +55,11 @@ ]; /** @type {Array<{event: string, id: string, fn: function(Event):void}>} */ var me2me_actions = [ - { event: 'click', id: 'change-daemon-pin', - fn: function() { remoting.hostSetupDialog.showForPin(); } }, { event: 'click', id: 'client-finished-me2me-button', fn: goHome }, { event: 'click', id: 'client-reconnect-button', fn: reconnect }, { event: 'click', id: 'daemon-pin-cancel', fn: goHome }, { event: 'click', id: 'get-started-me2me', - fn: remoting.showMe2MeUiAndSave }, - { event: 'click', id: 'start-daemon', - fn: function() { remoting.hostSetupDialog.showForStart(); } }, - { event: 'click', id: 'stop-daemon', fn: stopDaemon } + fn: remoting.showMe2MeUiAndSave } ]; /** @type {Array<{event: string, id: string, fn: function(Event):void}>} */ var host_actions = [
diff --git a/remoting/webapp/crd/js/crd_main.js b/remoting/webapp/crd/js/crd_main.js index 1fdc7a2..18defc6 100644 --- a/remoting/webapp/crd/js/crd_main.js +++ b/remoting/webapp/crd/js/crd_main.js
@@ -11,6 +11,7 @@ * Initialize the host list. */ remoting.initHostlist_ = function() { + remoting.hostController = new remoting.HostController(); remoting.hostList = new remoting.HostList( document.getElementById('host-list'), document.getElementById('host-list-empty'), @@ -62,22 +63,6 @@ var hostId = urlParams['hostId']; remoting.connectMe2Me(hostId); return; - } else if (urlParams['mode'] === 'hangout') { - getCurrentId().then( - /** @param {*} id */ - function(id) { - /** @type {string} */ - var accessCode = urlParams['accessCode']; - var connector = remoting.app.getSessionConnector(); - remoting.setMode(remoting.AppMode.CLIENT_CONNECTING); - 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. @@ -104,10 +89,7 @@ * 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');
diff --git a/remoting/webapp/crd/js/credentials_provider.js b/remoting/webapp/crd/js/credentials_provider.js new file mode 100644 index 0000000..b1d9e20 --- /dev/null +++ b/remoting/webapp/crd/js/credentials_provider.js
@@ -0,0 +1,100 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +var remoting = remoting || {}; + +/** @typedef {{id: string, secret: string}} */ +remoting.PairingInfo; + +/** @typedef {{token: string, secret: string}} */ +remoting.ThirdPartyToken; + +/** + * Parameters for the remoting.CredentialsProvider constructor. + * + * fetchPin: Called by Me2Me connections when a PIN needs to be obtained + * interactively. + * + * pairingInfo: The pairing info for Me2Me Connections. + * + * accessCode: It2Me access code. If present, the |fetchPin| callback will be + * ignored. + * + * fetchThirdPartyToken: Called when a third party authentication token + * is needed + * + * @typedef {{ + * accessCode: (string|undefined), + * fetchPin: (function(boolean,function(string): void)|undefined), + * pairingInfo: (remoting.PairingInfo|undefined), + * fetchThirdPartyToken: + * (function(string ,string , string, + * function(string, string):void) | undefined) + * }} + */ +remoting.CredentialsProviderParams; + +/** + * @param {remoting.CredentialsProviderParams} args + * @constructor + */ +remoting.CredentialsProvider = function(args) { + /** @private */ + this.fetchPin_ = (args.accessCode) ? this.getAccessCode_ : args.fetchPin; + /** @private */ + this.pairingInfo_ = args.pairingInfo; + /** @private */ + this.accessCode_ = args.accessCode; + /** @private */ + this.fetchThirdPartyToken_ = args.fetchThirdPartyToken; +}; + +/** @returns {void} */ +remoting.CredentialsProvider.prototype.getAccessCode_ = function( + /** boolean */ supportsPairing, /** Function */ callback) { + callback(this.accessCode_); +}; + +/** @returns {remoting.PairingInfo} */ +remoting.CredentialsProvider.prototype.getPairingInfo = function() { + return this.pairingInfo_ || { id: '', secret: ''}; +}; + +/** + * @param {boolean} pairingSupported Whether pairing is supported by the host. + * @returns {Promise<string>} + */ +remoting.CredentialsProvider.prototype.getPIN = function(pairingSupported) { + var that = this; + if (!this.fetchPin_) { + Promise.resolve(''); + } + return new Promise(function(/** function(string) */ resolve) { + that.fetchPin_(pairingSupported, resolve); + }); +}; + +/** + * @param {string} tokenUrl Token-issue URL received from the host. + * @param {string} hostPublicKey Host public key (DER and Base64 encoded). + * @param {string} scope OAuth scope to request the token for. + * + * @returns {Promise<remoting.ThirdPartyToken>} + */ +remoting.CredentialsProvider.prototype.getThirdPartyToken = function( + tokenUrl, hostPublicKey, scope) { + var that = this; + if (!this.fetchThirdPartyToken_) { + Promise.resolve({token: '', secret: ''}); + } + return new Promise(function(/** Function */ resolve) { + var onTokenFetched = function(/** string */ token, /** string */ secret) { + resolve({token: token, secret: secret}); + }; + that.fetchThirdPartyToken_(tokenUrl, hostPublicKey, scope, onTokenFetched); + }); +}; +
diff --git a/remoting/webapp/crd/js/desktop_connected_view.js b/remoting/webapp/crd/js/desktop_connected_view.js index dde6821..b40b63d 100644 --- a/remoting/webapp/crd/js/desktop_connected_view.js +++ b/remoting/webapp/crd/js/desktop_connected_view.js
@@ -60,9 +60,6 @@ */ this.onInitialized_ = onInitialized; - /** @type {function(boolean=):void} @private */ - this.callOnFullScreenChanged_ = this.onFullScreenChanged_.bind(this) - /** @private */ this.callPluginLostFocus_ = this.pluginLostFocus_.bind(this); /** @private */ @@ -88,6 +85,9 @@ /** @type {remoting.VideoFrameRecorder} @private */ this.videoFrameRecorder_ = null; + + /** private {base.Disposable} */ + this.eventHooks_ = null; }; // The mode of this session. @@ -222,14 +222,23 @@ * This is a callback that gets called when the window is resized. * * @return {void} Nothing. + * @private. */ -remoting.DesktopConnectedView.prototype.onResize = function() { +remoting.DesktopConnectedView.prototype.onResize_ = function() { if (this.viewport_) { this.viewport_.onResize(); } }; /** + * Called when the app window is hidden. + * @return {void} Nothing. + */ +remoting.DesktopConnectedView.prototype.onVisibilityChanged_ = function() { + this.pauseVideo(document.hidden); +}; + +/** * Callback that the plugin invokes to indicate when the connection is * ready. * @@ -269,7 +278,7 @@ */ remoting.DesktopConnectedView.prototype.updateClientSessionUi_ = function( clientSession) { - if (clientSession == null) { + if (clientSession === null) { if (remoting.windowFrame) { remoting.windowFrame.setDesktopConnectedView(null); } @@ -283,9 +292,8 @@ document.body.classList.remove('connected'); this.container_.removeEventListener( 'mousemove', this.updateMouseCursorPosition_, true); - // Stop listening for full-screen events. - remoting.fullscreen.removeListener(this.callOnFullScreenChanged_); - + base.dispose(this.eventHooks_); + this.eventHooks_ = null; base.dispose(this.viewport_); this.viewport_ = null; } else { @@ -307,11 +315,15 @@ document.body.classList.add('connected'); this.container_.addEventListener( 'mousemove', this.updateMouseCursorPosition_, true); - // Activate full-screen related UX. - remoting.fullscreen.addListener(this.callOnFullScreenChanged_); - this.onFullScreenChanged_(remoting.fullscreen.isActive()); this.setFocusHandlers_(); + this.eventHooks_ = new base.Disposables( + new base.DomEventHook(window, 'resize', this.onResize_.bind(this), false), + new base.DomEventHook(document, 'visibilitychange', + this.onVisibilityChanged_.bind(this), false), + new remoting.Fullscreen.EventHook(this.onFullScreenChanged_.bind(this)) + ); + this.onFullScreenChanged_(remoting.fullscreen.isActive()); } }; @@ -356,6 +368,12 @@ remoting.DesktopConnectedView.prototype.onFullScreenChanged_ = function ( fullscreen) { if (this.viewport_) { + // When a window goes full-screen, a resize event is triggered, but the + // Fullscreen.isActive call is not guaranteed to return true until the + // full-screen event is triggered. In apps v2, the size of the window's + // client area is calculated differently in full-screen mode, so register + // for both events. + this.viewport_.onResize(); this.viewport_.enableBumpScroll(Boolean(fullscreen)); } }; @@ -582,4 +600,4 @@ this.debugRegionContainer_.appendChild(rect); } } -} +};
diff --git a/remoting/webapp/crd/js/desktop_remoting.js b/remoting/webapp/crd/js/desktop_remoting.js index a1838d4..01da99b 100644 --- a/remoting/webapp/crd/js/desktop_remoting.js +++ b/remoting/webapp/crd/js/desktop_remoting.js
@@ -97,17 +97,10 @@ remoting.optionsMenu = remoting.toolbar.createOptionsMenu(); window.addEventListener('beforeunload', remoting.promptClose, false); - window.addEventListener('unload', remoting.disconnect, false); + window.addEventListener('unload', + remoting.app.disconnect.bind(remoting.app), false); } - // When a window goes full-screen, a resize event is triggered, but the - // Fullscreen.isActive call is not guaranteed to return true until the - // full-screen event is triggered. In apps v2, the size of the window's - // client area is calculated differently in full-screen mode, so register - // for both events. - window.addEventListener('resize', remoting.onResize, false); - remoting.fullscreen.addListener(remoting.onResize); - remoting.initHostlist_(); var homeFeedback = new remoting.MenuButton( @@ -233,6 +226,12 @@ * @return {void} Nothing. */ remoting.DesktopRemoting.prototype.handleDisconnected = function() { + if (remoting.desktopConnectedView.getMode() == + remoting.DesktopConnectedView.Mode.IT2ME) { + remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_IT2ME); + } else { + remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME); + } }; /** @@ -314,10 +313,6 @@ : this.app_.getSessionConnector().getConnectionMode(); if (mode == remoting.DesktopConnectedView.Mode.IT2ME) { remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED_IT2ME); - remoting.hangoutSessionEvents.raiseEvent( - remoting.hangoutSessionEvents.sessionStateChanged, - remoting.ClientSession.State.FAILED - ); } else { remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED_ME2ME); }
diff --git a/remoting/webapp/crd/js/fallback_signal_strategy.js b/remoting/webapp/crd/js/fallback_signal_strategy.js index 030bfb42..f250144 100644 --- a/remoting/webapp/crd/js/fallback_signal_strategy.js +++ b/remoting/webapp/crd/js/fallback_signal_strategy.js
@@ -112,16 +112,10 @@ /** * @type {Array<{strategyType: remoting.SignalStrategy.Type, - progress: remoting.FallbackSignalStrategy.Progress, - * elapsed: number}>} + progress: remoting.FallbackSignalStrategy.Progress}>} */ this.connectionSetupResults_ = []; - /** - * @type {number} - * @private - */ - this.startTime_ = 0; }; /** @@ -178,7 +172,6 @@ this.username_ = username; this.authToken_ = authToken; this.state_ = this.State.PRIMARY_PENDING; - this.startTime_ = new Date().getTime(); this.primary_.setIncomingStanzaCallback(this.onIncomingStanzaCallback_); this.primary_.connect(server, username, authToken); this.primaryConnectTimerId_ = @@ -211,8 +204,7 @@ for (var i = 0; i < this.connectionSetupResults_.length; ++i) { var result = this.connectionSetupResults_[i]; this.logToServer_.logSignalStrategyProgress(result.strategyType, - result.progress, - result.elapsed); + result.progress); } this.connectionSetupResults_ = []; }; @@ -391,8 +383,7 @@ progress); this.connectionSetupResults_.push({ 'strategyType': strategy.getType(), - 'progress': progress, - 'elapsed': new Date().getTime() - this.startTime_ + 'progress': progress }); if (this.logToServer_) { this.sendConnectionSetupResultsInternal_();
diff --git a/remoting/webapp/crd/js/fullscreen.js b/remoting/webapp/crd/js/fullscreen.js index 415734b..1dfff4f2 100644 --- a/remoting/webapp/crd/js/fullscreen.js +++ b/remoting/webapp/crd/js/fullscreen.js
@@ -50,3 +50,22 @@ /** @type {remoting.Fullscreen} */ remoting.fullscreen = null; + + +/** + * @constructor + * @param {function(boolean=)} listener + * @implements {base.Disposable} + */ +remoting.Fullscreen.EventHook = function(listener) { + /** @private */ + this.src_ = remoting.fullscreen; + /** @private */ + this.listener_ = listener; + + this.src_.addListener(listener); +}; + +remoting.Fullscreen.EventHook.prototype.dispose = function() { + this.src_.removeListener(this.listener_); +}; \ No newline at end of file
diff --git a/remoting/webapp/crd/js/hangout_consent_dialog.js b/remoting/webapp/crd/js/hangout_consent_dialog.js deleted file mode 100644 index 648419e..0000000 --- a/remoting/webapp/crd/js/hangout_consent_dialog.js +++ /dev/null
@@ -1,105 +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. - -/** @suppress {duplicate} */ -var remoting = remoting || {}; - -(function() { - -'use strict'; - -var instance_ = null; - -/** - * Shows a dialog to ask for the user's permission to accept remote assistance - * from a Hangout participant. - * - * @constructor - * @private - */ -remoting.HangoutConsentDialog = function() { - /** - * @type {base.Deferred} - * @private - */ - this.onConsentResponseDeferred_ = null; - - /** @private */ - this.requestToken_ = base.generateXsrfToken(); - - base.Ipc.getInstance().register('remoting.HangoutConsentDialog.confirm', - this.onConfirmResponse_.bind(this)); -}; - -/** - * @param {boolean} confirm Whether the user authorized the it2me connection - * @param {string} responseToken - * @private - */ -remoting.HangoutConsentDialog.prototype.onConfirmResponse_ = function( - confirm, responseToken) { - if (responseToken !== this.requestToken_) { - return; - } - - if (confirm) { - this.onConsentResponseDeferred_.resolve(); - } else { - this.onConsentResponseDeferred_.reject( - new Error(remoting.Error.CANCELLED)); - } - this.onConsentResponseDeferred_ = null; -}; - -/** - * @param {boolean} authorized If true, the consent dialog will hide the - * authorization section. - * @param {Bounds=} opt_parentBounds If present, the consent dialog will be - * centered within |opt_parentBounds|. - * @return {Promise} A Promise that will resolve when permission is granted or - * reject if the user cancels. - */ -remoting.HangoutConsentDialog.prototype.show = function(authorized, - opt_parentBounds) { - if (!this.onConsentResponseDeferred_) { - var DIALOG_WIDTH = 750; - var DIALOG_HEIGHT = 480; - - var createOptions = { - frame: 'none', - resizable: false, - outerBounds: { width: DIALOG_WIDTH, height: DIALOG_HEIGHT } - }; - - var params = { - token: this.requestToken_, - authorized: Boolean(authorized) - }; - - var url = base.urlJoin('dialog_hangout_consent.html', params); - - if (opt_parentBounds) { - // Center the dialog on the parent bounds. - var rect = opt_parentBounds; - createOptions.outerBounds.top = - Math.round(rect.top + rect.height / 2 - DIALOG_HEIGHT / 2); - createOptions.outerBounds.left = - Math.round(rect.left + rect.width / 2 - DIALOG_WIDTH / 2); - } - - this.onConsentResponseDeferred_ = new base.Deferred(); - chrome.app.window.create(url, createOptions); - } - return this.onConsentResponseDeferred_.promise(); -}; - -/** @return {remoting.HangoutConsentDialog} */ -remoting.HangoutConsentDialog.getInstance = function() { - if (!instance_) { - instance_ = new remoting.HangoutConsentDialog(); - } - return instance_; -}; - -}());
diff --git a/remoting/webapp/crd/js/hangout_consent_dialog_main.js b/remoting/webapp/crd/js/hangout_consent_dialog_main.js deleted file mode 100644 index 8ced7a86..0000000 --- a/remoting/webapp/crd/js/hangout_consent_dialog_main.js +++ /dev/null
@@ -1,63 +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. - -/** -* @fileoverview -* The entry point for dialog_hangout_consent.html. -*/ - - -/** @suppress {duplicate} */ -var remoting = remoting || {}; - -(function() { - -'use strict'; - -/** - * @constructor - * @param {HTMLElement} rootElement - * @param {string} requestToken - * @param {boolean} authorized Whether the user is authorized or not. - */ -var ConsentDialog = function(rootElement, requestToken, authorized) { - /** @private */ - this.okButton_ = rootElement.querySelector('.ok-button'); - /** @private */ - this.cancelButton_ = rootElement.querySelector('.cancel-button'); - /** @private */ - this.authSection_ = rootElement.querySelector('.auth-message'); - /** @private */ - this.requestToken_ = requestToken; - - if (authorized) { - this.authSection_.hidden = true; - } - - this.okButton_.addEventListener('click', this.onButton_.bind(this, true)); - this.cancelButton_.addEventListener('click',this.onButton_.bind(this, false)); - base.resizeWindowToContent(); -}; - -/** - * @param {boolean} confirm - * @private - */ -ConsentDialog.prototype.onButton_ = function(confirm) { - base.Ipc.invoke('remoting.HangoutConsentDialog.confirm', confirm, - this.requestToken_); - chrome.app.window.current().close(); -}; - -function onDomContentLoaded() { - var params = base.getUrlParameters(); - var authorized = getBooleanAttr(params, 'authorized', false); - var token = getStringAttr(params, 'token'); - l10n.localize(); - var confirmDialog = new ConsentDialog(document.body, token, authorized); -} - -window.addEventListener('load', onDomContentLoaded); - -}());
diff --git a/remoting/webapp/crd/js/hangout_session.js b/remoting/webapp/crd/js/hangout_session.js deleted file mode 100644 index ac46f1e..0000000 --- a/remoting/webapp/crd/js/hangout_session.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. - -/** - * @fileoverview - * Class to communicate with the background scripts via chrome runtime - * messages to - * 1. Forward session state notifications - * 2. Closes the window when the session terminates - */ - -'use strict'; - -/** @suppress {duplicate} */ -var remoting = remoting || {}; - -/** - * @constructor - * @param {string} senderId id of the current tab or window. - */ -remoting.HangoutSession = function(senderId) { - /** - * @private - * @type {chrome.runtime.Port} - */ - this.port_ = null; - - /** - * @private - * @type {string} - */ - this.senderId_ = senderId; -}; - -remoting.HangoutSession.prototype.init = function() { - var portName = 'it2me.helper.webapp@' + this.senderId_; - this.port_ = chrome.runtime.connect({name: portName}); - - remoting.hangoutSessionEvents.addEventListener( - remoting.hangoutSessionEvents.sessionStateChanged, - this.onSessionStateChanged_.bind(this)); -}; - -/** - * @param {remoting.ClientSession.State=} state - */ -remoting.HangoutSession.prototype.onSessionStateChanged_ = function(state) { - var State = remoting.ClientSession.State; - try { - this.port_.postMessage({method: 'sessionStateChanged', state: state}); - } catch (/** @type {Error} */ error) { - // postMessage will throw an exception if the port is disconnected. - // We can safely ignore this exception. - console.error(error); - } finally { - if (state === State.FAILED || state === State.CLOSED) { - // close the current window - if (base.isAppsV2()) { - chrome.app.window.current().close(); - } else { - window.close(); - } - } - } -}; - - -/** - * remoting.clientSession does not exist until the session is connected. - * hangoutSessionEvents serves as a global event source to plumb session - * state changes until we cleanup clientSession and sessionConnector. - * @type {base.EventSourceImpl} - */ -remoting.hangoutSessionEvents = new base.EventSourceImpl(); - -/** @type {string} */ -remoting.hangoutSessionEvents.sessionStateChanged = "sessionStateChanged"; - -remoting.hangoutSessionEvents.defineEvents( - [remoting.hangoutSessionEvents.sessionStateChanged]);
diff --git a/remoting/webapp/crd/js/host_controller.js b/remoting/webapp/crd/js/host_controller.js index 4a37ee2..17e29edd 100644 --- a/remoting/webapp/crd/js/host_controller.js +++ b/remoting/webapp/crd/js/host_controller.js
@@ -184,16 +184,18 @@ private_key: privateKey }; var hostOwner = clientBaseJid; - var hostOwnerEmail = remoting.identity.getCachedEmail(); - if (hostOwner != xmppLogin) { - hostConfig['host_owner'] = hostOwner; - if (hostOwnerEmail != hostOwner) { - hostConfig['host_owner_email'] = hostOwnerEmail; - } - } - that.hostDaemonFacade_.startDaemon( - hostConfig, consent, onStarted.bind(null, hostName, publicKey), - onStartError); + remoting.identity.getEmail().then( + function(/** string */ hostOwnerEmail) { + if (hostOwner != xmppLogin) { + hostConfig['host_owner'] = hostOwner; + if (hostOwnerEmail != hostOwner) { + hostConfig['host_owner_email'] = hostOwnerEmail; + } + } + that.hostDaemonFacade_.startDaemon( + hostConfig, consent, onStarted.bind(null, hostName, publicKey), + onStartError); + }); } /** @@ -248,13 +250,14 @@ onError); } else { // No authorization code returned, use regular user credential flow. - that.hostDaemonFacade_.getPinHash( - newHostId, hostPin, startHostWithHash.bind( - null, hostName, publicKey, privateKey, - remoting.identity.getCachedEmail(), - remoting.oauth2.getRefreshToken(), - remoting.identity.getCachedEmail()), - onError); + remoting.identity.getEmail().then( + function(/** string */ email) { + that.hostDaemonFacade_.getPinHash( + newHostId, hostPin, startHostWithHash.bind( + null, hostName, publicKey, privateKey, + email, remoting.oauth2.getRefreshToken(), email), + onError); + }); } } else { console.log('Failed to register the host. Status: ' + xhr.status +
diff --git a/remoting/webapp/crd/js/host_list.js b/remoting/webapp/crd/js/host_list.js index 4221115..5096998b 100644 --- a/remoting/webapp/crd/js/host_list.js +++ b/remoting/webapp/crd/js/host_list.js
@@ -72,15 +72,13 @@ */ this.lastError_ = ''; /** - * @type {remoting.Host?} + * @type {remoting.LocalHostSection} * @private */ - this.localHost_ = null; - /** - * @type {remoting.HostController.State} - * @private - */ - this.localHostState_ = remoting.HostController.State.UNKNOWN; + this.localHostSection_ = new remoting.LocalHostSection( + /** @type {HTMLElement} */ (document.querySelector('.daemon-control')), + new remoting.LocalHostSection.Controller( + this, new remoting.HostSetupDialog(remoting.hostController))); /** * @type {number} @@ -98,7 +96,7 @@ function refresh(event) { event.preventDefault(); that.refresh(that.display.bind(that)); - }; + } reloadButton.addEventListener('click', refresh, false); }; @@ -258,40 +256,22 @@ // not the local host (which is displayed separately). NB: if the host has // never sent a heartbeat, then there will be no jabberId. if (host.hostName && host.hostId && host.status && host.publicKey && - (!this.localHost_ || host.hostId != this.localHost_.hostId)) { + (host.hostId != this.localHostSection_.getHostId())) { var hostTableEntry = new remoting.HostTableEntry( - host, this.webappMajorVersion_, - this.renameHost_.bind(this), this.deleteHost_.bind(this)); - hostTableEntry.createDom(); + this.webappMajorVersion_, + remoting.connectMe2Me, + this.renameHost.bind(this), + this.deleteHost_.bind(this)); + hostTableEntry.setHost(host); this.hostTableEntries_[i] = hostTableEntry; - this.table_.appendChild(hostTableEntry.tableRow); + this.table_.appendChild(hostTableEntry.element()); } } } this.errorMsg_.parentNode.hidden = (this.lastError_ == ''); - - // The local host cannot be stopped or started if the host controller is not - // implemented for this platform. Additionally, it cannot be started if there - // is an error (in many error states, the start operation will fail anyway, - // but even if it succeeds, the chance of a related but hard-to-diagnose - // future error is high). - var state = this.localHostState_; - var enabled = (state == remoting.HostController.State.STARTING) || - (state == remoting.HostController.State.STARTED); - var canChangeLocalHostState = - (state != remoting.HostController.State.NOT_IMPLEMENTED) && - (state != remoting.HostController.State.UNKNOWN) && - (state != remoting.HostController.State.NOT_INSTALLED || - remoting.isMe2MeInstallable()) && - (enabled || this.lastError_ == ''); - - remoting.updateModalUi(enabled ? 'enabled' : 'disabled', 'data-daemon-state'); - var element = document.getElementById('daemon-control'); - element.hidden = !canChangeLocalHostState; - if (noHostsRegistered) { - this.showHostListEmptyMessage_(canChangeLocalHostState); + this.showHostListEmptyMessage_(this.localHostSection_.canChangeState()); } }; @@ -337,7 +317,7 @@ * @private */ remoting.HostList.prototype.deleteHost_ = function(hostTableEntry) { - this.table_.removeChild(hostTableEntry.tableRow); + this.table_.removeChild(hostTableEntry.element()); var index = this.hostTableEntries_.indexOf(hostTableEntry); if (index != -1) { this.hostTableEntries_.splice(index, 1); @@ -349,9 +329,8 @@ * Prepare a host for renaming by replacing its name with an edit box. * @param {remoting.HostTableEntry} hostTableEntry The host to be renamed. * @return {void} Nothing. - * @private */ -remoting.HostList.prototype.renameHost_ = function(hostTableEntry) { +remoting.HostList.prototype.renameHost = function(hostTableEntry) { for (var i = 0; i < this.hosts_.length; ++i) { if (this.hosts_[i].hostId == hostTableEntry.host.hostId) { this.hosts_[i].hostName = hostTableEntry.host.hostName; @@ -377,24 +356,6 @@ }; /** - * Set tool-tips for the 'connect' action. We can't just set this on the - * parent element because the button has no tool-tip, and therefore would - * inherit connectStr. - * - * @return {void} Nothing. - * @private - */ -remoting.HostList.prototype.setTooltips_ = function() { - var connectStr = ''; - if (this.localHost_) { - chrome.i18n.getMessage(/*i18n-content*/'TOOLTIP_CONNECT', - this.localHost_.hostName); - } - document.getElementById('this-host-name').title = connectStr; - document.getElementById('this-host-icon').title = connectStr; -}; - -/** * Set the state of the local host and localHostId if any. * * @param {remoting.HostController.State} state State of the local host. @@ -402,48 +363,9 @@ * @return {void} Nothing. */ remoting.HostList.prototype.setLocalHostStateAndId = function(state, hostId) { - this.localHostState_ = state; - this.setLocalHost_(hostId ? this.getHostForId(hostId) : null); -} - -/** - * Set the host object that corresponds to the local computer, if any. - * - * @param {remoting.Host?} host The host, or null if not registered. - * @return {void} Nothing. - * @private - */ -remoting.HostList.prototype.setLocalHost_ = function(host) { - this.localHost_ = host; - this.setTooltips_(); - /** @type {remoting.HostList} */ - var that = this; - if (host) { - /** @param {remoting.HostTableEntry} host */ - var renameHost = function(host) { - that.renameHost_(host); - that.setTooltips_(); - }; - if (!this.localHostTableEntry_) { - /** @type {remoting.HostTableEntry} @private */ - this.localHostTableEntry_ = new remoting.HostTableEntry( - host, this.webappMajorVersion_, renameHost); - this.localHostTableEntry_.init( - document.getElementById('this-host-connect'), - document.getElementById('this-host-warning'), - document.getElementById('this-host-name'), - document.getElementById('this-host-rename')); - } else { - // TODO(jamiewalch): This is hack to prevent multiple click handlers being - // registered for the same DOM elements if this method is called more than - // once. A better solution would be to let HostTable create the daemon row - // like it creates the rows for non-local hosts. - this.localHostTableEntry_.host = host; - } - } else { - this.localHostTableEntry_ = null; - } -} + var host = hostId ? this.getHostForId(hostId) : null; + this.localHostSection_.setModel(host, state, this.lastError_ !== ''); +}; /** * Called by the HostControlled after the local host has been started. @@ -471,7 +393,9 @@ localHost.status = 'ONLINE'; this.hosts_.push(localHost); this.save_(); - this.setLocalHost_(localHost); + this.localHostSection_.setModel(localHost, + remoting.HostController.State.STARTED, + this.lastError_ !== ''); }; /**
diff --git a/remoting/webapp/crd/js/host_screen.js b/remoting/webapp/crd/js/host_screen.js index 183deb7f..cb3695d 100644 --- a/remoting/webapp/crd/js/host_screen.js +++ b/remoting/webapp/crd/js/host_screen.js
@@ -94,10 +94,12 @@ base.debug.assert(hostSession_ === null); hostSession_ = new remoting.HostSession(); - var email = /** @type {string} */ (remoting.identity.getCachedEmail()); - hostSession_.connect( - hostFacade, email, token, onHostStateChanged_, - onNatTraversalPolicyChanged_, logDebugInfo_, it2meConnectFailed_); + remoting.identity.getEmail().then( + function(/** string */ email) { + hostSession_.connect( + hostFacade, email, token, onHostStateChanged_, + onNatTraversalPolicyChanged_, logDebugInfo_, it2meConnectFailed_); + }); }; /** @@ -336,4 +338,4 @@ } } -})(); \ No newline at end of file +})();
diff --git a/remoting/webapp/crd/js/host_table_entry.js b/remoting/webapp/crd/js/host_table_entry.js index 44a9f573..feb88a3e 100644 --- a/remoting/webapp/crd/js/host_table_entry.js +++ b/remoting/webapp/crd/js/host_table_entry.js
@@ -7,242 +7,277 @@ * Class representing an entry in the host-list portion of the home screen. */ -'use strict'; - /** @suppress {duplicate} */ var remoting = remoting || {}; +(function() { + +'use strict'; + /** * An entry in the host table. - * @param {remoting.Host} host The host, as obtained from Apiary. + * * @param {number} webappMajorVersion The major version nmber of the web-app, * used to identify out-of-date hosts. + * @param {function(string):void} onConnect Callback for + * connect operations. * @param {function(remoting.HostTableEntry):void} onRename Callback for * rename operations. * @param {function(remoting.HostTableEntry):void=} opt_onDelete Callback for * delete operations. + * * @constructor + * @implements {base.Disposable} */ remoting.HostTableEntry = function( - host, webappMajorVersion, onRename, opt_onDelete) { + webappMajorVersion, onConnect, onRename, opt_onDelete) { /** @type {remoting.Host} */ - this.host = host; - /** @type {number} */ + this.host = null; + /** @private {number} */ this.webappMajorVersion_ = webappMajorVersion; - /** @type {function(remoting.HostTableEntry):void} @private */ + /** @private {function(remoting.HostTableEntry):void} */ this.onRename_ = onRename; - /** @type {undefined|function(remoting.HostTableEntry):void} @private */ + /** @private {undefined|function(remoting.HostTableEntry):void} */ this.onDelete_ = opt_onDelete; + /** @private {function(string):void} */ + this.onConnect_ = onConnect; - /** @type {HTMLElement} */ - this.tableRow = null; - /** @type {HTMLElement} @private */ - this.hostNameCell_ = null; - /** @type {HTMLElement} @private */ + /** @private {HTMLElement} */ + this.rootElement_ = null; + /** @private {HTMLElement} */ + this.hostNameLabel_ = null; + /** @private {HTMLInputElement} */ + this.renameInputField_ = null; + /** @private {HTMLElement} */ this.warningOverlay_ = null; + + /** @private {base.Disposables} */ + this.renameInputEventHooks_ = null; + /** @private {base.Disposables} */ + this.disposables_ = new base.Disposables(); + // References to event handlers so that they can be removed. - /** @type {function():void} @private */ - this.onBlurReference_ = function() {}; - /** @type {function():void} @private */ + /** @private {function():void} */ this.onConfirmDeleteReference_ = function() {}; - /** @type {function():void} @private */ + /** @private {function():void} */ this.onCancelDeleteReference_ = function() {}; - /** @type {function():void?} @private */ - this.onConnectReference_ = null; + + this.createDom_(); +}; + +/** @param {remoting.Host} host */ +remoting.HostTableEntry.prototype.setHost = function(host) { + this.host = host; + this.updateUI_(); +}; + +/** @return {HTMLElement} */ +remoting.HostTableEntry.prototype.element = function() { + return this.rootElement_; +}; + +remoting.HostTableEntry.prototype.dispose = function() { + base.dispose(this.disposables_); + this.disposables_ = null; + base.dispose(this.renameInputEventHooks_); + this.renameInputEventHooks_ = null; +}; + +/** @return {string} */ +remoting.HostTableEntry.prototype.getHTML_ = function() { + var html = + '<div class="host-list-main-icon">' + + '<span class="warning-overlay"></span>' + + '<img src="icon_host.webp">' + + '</div>' + + '<div class="box-spacer"">' + + '<a class="host-name-label" href="#""></a>' + + '<input class="host-rename-input" type="text" hidden/>' + + '</div>' + + '<span tabindex="0" class="clickable host-list-edit rename-button">' + + '<img src="icon_pencil.webp" class="host-list-rename-icon">' + + '</span>'; + if (this.onDelete_) { + html += + '<span tabindex="0" class="clickable host-list-edit delete-button">' + + '<img src="icon_cross.webp" class="host-list-remove-icon">' + + '</span>'; + } + return '<div class="section-row host-offline">' + html + '</div>'; }; /** * Create the HTML elements for this entry and set up event handlers. * @return {void} Nothing. */ -remoting.HostTableEntry.prototype.createDom = function() { - // Create the top-level <div> - var tableRow = /** @type {HTMLElement} */ (document.createElement('div')); - tableRow.classList.add('section-row'); - // Create the host icon cell. - var hostIconDiv = /** @type {HTMLElement} */ (document.createElement('div')); - hostIconDiv.classList.add('host-list-main-icon'); - var warningOverlay = - /** @type {HTMLElement} */ (document.createElement('span')); - hostIconDiv.appendChild(warningOverlay); - var hostIcon = /** @type {HTMLElement} */ (document.createElement('img')); - hostIcon.src = 'icon_host.webp'; - hostIconDiv.appendChild(hostIcon); - tableRow.appendChild(hostIconDiv); - // Create the host name cell. - var hostNameCell = /** @type {HTMLElement} */ (document.createElement('div')); - hostNameCell.classList.add('box-spacer'); - hostNameCell.id = 'host_' + this.host.hostId; - tableRow.appendChild(hostNameCell); - // Create the host rename cell. - var editButton = /** @type {HTMLElement} */ (document.createElement('span')); - var editButtonImg = - /** @type {HTMLElement} */ (document.createElement('img')); - editButtonImg.title = chrome.i18n.getMessage( - /*i18n-content*/'TOOLTIP_RENAME'); - editButtonImg.src = 'icon_pencil.webp'; - editButton.tabIndex = 0; - editButton.classList.add('clickable'); - editButton.classList.add('host-list-edit'); - editButtonImg.classList.add('host-list-rename-icon'); - editButton.appendChild(editButtonImg); - tableRow.appendChild(editButton); - // Create the host delete cell. - var deleteButton = - /** @type {HTMLElement} */ (document.createElement('span')); - var deleteButtonImg = - /** @type {HTMLElement} */ (document.createElement('img')); - deleteButtonImg.title = - chrome.i18n.getMessage(/*i18n-content*/'TOOLTIP_DELETE'); - deleteButtonImg.src = 'icon_cross.webp'; - deleteButton.tabIndex = 0; - deleteButton.classList.add('clickable'); - deleteButton.classList.add('host-list-edit'); - deleteButtonImg.classList.add('host-list-remove-icon'); - deleteButton.appendChild(deleteButtonImg); - tableRow.appendChild(deleteButton); +remoting.HostTableEntry.prototype.createDom_ = function() { + var container = /** @type {HTMLElement} */ (document.createElement('div')); + container.innerHTML = this.getHTML_(); - this.init(tableRow, warningOverlay, hostNameCell, editButton, deleteButton); + // Setup DOM references. + this.rootElement_ = /** @type {HTMLElement} */ (container.firstElementChild); + this.warningOverlay_ = container.querySelector('.warning-overlay'); + this.hostNameLabel_ = container.querySelector('.host-name-label'); + this.renameInputField_ = /** @type {HTMLInputElement} */ ( + container.querySelector('.host-rename-input')); + + // Register event handlers and set tooltips. + var editButton = container.querySelector('.rename-button'); + var deleteButton = container.querySelector('.delete-button'); + editButton.title = chrome.i18n.getMessage(/*i18n-content*/'TOOLTIP_RENAME'); + this.registerButton_(editButton, this.beginRename_.bind(this)); + this.registerButton_(this.rootElement_, this.onConnectButton_.bind(this)); + if (deleteButton) { + this.registerButton_(deleteButton, this.showDeleteConfirmation_.bind(this)); + deleteButton.title = + chrome.i18n.getMessage(/*i18n-content*/'TOOLTIP_DELETE'); + } +}; + +/** @return {base.Disposable} @private */ +remoting.HostTableEntry.prototype.registerButton_ = function( + /** HTMLElement */ button, /** Function */ callback) { + var onKeyDown = function(/** Event */ e) { + if (e.which === KeyCodes.ENTER || e.which === KeyCodes.SPACEBAR) { + callback(); + e.stopPropagation(); + } + }; + var onClick = function(/** Event */ e) { + callback(); + e.stopPropagation(); + }; + var onFocusChanged = this.onFocusChange_.bind(this); + this.disposables_.add( + new base.DomEventHook(button, 'click', onClick, false), + new base.DomEventHook(button, 'keydown', onKeyDown, false), + // Register focus and blur handlers to cause the parent node to be + // highlighted whenever a child link has keyboard focus. Note that this is + // only necessary because Chrome does not yet support the draft CSS + // Selectors 4 specification (http://www.w3.org/TR/selectors4/#subject), + // which provides a more elegant solution to this problem. + new base.DomEventHook(button, 'focus', onFocusChanged, false), + new base.DomEventHook(button, 'blur', onFocusChanged, false)); +}; + + +/** @return {void} @private */ +remoting.HostTableEntry.prototype.onConnectButton_ = function() { + // Don't connect during renaming as this event fires if the user hits Enter + // after typing a new name. + if (!this.isRenaming_() && this.isOnline_()) { + var encodedHostId = encodeURIComponent(this.host.hostId); + this.onConnect_(encodedHostId); + } +}; + +/** @return {boolean} @private */ +remoting.HostTableEntry.prototype.isOnline_ = function() { + return Boolean(this.host) && this.host.status === 'ONLINE'; +}; + +/** @return {string} @private */ +remoting.HostTableEntry.prototype.getHostDisplayName_ = function() { + if (this.isOnline_()) { + if (remoting.Host.needsUpdate(this.host, this.webappMajorVersion_)) { + return chrome.i18n.getMessage( + /*i18n-content*/'UPDATE_REQUIRED', this.host.hostName); + } + return this.host.hostName; + } else { + if (this.host.updatedTime) { + var formattedTime = formatUpdateTime(this.host.updatedTime); + return chrome.i18n.getMessage(/*i18n-content*/ 'LAST_ONLINE', + [this.host.hostName, formattedTime]); + } + return chrome.i18n.getMessage(/*i18n-content*/ 'OFFLINE', + this.host.hostName); + } }; /** - * Associate the table row with the specified elements and callbacks, and set - * up event handlers. + * Update the UI to reflect the current status of the host * - * @param {HTMLElement} tableRow The top-level <div> for the table entry. - * @param {HTMLElement} warningOverlay The <span> element to render a warning - * icon on top of the host icon. - * @param {HTMLElement} hostNameCell The element containing the host name. - * @param {HTMLElement} editButton The <img> containing the pencil icon for - * editing the host name. - * @param {HTMLElement=} opt_deleteButton The <img> containing the cross icon - * for deleting the host, if present. * @return {void} Nothing. + * @private */ -remoting.HostTableEntry.prototype.init = function( - tableRow, warningOverlay, hostNameCell, editButton, opt_deleteButton) { - this.tableRow = tableRow; - this.warningOverlay_ = warningOverlay; - this.hostNameCell_ = hostNameCell; - this.setHostName_(); - - /** @type {remoting.HostTableEntry} */ - var that = this; - - /** @param {Event} event The click event. */ - var beginRename = function(event) { - that.beginRename_(); - event.stopPropagation(); - }; - /** @param {Event} event The keyup event. */ - var beginRenameKeyboard = function(event) { - if (event.which == 13 || event.which == 32) { - that.beginRename_(); - event.stopPropagation(); - } - }; - editButton.addEventListener('click', beginRename, true); - editButton.addEventListener('keyup', beginRenameKeyboard, true); - this.registerFocusHandlers_(editButton); - - if (opt_deleteButton) { - /** @param {Event} event The click event. */ - var confirmDelete = function(event) { - that.showDeleteConfirmation_(); - event.stopPropagation(); - }; - /** @param {Event} event The keyup event. */ - var confirmDeleteKeyboard = function(event) { - if (event.which == 13 || event.which == 32) { - that.showDeleteConfirmation_(); - } - }; - opt_deleteButton.addEventListener('click', confirmDelete, false); - opt_deleteButton.addEventListener('keyup', confirmDeleteKeyboard, false); - this.registerFocusHandlers_(opt_deleteButton); +remoting.HostTableEntry.prototype.updateUI_ = function() { + if (!this.host) { + return; } - this.updateStatus(); -}; + var clickToConnect = this.isOnline_() && !this.isRenaming_(); + var showOffline = !this.isOnline_(); + var connectLabel = chrome.i18n.getMessage(/*i18n-content*/'TOOLTIP_CONNECT', + this.host.hostName); + this.rootElement_.classList.toggle('clickable', clickToConnect); + this.rootElement_.title = (clickToConnect) ? connectLabel : ''; + this.rootElement_.classList.toggle('host-online', !showOffline); + this.rootElement_.classList.toggle('host-offline', showOffline); -/** - * Update the row to reflect the current status of the host (online/offline and - * clickable/unclickable). - * - * @param {boolean=} opt_forEdit True if the status is being updated in order - * to allow the host name to be edited. - * @return {void} Nothing. - */ -remoting.HostTableEntry.prototype.updateStatus = function(opt_forEdit) { - var clickToConnect = this.host.status == 'ONLINE' && !opt_forEdit; - if (clickToConnect) { - if (!this.onConnectReference_) { - /** @type {string} */ - var encodedHostId = encodeURIComponent(this.host.hostId); - this.onConnectReference_ = function() { - remoting.connectMe2Me(encodedHostId); - }; - this.tableRow.addEventListener('click', this.onConnectReference_, false); - } - this.tableRow.classList.add('clickable'); - this.tableRow.title = chrome.i18n.getMessage( - /*i18n-content*/'TOOLTIP_CONNECT', this.host.hostName); - } else { - if (this.onConnectReference_) { - this.tableRow.removeEventListener('click', this.onConnectReference_, - false); - this.onConnectReference_ = null; - } - this.tableRow.classList.remove('clickable'); - this.tableRow.title = ''; - } - var showOffline = this.host.status != 'ONLINE'; - if (showOffline) { - this.tableRow.classList.remove('host-online'); - this.tableRow.classList.add('host-offline'); - } else { - this.tableRow.classList.add('host-online'); - this.tableRow.classList.remove('host-offline'); - } - var hostReportedError = this.host.hostOfflineReason != ''; + var hostReportedError = this.host.hostOfflineReason !== ''; var hostNeedsUpdate = remoting.Host.needsUpdate( this.host, this.webappMajorVersion_); this.warningOverlay_.hidden = !hostNeedsUpdate && !hostReportedError; + this.hostNameLabel_.innerText = this.getHostDisplayName_(); + this.hostNameLabel_.title = + formatHostOfflineReason(this.host.hostOfflineReason); + this.renameInputField_.hidden = !this.isRenaming_(); + this.hostNameLabel_.hidden = this.isRenaming_(); }; /** - * Prepare the host for renaming by replacing its name with an edit box. + * Prepares the host for renaming by showing an edit box. * @return {void} Nothing. * @private */ remoting.HostTableEntry.prototype.beginRename_ = function() { - var editBox = - /** @type {HTMLInputElement} */ (document.createElement('input')); - editBox.type = 'text'; - editBox.value = this.host.hostName; - this.hostNameCell_.innerText = ''; - this.hostNameCell_.appendChild(editBox); - editBox.select(); + this.renameInputField_.value = this.host.hostName; + base.debug.assert(this.renameInputEventHooks_ === null); + base.dispose(this.renameInputEventHooks_); + this.renameInputEventHooks_ = new base.Disposables( + new base.DomEventHook(this.renameInputField_, 'blur', + this.commitRename_.bind(this), false), + new base.DomEventHook(this.renameInputField_, 'keydown', + this.onKeydown_.bind(this), false)); + this.updateUI_(); + this.renameInputField_.focus(); +}; - this.onBlurReference_ = this.commitRename_.bind(this); - editBox.addEventListener('blur', this.onBlurReference_, false); +/** @return {boolean} @private */ +remoting.HostTableEntry.prototype.isRenaming_ = function() { + return Boolean(this.renameInputEventHooks_); +}; - editBox.addEventListener('keydown', this.onKeydown_.bind(this), false); - this.updateStatus(true); +/** @return {void} @private */ +remoting.HostTableEntry.prototype.commitRename_ = function() { + if (this.host.hostName != this.renameInputField_.value) { + this.host.hostName = this.renameInputField_.value; + this.onRename_(this); + } + this.hideEditBox_(); +}; + +/** @return {void} @private */ +remoting.HostTableEntry.prototype.hideEditBox_ = function() { + // onblur will fire when the edit box is removed, so remove the hook. + base.dispose(this.renameInputEventHooks_); + this.renameInputEventHooks_ = null; + // Update the tool-tip and event handler. + this.updateUI_(); }; /** - * Accept the hostname entered by the user. + * Handle a key event while the user is typing a host name + * @param {Event} event The keyboard event. * @return {void} Nothing. * @private */ -remoting.HostTableEntry.prototype.commitRename_ = function() { - var editBox = this.hostNameCell_.querySelector('input'); - if (editBox) { - if (this.host.hostName != editBox.value) { - this.host.hostName = editBox.value; - this.onRename_(this); - } - this.removeEditBox_(); +remoting.HostTableEntry.prototype.onKeydown_ = function(event) { + if (event.which == KeyCodes.ESCAPE) { + this.hideEditBox_(); + } else if (event.which == KeyCodes.ENTER) { + this.commitRename_(); + event.stopPropagation(); } }; @@ -300,19 +335,20 @@ }; /** - * Remove the edit box corresponding to the specified host, and reset its name. + * Handle a focus change event within this table row. * @return {void} Nothing. * @private */ -remoting.HostTableEntry.prototype.removeEditBox_ = function() { - var editBox = this.hostNameCell_.querySelector('input'); - if (editBox) { - // onblur will fire when the edit box is removed, so remove the hook. - editBox.removeEventListener('blur', this.onBlurReference_, false); +remoting.HostTableEntry.prototype.onFocusChange_ = function() { + var element = document.activeElement; + while (element) { + if (element == this.rootElement_) { + this.rootElement_.classList.add('child-focused'); + return; + } + element = element.parentNode; } - // Update the tool-top and event handler. - this.updateStatus(); - this.setHostName_(); + this.rootElement_.classList.remove('child-focused'); }; /** @@ -341,118 +377,35 @@ * @return {string} */ function formatHostOfflineReason(hostOfflineReason) { + if (!hostOfflineReason) { + return ''; + } var knownReasonTags = [ - /*i18n-content*/ 'OFFLINE_REASON_INITIALIZATION_FAILED', - /*i18n-content*/ 'OFFLINE_REASON_INVALID_HOST_CONFIGURATION', - /*i18n-content*/ 'OFFLINE_REASON_INVALID_HOST_DOMAIN', - /*i18n-content*/ 'OFFLINE_REASON_INVALID_HOST_ID', - /*i18n-content*/ 'OFFLINE_REASON_INVALID_OAUTH_CREDENTIALS', - /*i18n-content*/ 'OFFLINE_REASON_LOGIN_SCREEN_NOT_SUPPORTED', - /*i18n-content*/ 'OFFLINE_REASON_POLICY_CHANGE_REQUIRES_RESTART', - /*i18n-content*/ 'OFFLINE_REASON_POLICY_READ_ERROR', - /*i18n-content*/ 'OFFLINE_REASON_SUCCESS_EXIT', - /*i18n-content*/ 'OFFLINE_REASON_USERNAME_MISMATCH' + /*i18n-content*/'OFFLINE_REASON_INITIALIZATION_FAILED', + /*i18n-content*/'OFFLINE_REASON_INVALID_HOST_CONFIGURATION', + /*i18n-content*/'OFFLINE_REASON_INVALID_HOST_DOMAIN', + /*i18n-content*/'OFFLINE_REASON_INVALID_HOST_ID', + /*i18n-content*/'OFFLINE_REASON_INVALID_OAUTH_CREDENTIALS', + /*i18n-content*/'OFFLINE_REASON_LOGIN_SCREEN_NOT_SUPPORTED', + /*i18n-content*/'OFFLINE_REASON_POLICY_CHANGE_REQUIRES_RESTART', + /*i18n-content*/'OFFLINE_REASON_POLICY_READ_ERROR', + /*i18n-content*/'OFFLINE_REASON_SUCCESS_EXIT', + /*i18n-content*/'OFFLINE_REASON_USERNAME_MISMATCH' ]; var offlineReasonTag = 'OFFLINE_REASON_' + hostOfflineReason; if (knownReasonTags.indexOf(offlineReasonTag) != (-1)) { return chrome.i18n.getMessage(offlineReasonTag); } else { return chrome.i18n.getMessage( - /*i18n-content*/ 'OFFLINE_REASON_UNKNOWN', - hostOfflineReason); + /*i18n-content*/'OFFLINE_REASON_UNKNOWN', hostOfflineReason); } } -/** - * Create the DOM nodes and event handlers for the hostname cell. - * @return {void} Nothing. - * @private - */ -remoting.HostTableEntry.prototype.setHostName_ = function() { - var hostNameNode = /** @type {HTMLElement} */ (document.createElement('a')); - if (this.host.status == 'ONLINE') { - if (remoting.Host.needsUpdate(this.host, this.webappMajorVersion_)) { - hostNameNode.innerText = chrome.i18n.getMessage( - /*i18n-content*/'UPDATE_REQUIRED', this.host.hostName); - } else { - hostNameNode.innerText = this.host.hostName; - } - hostNameNode.href = '#'; - this.registerFocusHandlers_(hostNameNode); - /** @type {remoting.HostTableEntry} */ - var that = this; - /** @param {Event} event */ - var onKeyDown = function(event) { - if (that.onConnectReference_ && - (event.which == 13 || event.which == 32)) { - that.onConnectReference_(); - } - }; - hostNameNode.addEventListener('keydown', onKeyDown, false); - } else { - if (this.host.updatedTime) { - var formattedTime = formatUpdateTime(this.host.updatedTime); - hostNameNode.innerText = chrome.i18n.getMessage( - /*i18n-content*/'LAST_ONLINE', [this.host.hostName, formattedTime]); - if (this.host.hostOfflineReason) { - var detailsText = formatHostOfflineReason(this.host.hostOfflineReason); - // TODO(lukasza): Put detailsText into a hideable div (title/tooltip - // is not as discoverable + doesn't work well for touchscreens). - hostNameNode.title = detailsText; - } - } else { - hostNameNode.innerText = chrome.i18n.getMessage( - /*i18n-content*/'OFFLINE', this.host.hostName); - } - } - hostNameNode.classList.add('host-list-label'); - this.hostNameCell_.innerText = ''; // Remove previous contents (if any). - this.hostNameCell_.appendChild(hostNameNode); +/** @enum {number} */ +var KeyCodes = { + ENTER: 13, + ESCAPE: 27, + SPACEBAR: 32 }; -/** - * Handle a key event while the user is typing a host name - * @param {Event} event The keyboard event. - * @return {void} Nothing. - * @private - */ -remoting.HostTableEntry.prototype.onKeydown_ = function(event) { - if (event.which == 27) { // Escape - this.removeEditBox_(); - } else if (event.which == 13) { // Enter - this.commitRename_(); - } -}; - -/** - * Register focus and blur handlers to cause the parent node to be highlighted - * whenever a child link has keyboard focus. Note that this is only necessary - * because Chrome does not yet support the draft CSS Selectors 4 specification - * (http://www.w3.org/TR/selectors4/#subject), which provides a more elegant - * solution to this problem. - * - * @param {HTMLElement} e The element on which to register the event handlers. - * @return {void} Nothing. - * @private - */ -remoting.HostTableEntry.prototype.registerFocusHandlers_ = function(e) { - e.addEventListener('focus', this.onFocusChange_.bind(this), false); - e.addEventListener('blur', this.onFocusChange_.bind(this), false); -}; - -/** - * Handle a focus change event within this table row. - * @return {void} Nothing. - * @private - */ -remoting.HostTableEntry.prototype.onFocusChange_ = function() { - var element = document.activeElement; - while (element) { - if (element == this.tableRow) { - this.tableRow.classList.add('child-focused'); - return; - } - element = element.parentNode; - } - this.tableRow.classList.remove('child-focused'); -}; +})();
diff --git a/remoting/webapp/crd/js/identity.js b/remoting/webapp/crd/js/identity.js index b2f2c5a3..dfa7f987 100644 --- a/remoting/webapp/crd/js/identity.js +++ b/remoting/webapp/crd/js/identity.js
@@ -13,9 +13,6 @@ var remoting = remoting || {}; /** - * TODO(jamiewalch): Remove remoting.OAuth2 from this type annotation when - * the Apps v2 work is complete. - * * @type {remoting.Identity} */ remoting.identity = null; @@ -163,29 +160,6 @@ }; /** - * Gets the user's email address, or null if no successful call to - * getUserInfo has been made. - * - * @return {?string} The cached email address, if available. - */ -remoting.Identity.prototype.getCachedEmail = function() { - return this.email_; -}; - -/** - * Gets the user's full name. - * - * This will return null if either: - * No successful call to getUserInfo has been made, or - * The webapp doesn't have permission to access this value. - * - * @return {?string} The cached user's full name, if available. - */ -remoting.Identity.prototype.getCachedUserFullName = function() { - return this.fullName_; -}; - -/** * Callback for the getAuthToken API. * * @param {boolean} interactive The value of the "interactive" parameter to
diff --git a/remoting/webapp/crd/js/it2me_helpee_channel.js b/remoting/webapp/crd/js/it2me_helpee_channel.js deleted file mode 100644 index 79c016b..0000000 --- a/remoting/webapp/crd/js/it2me_helpee_channel.js +++ /dev/null
@@ -1,477 +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. - -/** - * @fileoverview - * - * It2MeHelpeeChannel relays messages between the Hangouts web page (Hangouts) - * and the It2Me Native Messaging Host (It2MeHost) for the helpee (the Hangouts - * participant who is receiving remoting assistance). - * - * It runs in the background page. It contains a chrome.runtime.Port object, - * representing a connection to Hangouts, and a remoting.It2MeHostFacade object, - * representing a connection to the IT2Me Native Messaging Host. - * - * Hangouts It2MeHelpeeChannel It2MeHost - * |---------runtime.connect()-------->| | - * |-----------hello message---------->| | - * |<-----helloResponse message------->| | - * |----------connect message--------->| | - * | |-----showConfirmDialog()----->| - * | |----------connect()---------->| - * | |<-------hostStateChanged------| - * | | (RECEIVED_ACCESS_CODE) | - * |<---connect response (access code)-| | - * | | | - * - * Hangouts will send the access code to the web app on the helper side. - * The helper will then connect to the It2MeHost using the access code. - * - * Hangouts It2MeHelpeeChannel It2MeHost - * | |<-------hostStateChanged------| - * | | (CONNECTED) | - * |<-- hostStateChanged(CONNECTED)----| | - * |-------disconnect message--------->| | - * |<--hostStateChanged(DISCONNECTED)--| | - * - * - * It also handles host downloads and install status queries: - * - * Hangouts It2MeHelpeeChannel - * |------isHostInstalled message----->| - * |<-isHostInstalled response(false)--| - * | | - * |--------downloadHost message------>| - * | | - * |------isHostInstalled message----->| - * |<-isHostInstalled response(false)--| - * | | - * |------isHostInstalled message----->| - * |<-isHostInstalled response(true)---| - */ - -'use strict'; - -/** @suppress {duplicate} */ -var remoting = remoting || {}; - -/** - * @param {chrome.runtime.Port} hangoutPort - * @param {remoting.It2MeHostFacade} host - * @param {remoting.HostInstaller} hostInstaller - * @param {function()} onDisposedCallback Callback to notify the client when - * the connection is torn down. - * - * @constructor - * @implements {base.Disposable} - */ -remoting.It2MeHelpeeChannel = - function(hangoutPort, host, hostInstaller, onDisposedCallback) { - /** - * @type {chrome.runtime.Port} - * @private - */ - this.hangoutPort_ = hangoutPort; - - /** - * @type {remoting.It2MeHostFacade} - * @private - */ - this.host_ = host; - - /** - * @type {?remoting.HostInstaller} - * @private - */ - this.hostInstaller_ = hostInstaller; - - /** - * @type {remoting.HostSession.State} - * @private - */ - this.hostState_ = remoting.HostSession.State.UNKNOWN; - - /** - * @type {?function()} - * @private - */ - this.onDisposedCallback_ = onDisposedCallback; - - this.onHangoutMessageRef_ = this.onHangoutMessage_.bind(this); - this.onHangoutDisconnectRef_ = this.onHangoutDisconnect_.bind(this); -}; - -/** @enum {string} */ -remoting.It2MeHelpeeChannel.HangoutMessageTypes = { - CONNECT: 'connect', - CONNECT_RESPONSE: 'connectResponse', - DISCONNECT: 'disconnect', - DOWNLOAD_HOST: 'downloadHost', - ERROR: 'error', - HELLO: 'hello', - HELLO_RESPONSE: 'helloResponse', - HOST_STATE_CHANGED: 'hostStateChanged', - IS_HOST_INSTALLED: 'isHostInstalled', - IS_HOST_INSTALLED_RESPONSE: 'isHostInstalledResponse' -}; - -/** @enum {string} */ -remoting.It2MeHelpeeChannel.Features = { - REMOTE_ASSISTANCE: 'remoteAssistance' -}; - -remoting.It2MeHelpeeChannel.prototype.init = function() { - this.hangoutPort_.onMessage.addListener(this.onHangoutMessageRef_); - this.hangoutPort_.onDisconnect.addListener(this.onHangoutDisconnectRef_); -}; - -remoting.It2MeHelpeeChannel.prototype.dispose = function() { - if (this.host_ !== null) { - this.host_.unhookCallbacks(); - this.host_.disconnect(); - this.host_ = null; - } - - if (this.hangoutPort_ !== null) { - this.hangoutPort_.onMessage.removeListener(this.onHangoutMessageRef_); - this.hangoutPort_.onDisconnect.removeListener(this.onHangoutDisconnectRef_); - this.hostState_ = remoting.HostSession.State.DISCONNECTED; - - try { - var MessageTypes = remoting.It2MeHelpeeChannel.HangoutMessageTypes; - this.hangoutPort_.postMessage({ - method: MessageTypes.HOST_STATE_CHANGED, - state: this.hostState_ - }); - } catch (e) { - // |postMessage| throws if |this.hangoutPort_| is disconnected - // It is safe to ignore the exception. - } - this.hangoutPort_.disconnect(); - this.hangoutPort_ = null; - } - - if (this.onDisposedCallback_ !== null) { - this.onDisposedCallback_(); - this.onDisposedCallback_ = null; - } -}; - -/** - * Message Handler for incoming runtime messages from Hangouts. - * - * @param {{method:string, data:Object<string,*>}} message - * @private - */ -remoting.It2MeHelpeeChannel.prototype.onHangoutMessage_ = function(message) { - try { - var MessageTypes = remoting.It2MeHelpeeChannel.HangoutMessageTypes; - switch (message.method) { - case MessageTypes.HELLO: - this.hangoutPort_.postMessage({ - method: MessageTypes.HELLO_RESPONSE, - supportedFeatures: base.values(remoting.It2MeHelpeeChannel.Features) - }); - return true; - case MessageTypes.IS_HOST_INSTALLED: - this.handleIsHostInstalled_(message); - return true; - case MessageTypes.DOWNLOAD_HOST: - this.handleDownloadHost_(message); - return true; - case MessageTypes.CONNECT: - this.handleConnect_(message); - return true; - case MessageTypes.DISCONNECT: - this.dispose(); - return true; - } - throw new Error('Unsupported message method=' + message.method); - } catch(/** @type {Error} */ error) { - this.sendErrorResponse_(message, error.message); - } - return false; -}; - -/** - * Queries the |hostInstaller| for the installation status. - * - * @param {{method:string, data:Object<string,*>}} message - * @private - */ -remoting.It2MeHelpeeChannel.prototype.handleIsHostInstalled_ = - function(message) { - /** @type {remoting.It2MeHelpeeChannel} */ - var that = this; - - /** @param {boolean} installed */ - function sendResponse(installed) { - var MessageTypes = remoting.It2MeHelpeeChannel.HangoutMessageTypes; - that.hangoutPort_.postMessage({ - method: MessageTypes.IS_HOST_INSTALLED_RESPONSE, - result: installed - }); - } - - remoting.HostInstaller.isInstalled().then( - sendResponse, - /** @type {function(*):void} */(this.sendErrorResponse_.bind(this, message)) - ); -}; - -/** - * @param {{method:string, data:Object<string,*>}} message - * @private - */ -remoting.It2MeHelpeeChannel.prototype.handleDownloadHost_ = function(message) { - try { - this.hostInstaller_.download(); - } catch (/** @type {*} */ e) { - var error = /** @type {Error} */ (e); - this.sendErrorResponse_(message, error.message); - } -}; - -/** - * Disconnect the session if the |hangoutPort| gets disconnected. - * @private - */ -remoting.It2MeHelpeeChannel.prototype.onHangoutDisconnect_ = function() { - this.dispose(); -}; - -/** - * Connects to the It2Me Native messaging Host and retrieves the access code. - * - * @param {{method:string, data:Object<string,*>}} message - * @private - */ -remoting.It2MeHelpeeChannel.prototype.handleConnect_ = - function(message) { - var bounds = - /** @type {Bounds} */ (getObjectAttr(message, 'hangoutBounds', null)); - - if (this.hostState_ !== remoting.HostSession.State.UNKNOWN) { - throw new Error('An existing connection is in progress.'); - } - - var that = this; - this.showConfirmDialog_(bounds) - .then(this.initializeHost_.bind(this)) - .then(this.fetchOAuthToken_.bind(this)) - .then(this.fetchEmail_.bind(this)) - /** @param {{email:string, token:string}|Promise} result */ - .then(function(result) { - that.connectToHost_(result.email, result.token); - /** @param {*} reason */ - }).catch(function(reason) { - that.sendErrorResponse_(message, /** @type {Error} */ (reason)); - that.dispose(); - }); -}; - -/** - * Prompts the user before starting the It2Me Native Messaging Host. This - * ensures that even if Hangouts is compromised, an attacker cannot start the - * host without explicit user confirmation. - * - * @param {Bounds} bounds Bounds of the hangout window - * @return {Promise} A promise that will resolve if the user accepts remote - * assistance or reject otherwise. - * @private - */ -remoting.It2MeHelpeeChannel.prototype.showConfirmDialog_ = function(bounds) { - if (base.isAppsV2()) { - return this.showConfirmDialogV2_(bounds); - } else { - return this.showConfirmDialogV1_(); - } -}; - -/** - * @return {Promise} A promise that will resolve if the user accepts remote - * assistance or reject otherwise. - * @private - */ -remoting.It2MeHelpeeChannel.prototype.showConfirmDialogV1_ = function() { - var messageHeader = l10n.getTranslationOrError( - /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_1'); - var message1 = l10n.getTranslationOrError( - /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_2'); - var message2 = l10n.getTranslationOrError( - /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_3'); - var message = base.escapeHTML(messageHeader) + '\n' + - '- ' + base.escapeHTML(message1) + '\n' + - '- ' + base.escapeHTML(message2) + '\n'; - - if(window.confirm(message)) { - return Promise.resolve(); - } else { - return Promise.reject(new Error(remoting.Error.CANCELLED)); - } -}; - -/** - * @param {Bounds} bounds the bounds of the Hangouts Window. If set, the - * confirm dialog will be centered within |bounds|. - * @return {Promise} A promise that will resolve if the user accepts remote - * assistance or reject otherwise. - * @private - */ -remoting.It2MeHelpeeChannel.prototype.showConfirmDialogV2_ = function(bounds) { - var getToken = - base.Promise.as(chrome.identity.getAuthToken, [{interactive: false}]); - - return getToken.then( - /** @param {string} token */ - function(token) { - return remoting.HangoutConsentDialog.getInstance().show(Boolean(token), - bounds); - }); -}; - -/** - * @return {Promise} A promise that resolves when the host is initialized. - * @private - */ -remoting.It2MeHelpeeChannel.prototype.initializeHost_ = function() { - /** @type {remoting.It2MeHostFacade} */ - var host = this.host_; - - /** - * @param {function(*=):void} resolve - * @param {function(*=):void} reject - */ - return new Promise(function(resolve, reject) { - if (host.initialized()) { - resolve(true); - } else { - host.initialize(/** @type {function(*=):void} */ (resolve), - /** @type {function(*=):void} */ (reject)); - } - }); -}; - -/** - * @return {!Promise<string>} Promise that resolves with the OAuth token as the - * value. - */ -remoting.It2MeHelpeeChannel.prototype.fetchOAuthToken_ = function() { - if (base.isAppsV2()) { - return remoting.identity.getToken(); - } else { - var onError = function(/** * */ error) { - if (error === remoting.Error.NOT_AUTHENTICATED) { - return new Promise(function(resolve, reject) { - remoting.oauth2.doAuthRedirect(function() { - remoting.identity.getToken().then(resolve); - }); - }); - } - throw Error(remoting.Error.NOT_AUTHENTICATED); - }; - return /** @type {!Promise<string>} */ ( - remoting.identity.getToken().catch(onError)); - } -}; - -/** - * @param {string|Promise} token - * @return {Promise} Promise that resolves with the access token and the email - * of the user. - */ -remoting.It2MeHelpeeChannel.prototype.fetchEmail_ = function(token) { - /** @param {string} email */ - function onEmail (email) { - return { email: email, token: token }; - } - return remoting.identity.getEmail().then(onEmail); -}; - -/** - * Connects to the It2Me Native Messaging Host and retrieves the access code - * in the |onHostStateChanged_| callback. - * - * @param {string} email - * @param {string} accessToken - * @private - */ -remoting.It2MeHelpeeChannel.prototype.connectToHost_ = - function(email, accessToken) { - base.debug.assert(this.host_.initialized()); - this.host_.connect( - email, - 'oauth2:' + accessToken, - this.onHostStateChanged_.bind(this), - base.doNothing, // Ignore |onNatPolicyChanged|. - console.log.bind(console), // Forward logDebugInfo to console.log. - remoting.settings.XMPP_SERVER_FOR_IT2ME_HOST, - remoting.settings.XMPP_SERVER_USE_TLS, - remoting.settings.DIRECTORY_BOT_JID, - this.onHostConnectError_); -}; - -/** - * @param {remoting.Error} error - * @private - */ -remoting.It2MeHelpeeChannel.prototype.onHostConnectError_ = function(error) { - this.sendErrorResponse_(null, error); -}; - -/** - * @param {remoting.HostSession.State} state - * @private - */ -remoting.It2MeHelpeeChannel.prototype.onHostStateChanged_ = function(state) { - this.hostState_ = state; - var MessageTypes = remoting.It2MeHelpeeChannel.HangoutMessageTypes; - var HostState = remoting.HostSession.State; - - switch (state) { - case HostState.RECEIVED_ACCESS_CODE: - var accessCode = this.host_.getAccessCode(); - this.hangoutPort_.postMessage({ - method: MessageTypes.CONNECT_RESPONSE, - accessCode: accessCode - }); - break; - case HostState.CONNECTED: - case HostState.DISCONNECTED: - this.hangoutPort_.postMessage({ - method: MessageTypes.HOST_STATE_CHANGED, - state: state - }); - break; - case HostState.ERROR: - this.sendErrorResponse_(null, remoting.Error.UNEXPECTED); - break; - case HostState.INVALID_DOMAIN_ERROR: - this.sendErrorResponse_(null, remoting.Error.INVALID_HOST_DOMAIN); - break; - default: - // It is safe to ignore other state changes. - } -}; - -/** - * @param {?{method:string, data:Object<string,*>}} incomingMessage - * @param {string|Error} error - * @private - */ -remoting.It2MeHelpeeChannel.prototype.sendErrorResponse_ = - function(incomingMessage, error) { - if (error instanceof Error) { - error = error.message; - } - - console.error('Error responding to message method:' + - (incomingMessage ? incomingMessage.method : 'null') + - ' error:' + error); - this.hangoutPort_.postMessage({ - method: remoting.It2MeHelpeeChannel.HangoutMessageTypes.ERROR, - message: error, - request: incomingMessage - }); -};
diff --git a/remoting/webapp/crd/js/it2me_helper_channel.js b/remoting/webapp/crd/js/it2me_helper_channel.js deleted file mode 100644 index 5411ea38..0000000 --- a/remoting/webapp/crd/js/it2me_helper_channel.js +++ /dev/null
@@ -1,327 +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. - -/** - * @fileoverview - * - * It2MeHelperChannel relays messages between Hangouts and Chrome Remote Desktop - * (webapp) for the helper (the Hangouts participant who is giving remote - * assistance). - * - * It runs in the background page and contains two chrome.runtime.Port objects, - * representing connections to the webapp and hangout, respectively. - * - * Connection is always initiated from Hangouts by calling - * var port = chrome.runtime.connect({name:'it2me.helper.hangout'}, extId). - * port.postMessage('hello') - * If the webapp is not installed, |port.onDisconnect| will fire. - * If the webapp is installed, Hangouts will receive a hello response with the - * list of supported features. - * - * Hangout It2MeHelperChannel Chrome Remote Desktop - * |-----runtime.connect() ------>| | - * |--------hello message-------->| | - * | |<-----helloResponse message-----| - * |-------connect message------->| | - * | |-------appLauncher.launch()---->| - * | |<------runtime.connect()------- | - * | |<-----sessionStateChanged------ | - * |<----sessionStateChanged------| | - * - * Disconnection can be initiated from either side: - * 1. In the normal flow initiated from hangout - * Hangout It2MeHelperChannel Chrome Remote Desktop - * |-----disconnect message------>| | - * |<-sessionStateChanged(CLOSED)-| | - * | |-----appLauncher.close()------>| - * - * 2. In the normal flow initiated from webapp - * Hangout It2MeHelperChannel Chrome Remote Desktop - * | |<-sessionStateChanged(CLOSED)--| - * | |<--------port.disconnect()-----| - * |<--------port.disconnect()----| | - * - * 2. If hangout crashes - * Hangout It2MeHelperChannel Chrome Remote Desktop - * |---------port.disconnect()--->| | - * | |--------port.disconnect()----->| - * | |------appLauncher.close()----->| - * - * 3. If webapp crashes - * Hangout It2MeHelperChannel Chrome Remote Desktop - * | |<-------port.disconnect()------| - * |<-sessionStateChanged(FAILED)-| | - * |<--------port.disconnect()----| | - */ - -'use strict'; - -/** @suppress {duplicate} */ -var remoting = remoting || {}; - -/** - * @param {remoting.AppLauncher} appLauncher - * @param {chrome.runtime.Port} hangoutPort Represents an active connection to - * Hangouts. - * @param {function(remoting.It2MeHelperChannel)} onDisconnectCallback Callback - * to notify when the connection is torn down. IT2MeService uses this - * callback to dispose of the channel object. - * @constructor - */ -remoting.It2MeHelperChannel = - function(appLauncher, hangoutPort, onDisconnectCallback) { - - /** - * @type {remoting.AppLauncher} - * @private - */ - this.appLauncher_ = appLauncher; - - /** - * @type {chrome.runtime.Port} - * @private - */ - this.hangoutPort_ = hangoutPort; - - /** - * @type {chrome.runtime.Port} - * @private - */ - this.webappPort_ = null; - - /** - * @type {string} - * @private - */ - this.instanceId_ = ''; - - /** - * @type {remoting.ClientSession.State} - * @private - */ - this.sessionState_ = remoting.ClientSession.State.CONNECTING; - - /** - * @type {?function(remoting.It2MeHelperChannel)} - * @private - */ - this.onDisconnectCallback_ = onDisconnectCallback; - - this.onWebappMessageRef_ = this.onWebappMessage_.bind(this); - this.onWebappDisconnectRef_ = this.onWebappDisconnect_.bind(this); - this.onHangoutMessageRef_ = this.onHangoutMessage_.bind(this); - this.onHangoutDisconnectRef_ = this.onHangoutDisconnect_.bind(this); -}; - -/** @enum {string} */ -remoting.It2MeHelperChannel.HangoutMessageTypes = { - HELLO: 'hello', - HELLO_RESPONSE: 'helloResponse', - CONNECT: 'connect', - DISCONNECT: 'disconnect', - ERROR: 'error' -}; - -/** @enum {string} */ -remoting.It2MeHelperChannel.Features = { - REMOTE_ASSISTANCE: 'remoteAssistance' -}; - -/** @enum {string} */ -remoting.It2MeHelperChannel.WebappMessageTypes = { - SESSION_STATE_CHANGED: 'sessionStateChanged' -}; - -remoting.It2MeHelperChannel.prototype.init = function() { - this.hangoutPort_.onMessage.addListener(this.onHangoutMessageRef_); - this.hangoutPort_.onDisconnect.addListener(this.onHangoutDisconnectRef_); -}; - -/** @return {string} */ -remoting.It2MeHelperChannel.prototype.instanceId = function() { - return this.instanceId_; -}; - -/** - * @param {{method:string, data:Object<string,*>}} message - * @return {boolean} whether the message is handled or not. - * @private - */ -remoting.It2MeHelperChannel.prototype.onHangoutMessage_ = function(message) { - try { - var MessageTypes = remoting.It2MeHelperChannel.HangoutMessageTypes; - switch (message.method) { - case MessageTypes.CONNECT: - this.launchWebapp_(message); - return true; - case MessageTypes.DISCONNECT: - this.closeWebapp_(message); - return true; - case MessageTypes.HELLO: - this.hangoutPort_.postMessage({ - method: MessageTypes.HELLO_RESPONSE, - supportedFeatures: base.values(remoting.It2MeHelperChannel.Features) - }); - return true; - } - throw new Error('Unknown message method=' + message.method); - } catch(/** @type {*} */ e) { - var error = /** @type {Error} */ (e); - this.sendErrorResponse_(this.hangoutPort_, error, message); - } - return false; -}; - -/** - * Disconnect the existing connection to the helpee. - * - * @param {{method:string, data:Object<string,*>}} message - * @private - */ -remoting.It2MeHelperChannel.prototype.closeWebapp_ = - function(message) { - // TODO(kelvinp): Closing the v2 app currently doesn't disconnect the IT2me - // session (crbug.com/402137), so send an explicit notification to Hangouts. - this.sessionState_ = remoting.ClientSession.State.CLOSED; - this.hangoutPort_.postMessage({ - method: 'sessionStateChanged', - state: this.sessionState_ - }); - this.appLauncher_.close(this.instanceId_); -}; - -/** - * Launches the web app. - * - * @param {{method:string, data:Object<string,*>}} message - * @private - */ -remoting.It2MeHelperChannel.prototype.launchWebapp_ = - function(message) { - var accessCode = getStringAttr(message, 'accessCode'); - if (!accessCode) { - throw new Error('Access code is missing'); - } - - /** - * @this {remoting.It2MeHelperChannel} - * @param {string} instanceId - */ - var setInstance = function(instanceId) { - this.instanceId_ = instanceId; - }; - - // Launch the webapp. - this.appLauncher_.launch({ - mode: 'hangout', - accessCode: accessCode - }).then(setInstance.bind(this)); -}; - -/** - * @private - */ -remoting.It2MeHelperChannel.prototype.onHangoutDisconnect_ = function() { - this.appLauncher_.close(this.instanceId_); - this.unhookPorts_(); -}; - -/** - * @param {chrome.runtime.Port} port The port represents a connection to the - * webapp. - * @param {string} id The id of the tab or window that is hosting the webapp. - */ -remoting.It2MeHelperChannel.prototype.onWebappConnect = function(port, id) { - base.debug.assert(id === this.instanceId_); - base.debug.assert(this.hangoutPort_ !== null); - - // Hook listeners. - port.onMessage.addListener(this.onWebappMessageRef_); - port.onDisconnect.addListener(this.onWebappDisconnectRef_); - this.webappPort_ = port; -}; - -/** @param {chrome.runtime.Port} port The webapp port. */ -remoting.It2MeHelperChannel.prototype.onWebappDisconnect_ = function(port) { - // If the webapp port got disconnected while the session is still connected, - // treat it as an error. - var States = remoting.ClientSession.State; - if (this.sessionState_ === States.CONNECTING || - this.sessionState_ === States.CONNECTED) { - this.sessionState_ = States.FAILED; - this.hangoutPort_.postMessage({ - method: 'sessionStateChanged', - state: this.sessionState_ - }); - } - this.unhookPorts_(); -}; - -/** - * @param {{method:string, data:Object<string,*>}} message - * @private - */ -remoting.It2MeHelperChannel.prototype.onWebappMessage_ = function(message) { - try { - console.log('It2MeHelperChannel id=' + this.instanceId_ + - ' incoming message method=' + message.method); - var MessageTypes = remoting.It2MeHelperChannel.WebappMessageTypes; - switch (message.method) { - case MessageTypes.SESSION_STATE_CHANGED: - var state = getNumberAttr(message, 'state'); - this.sessionState_ = - /** @type {remoting.ClientSession.State} */(state); - this.hangoutPort_.postMessage(message); - return true; - } - throw new Error('Unknown message method=' + message.method); - } catch(/** @type {*} */ e) { - var error = /** @type {Error} */ (e); - this.sendErrorResponse_(this.webappPort_, error, message); - } - return false; -}; - -remoting.It2MeHelperChannel.prototype.unhookPorts_ = function() { - if (this.webappPort_) { - this.webappPort_.onMessage.removeListener(this.onWebappMessageRef_); - this.webappPort_.onDisconnect.removeListener(this.onWebappDisconnectRef_); - this.webappPort_.disconnect(); - this.webappPort_ = null; - } - - if (this.hangoutPort_) { - this.hangoutPort_.onMessage.removeListener(this.onHangoutMessageRef_); - this.hangoutPort_.onDisconnect.removeListener(this.onHangoutDisconnectRef_); - this.hangoutPort_.disconnect(); - this.hangoutPort_ = null; - } - - if (this.onDisconnectCallback_) { - this.onDisconnectCallback_(this); - this.onDisconnectCallback_ = null; - } -}; - -/** - * @param {chrome.runtime.Port} port - * @param {string|Error} error - * @param {?{method:string, data:Object<string,*>}=} opt_incomingMessage - * @private - */ -remoting.It2MeHelperChannel.prototype.sendErrorResponse_ = - function(port, error, opt_incomingMessage) { - if (error instanceof Error) { - error = error.message; - } - - console.error('Error responding to message method:' + - (opt_incomingMessage ? opt_incomingMessage.method : 'null') + - ' error:' + error); - port.postMessage({ - method: remoting.It2MeHelperChannel.HangoutMessageTypes.ERROR, - message: error, - request: opt_incomingMessage - }); -};
diff --git a/remoting/webapp/crd/js/it2me_service.js b/remoting/webapp/crd/js/it2me_service.js deleted file mode 100644 index 8135e33..0000000 --- a/remoting/webapp/crd/js/it2me_service.js +++ /dev/null
@@ -1,178 +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. - -/** - * @fileoverview - * It2MeService listens to incoming connections requests from Hangouts - * and the webapp and creates a It2MeHelperChannel between them. - * It supports multiple helper sessions, but only a single helpee. - */ - -'use strict'; - -/** @suppress {duplicate} */ -var remoting = remoting || {}; - -/** - * @param {remoting.AppLauncher} appLauncher - * - * @constructor - * @implements {base.Disposable} - */ -remoting.It2MeService = function(appLauncher) { - /** - * @type {remoting.AppLauncher} - * @private - */ - this.appLauncher_ = appLauncher; - - /** - * @type {Array<remoting.It2MeHelperChannel>} - * @private - */ - this.helpers_ = []; - - /** @private */ - this.helpee_ = null; - - this.onWebappConnectRef_ = this.onWebappConnect_.bind(this); - this.onConnectExternalRef_ = this.onConnectExternal_.bind(this); -}; - -/** @enum {string} */ -remoting.It2MeService.ConnectionTypes = { - HELPER_HANGOUT: 'it2me.helper.hangout', - HELPEE_HANGOUT: 'it2me.helpee.hangout', - HELPER_WEBAPP: 'it2me.helper.webapp' -}; - -/** - * Starts listening to external connection from Hangouts and the webapp. - */ -remoting.It2MeService.prototype.init = function() { - chrome.runtime.onConnect.addListener(this.onWebappConnectRef_); - chrome.runtime.onConnectExternal.addListener(this.onConnectExternalRef_); -}; - -remoting.It2MeService.prototype.dispose = function() { - chrome.runtime.onConnect.removeListener(this.onWebappConnectRef_); - chrome.runtime.onConnectExternal.removeListener( - this.onConnectExternalRef_); -}; - -/** - * This function is called when Hangouts connects via chrome.runtime.connect. - * Only web pages that are white-listed in the manifest are allowed to connect. - * - * @param {chrome.runtime.Port} port - * @private - */ -remoting.It2MeService.prototype.onConnectExternal_ = function(port) { - var ConnectionTypes = remoting.It2MeService.ConnectionTypes; - try { - switch (port.name) { - case ConnectionTypes.HELPER_HANGOUT: - this.handleExternalHelperConnection_(port); - return true; - case ConnectionTypes.HELPEE_HANGOUT: - this.handleExternalHelpeeConnection_(port); - return true; - default: - throw new Error('Unsupported port - ' + port.name); - } - } catch (/** @type {*} */ e) { - var error = /**@type {Error} */ (e); - console.error(error); - port.disconnect(); - } - return false; -}; - -/** - * @param {chrome.runtime.Port} port - * @private - */ -remoting.It2MeService.prototype.onWebappConnect_ = function(port) { - try { - console.log('Incoming helper connection from webapp.'); - - // The senderId (tabId or windowId) of the webapp is embedded in the port - // name with the format port_name@senderId. - var parts = port.name.split('@'); - var portName = parts[0]; - var senderId = parts[1]; - var ConnectionTypes = remoting.It2MeService.ConnectionTypes; - if (portName === ConnectionTypes.HELPER_WEBAPP && senderId !== undefined) { - for (var i = 0; i < this.helpers_.length; i++) { - var helper = this.helpers_[i]; - if (helper.instanceId() === senderId) { - helper.onWebappConnect(port, senderId); - return; - } - } - } - throw new Error('No matching hangout connection found for ' + port.name); - } catch (/** @type {*} */ e) { - var error = /** @type {Error} */ (e); - console.error(error); - port.disconnect(); - } -}; - -/** - * @param {remoting.It2MeHelperChannel} helper - */ -remoting.It2MeService.prototype.onHelperChannelDisconnected = function(helper) { - for (var i = 0; i < this.helpers_.length; i++) { - if (helper === this.helpers_[i]) { - this.helpers_.splice(i, 1); - } - } -}; - -remoting.It2MeService.prototype.onHelpeeChannelDisconnected = function() { - base.debug.assert(this.helpee_ !== null); - this.helpee_ = null; -}; - -/** - * @param {chrome.runtime.Port} port - * @private - */ -remoting.It2MeService.prototype.handleExternalHelperConnection_ = - function(port) { - if (this.helpee_) { - console.error( - 'Cannot start a helper session while a helpee session is in process.'); - port.disconnect(); - return; - } - - console.log('Incoming helper connection from Hangouts'); - var helper = new remoting.It2MeHelperChannel( - this.appLauncher_, port, this.onHelperChannelDisconnected.bind(this)); - helper.init(); - this.helpers_.push(helper); -}; - -/** - * @param {chrome.runtime.Port} hangoutPort Represents a connection to Hangouts. - * @private - */ -remoting.It2MeService.prototype.handleExternalHelpeeConnection_ = - function(hangoutPort) { - if (this.helpee_) { - console.error('An existing helpee session is in process.'); - hangoutPort.disconnect(); - return; - } - - console.log('Incoming helpee connection from Hangouts'); - this.helpee_ = new remoting.It2MeHelpeeChannel( - hangoutPort, - new remoting.It2MeHostFacade(), - new remoting.HostInstaller(), - this.onHelpeeChannelDisconnected.bind(this)); - this.helpee_.init(); -};
diff --git a/remoting/webapp/crd/js/local_host_section.js b/remoting/webapp/crd/js/local_host_section.js new file mode 100644 index 0000000..50bebe7 --- /dev/null +++ b/remoting/webapp/crd/js/local_host_section.js
@@ -0,0 +1,162 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var remoting = remoting || {}; + +(function() { + +'use strict'; + +/** + * @param {HTMLElement} rootElement + * @param {remoting.LocalHostSection.Controller} controller + * + * @constructor + * @implements {base.Disposable} + */ +remoting.LocalHostSection = function(rootElement, controller) { + /** @private */ + this.rootElement_ = rootElement; + /** @private */ + this.controller_ = controller; + /** @private {remoting.Host} */ + this.host_ = null; + /** @private {remoting.HostController.State} */ + this.state_ = remoting.HostController.State.UNKNOWN; + + var hostContainer = rootElement.querySelector('.host-entry'); + /** @private */ + this.hostTableEntry_ = new remoting.HostTableEntry( + parseInt(chrome.runtime.getManifest().version, 10), + remoting.connectMe2Me, + this.rename_.bind(this)); + hostContainer.appendChild(this.hostTableEntry_.element()); + this.hostTableEntry_.element().id = 'local-host-connect-button'; + + var startButton = rootElement.querySelector('.start-daemon'); + var stopButton = rootElement.querySelector('.stop-daemon'); + var stopLocalDaemonButton = rootElement.querySelector('.stop-local-daemon'); + var changePINButton = rootElement.querySelector('.change-daemon-pin'); + + /** @private */ + this.eventHooks_ = new base.Disposables( + new base.DomEventHook(startButton, 'click', + controller.start.bind(controller), false), + new base.DomEventHook(stopButton, 'click', + controller.stop.bind(controller), false), + new base.DomEventHook(stopLocalDaemonButton, 'click', + controller.stop.bind(controller), false), + new base.DomEventHook(changePINButton, 'click', + controller.changePIN.bind(controller), false)); + /** @private */ + this.hasError_ = false; +}; + +remoting.LocalHostSection.prototype.dispose = function() { + base.dispose(this.eventHooks_); + this.eventHooks_ = null; +}; + +/** + * @param {remoting.Host} host + * @param {remoting.HostController.State} state + * @param {boolean} hasError Whether the host list is in an error state. + */ +remoting.LocalHostSection.prototype.setModel = function(host, state, hasError) { + this.host_ = host; + this.state_ = state; + this.hasError_ = hasError; + this.updateUI_(); +}; + +/** + * @return {?string} + */ +remoting.LocalHostSection.prototype.getHostId = function() { + return this.host_ ? this.host_.hostId : null; +}; + +/** @return {boolean} */ +remoting.LocalHostSection.prototype.isEnabled_ = function() { + return (this.state_ == remoting.HostController.State.STARTING) || + (this.state_ == remoting.HostController.State.STARTED); +}; + +/** @return {boolean} */ +remoting.LocalHostSection.prototype.canChangeState = function() { + // The local host cannot be stopped or started if the host controller is not + // implemented for this platform. + var state = this.state_; + if (state === remoting.HostController.State.NOT_IMPLEMENTED || + state === remoting.HostController.State.UNKNOWN) { + return false; + } + + // Return false if the host is uninstallable. The NOT_INSTALLED check is + // required to handle the special case for Ubuntu, as we report the host as + // uninstallable on Linux. + if (!remoting.isMe2MeInstallable() && + state === remoting.HostController.State.NOT_INSTALLED) { + return false; + } + + // In addition, it cannot be started if there is an error (in many error + // states, the start operation will fail anyway, but even if it succeeds, the + // chance of a related but hard-to-diagnose future error is high). + return this.isEnabled_() || !this.hasError_; +}; + +/** @private */ +remoting.LocalHostSection.prototype.updateUI_ = function() { + this.hostTableEntry_.setHost(this.host_); + + // Disable elements. + var enabled = this.isEnabled_(); + var canChangeLocalHostState = this.canChangeState(); + var daemonState = ''; + if (!enabled) { + daemonState = 'disabled'; + } else if (this.host_ !== null) { + daemonState = 'enabled'; + } else { + daemonState = 'enabled-other-account'; + } + remoting.updateModalUi(daemonState, 'data-daemon-state'); + this.rootElement_.hidden = !canChangeLocalHostState; +}; + +remoting.LocalHostSection.prototype.rename_ = function() { + return this.controller_.rename(this.hostTableEntry_); +}; + +/** + * @constructor + * @param {remoting.HostList} hostList + * @param {remoting.HostSetupDialog} setupDialog + */ +remoting.LocalHostSection.Controller = function(hostList, setupDialog) { + /** @private */ + this.hostList_ = hostList; + this.setupDialog_ = setupDialog; +}; + +remoting.LocalHostSection.Controller.prototype.start = function() { + this.setupDialog_.showForStart(); +}; + +remoting.LocalHostSection.Controller.prototype.stop = function() { + this.setupDialog_.showForStop(); +}; + +remoting.LocalHostSection.Controller.prototype.changePIN = function() { + this.setupDialog_.showForPin(); +}; + +/** @param {remoting.HostTableEntry} host */ +remoting.LocalHostSection.Controller.prototype.rename = function(host) { + this.hostList_.renameHost(host); +}; + +}()); +
diff --git a/remoting/webapp/crd/js/log_to_server.js b/remoting/webapp/crd/js/log_to_server.js index 8b87f1b5c..fcd7e05 100644 --- a/remoting/webapp/crd/js/log_to_server.js +++ b/remoting/webapp/crd/js/log_to_server.js
@@ -25,7 +25,7 @@ /** @private */ this.sessionIdGenerationTime_ = 0; /** @private */ - this.sessionStartTime_ = 0; + this.sessionStartTime_ = new Date().getTime(); /** @private */ this.signalStrategy_ = signalStrategy; /** @private */ @@ -60,12 +60,6 @@ remoting.LogToServer.prototype.logClientSessionStateChange = function(state, connectionError) { this.maybeExpireSessionId_(); - // Set the session start time if we haven't done so already. - if (remoting.LogToServer.isStartOfSession_(state)) { - if (this.sessionStartTime_ == 0) { - this.sessionStartTime_ = new Date().getTime(); - } - } // Log the session state change. var entry = remoting.ServerLogEntry.makeClientSessionStateChange( state, connectionError, this.mode_); @@ -73,15 +67,6 @@ entry.addChromeVersionField(); entry.addWebappVersionField(); entry.addSessionIdField(this.sessionId_); - // Maybe clear the session start time, and log the session duration. - if (remoting.LogToServer.shouldAddDuration_(state) && - (this.sessionStartTime_ != 0)) { - entry.addSessionDurationField( - (new Date().getTime() - this.sessionStartTime_) / 1000.0); - if (remoting.LogToServer.isEndOfSession_(state)) { - this.sessionStartTime_ = 0; - } - } this.log_(entry); // Don't accumulate connection statistics across state changes. this.logAccumulatedStatistics_(); @@ -104,13 +89,12 @@ /** * @param {remoting.SignalStrategy.Type} strategyType * @param {remoting.FallbackSignalStrategy.Progress} progress - * @param {number} elapsedTimeInMs */ remoting.LogToServer.prototype.logSignalStrategyProgress = - function(strategyType, progress, elapsedTimeInMs) { + function(strategyType, progress) { this.maybeExpireSessionId_(); var entry = remoting.ServerLogEntry.makeSignalStrategyProgress( - this.sessionId_, strategyType, progress, elapsedTimeInMs); + this.sessionId_, strategyType, progress); this.log_(entry); }; @@ -143,20 +127,6 @@ (state == remoting.ClientSession.State.CONNECTION_CANCELED)); }; -/** - * Whether the duration should be added to the log entry for this state. - * - * @private - * @param {remoting.ClientSession.State} state - * @return {boolean} - */ -remoting.LogToServer.shouldAddDuration_ = function(state) { - // Duration is added to log entries at the end of the session, as well as at - // some intermediate states where it is relevant (e.g. to determine how long - // it took for a session to become CONNECTED). - return (remoting.LogToServer.isEndOfSession_(state) || - (state == remoting.ClientSession.State.CONNECTED)); -}; /** * Logs connection statistics. @@ -203,6 +173,11 @@ * @param {remoting.ServerLogEntry} entry */ remoting.LogToServer.prototype.log_ = function(entry) { + // Log the time taken to get to this point from the time this session started. + var sessionDurationInSeconds = + (new Date().getTime() - this.sessionStartTime_) / 1000.0; + entry.addSessionDuration(sessionDurationInSeconds); + // Send the stanza to the debug log. console.log('Enqueueing log entry:'); entry.toDebugLog(1);
diff --git a/remoting/webapp/crd/js/oauth2.js b/remoting/webapp/crd/js/oauth2.js index 1074ed2..0ad1f7a7 100644 --- a/remoting/webapp/crd/js/oauth2.js +++ b/remoting/webapp/crd/js/oauth2.js
@@ -23,7 +23,10 @@ remoting.oauth2 = null; -/** @constructor */ +/** + * @constructor + * @extends {remoting.Identity} + */ remoting.OAuth2 = function() { }; @@ -445,31 +448,3 @@ reject); }); }; - -/** - * If the user's email address is cached, return it, otherwise return null. - * - * @return {?string} The email address, if it has been cached by a previous call - * to getEmail or getUserInfo, otherwise null. - */ -remoting.OAuth2.prototype.getCachedEmail = function() { - var value = window.localStorage.getItem(this.KEY_EMAIL_); - if (typeof value == 'string') { - return value; - } - return null; -}; - -/** - * If the user's full name is cached, return it, otherwise return null. - * - * @return {?string} The user's full name, if it has been cached by a previous - * call to getUserInfo, otherwise null. - */ -remoting.OAuth2.prototype.getCachedUserFullName = function() { - var value = window.localStorage.getItem(this.KEY_FULLNAME_); - if (typeof value == 'string') { - return value; - } - return null; -};
diff --git a/remoting/webapp/crd/js/remoting.js b/remoting/webapp/crd/js/remoting.js index bc23d7c..d160add 100644 --- a/remoting/webapp/crd/js/remoting.js +++ b/remoting/webapp/crd/js/remoting.js
@@ -182,7 +182,7 @@ document.getElementById('token-refresh-error-message'), error); var auth_failed = (error == remoting.Error.AUTHENTICATION_FAILED); - if (base.isAppsV2()) { + if (auth_failed && base.isAppsV2()) { remoting.handleAuthFailureAndRelaunch(); } else { document.getElementById('token-refresh-auth-failed').hidden = !auth_failed;
diff --git a/remoting/webapp/crd/js/server_log_entry.js b/remoting/webapp/crd/js/server_log_entry.js index 7d848aa5..b7fdd3d 100644 --- a/remoting/webapp/crd/js/server_log_entry.js +++ b/remoting/webapp/crd/js/server_log_entry.js
@@ -47,8 +47,8 @@ remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_PROGRESS_ = 'signal-strategy-progress'; /** @private */ -remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_ELAPSED_TIME_ = - 'signal-strategy-elapsed-time'; +remoting.ServerLogEntry.KEY_SESSION_DURATION_SECONDS_ = 'session-duration'; + /** * @private @@ -119,8 +119,6 @@ } }; -/** @private */ -remoting.ServerLogEntry.KEY_SESSION_DURATION_ = 'session-duration'; /** @private */ remoting.ServerLogEntry.VALUE_EVENT_NAME_CONNECTION_STATISTICS_ = @@ -242,17 +240,6 @@ }; /** - * Adds a session duration to a log entry. - * - * @param {number} sessionDuration - */ -remoting.ServerLogEntry.prototype.addSessionDurationField = function( - sessionDuration) { - this.set_(remoting.ServerLogEntry.KEY_SESSION_DURATION_, - sessionDuration.toString()); -}; - -/** * Makes a log entry for a set of connection statistics. * Returns null if all the statistics were zero. * @@ -357,11 +344,10 @@ * @param {string} sessionId * @param {remoting.SignalStrategy.Type} strategyType * @param {remoting.FallbackSignalStrategy.Progress} progress - * @param {number} elapsedTimeInMs * @return {remoting.ServerLogEntry} */ remoting.ServerLogEntry.makeSignalStrategyProgress = - function(sessionId, strategyType, progress, elapsedTimeInMs) { + function(sessionId, strategyType, progress) { var entry = new remoting.ServerLogEntry(); entry.set_(remoting.ServerLogEntry.KEY_ROLE_, remoting.ServerLogEntry.VALUE_ROLE_CLIENT_); @@ -371,8 +357,6 @@ entry.addSessionIdField(sessionId); entry.set_(remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_TYPE_, strategyType); entry.set_(remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_PROGRESS_, progress); - entry.set_(remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_ELAPSED_TIME_, - String(elapsedTimeInMs)); return entry; }; @@ -467,6 +451,18 @@ }; /** + * Adds a field to this log entry specifying the time in seconds since the start + * of the session to the current event. + * @param {number} sessionDurationInSeconds + */ +remoting.ServerLogEntry.prototype.addSessionDuration = + function(sessionDurationInSeconds) { + this.set_(remoting.ServerLogEntry.KEY_SESSION_DURATION_SECONDS_, + String(sessionDurationInSeconds)); +}; + + +/** * Adds a field specifying the browser version to this log entry. */ remoting.ServerLogEntry.prototype.addChromeVersionField = function() {
diff --git a/remoting/webapp/crd/js/session_connector_impl.js b/remoting/webapp/crd/js/session_connector_impl.js index a89fdd4f1..fdbd6f0 100644 --- a/remoting/webapp/crd/js/session_connector_impl.js +++ b/remoting/webapp/crd/js/session_connector_impl.js
@@ -117,32 +117,6 @@ */ remoting.SessionConnectorImpl.prototype.reset = function() { /** - * For paired connections, the client id of this device, issued by the host. - * - * @type {string} - * @private - */ - this.clientPairingId_ = ''; - - /** - * For paired connections, the paired secret for this device, issued by the - * host. - * - * @type {string} - * @private - */ - this.clientPairedSecret_ = ''; - - /** - * String used to authenticate to the host on connection. For IT2Me, this is - * the access code; for Me2Me it is the PIN. - * - * @type {string} - * @private - */ - this.passPhrase_ = ''; - - /** * @type {remoting.Host} * @private */ @@ -167,19 +141,10 @@ this.pendingXhr_ = null; /** - * Function to interactively obtain the PIN from the user. - * @type {function(boolean, function(string):void):void} + * @type {remoting.CredentialsProvider} * @private */ - this.fetchPin_ = function(onPinFetched) {}; - - /** - * @type {function(string, string, string, - * function(string, string):void): void} - * @private - */ - this.fetchThirdPartyToken_ = function( - tokenUrl, hostPublicKey, scope, onThirdPartyTokenFetched) {}; + this.credentialsProvider_ = null; }; /** @@ -191,10 +156,6 @@ * @param {remoting.Host} host The Me2Me host to which to connect. * @param {function(boolean, function(string):void):void} fetchPin Function to * interactively obtain the PIN from the user. - * @param {function(string, string, string, - * function(string, string): void): void} - * fetchThirdPartyToken Function to obtain a token from a third party - * authentication server. * @param {string} clientPairingId The client id issued by the host when * this device was paired, if it is already paired. * @param {string} clientPairedSecret The shared secret issued by the host when @@ -206,8 +167,12 @@ clientPairingId, clientPairedSecret) { this.connectionMode_ = remoting.DesktopConnectedView.Mode.ME2ME; this.logHostOfflineErrors_ = false; - this.connectMe2MeInternal_(host, fetchPin, fetchThirdPartyToken, - clientPairingId, clientPairedSecret); + var credentialsProvider = new remoting.CredentialsProvider({ + fetchPin: fetchPin, + pairingInfo: { id: clientPairingId, secret: clientPairedSecret }, + fetchThirdPartyToken: fetchThirdPartyToken + }); + this.connectInternal_(host, credentialsProvider); }; /** @@ -222,8 +187,7 @@ remoting.SessionConnectorImpl.prototype.retryConnectMe2Me = function(host) { this.connectionMode_ = remoting.DesktopConnectedView.Mode.ME2ME; this.logHostOfflineErrors_ = true; - this.connectMe2MeInternal_(host, this.fetchPin_, this.fetchThirdPartyToken_, - this.clientPairingId_, this.clientPairedSecret_); + this.connectInternal_(host, this.credentialsProvider_); }; /** @@ -240,7 +204,10 @@ function(host, fetchThirdPartyToken) { this.connectionMode_ = remoting.DesktopConnectedView.Mode.APP_REMOTING; this.logHostOfflineErrors_ = true; - this.connectMe2MeInternal_(host, function() {}, fetchThirdPartyToken, '', ''); + var credentialsProvider = new remoting.CredentialsProvider({ + fetchThirdPartyToken : fetchThirdPartyToken + }); + this.connectInternal_(host, credentialsProvider); }; /** @@ -251,38 +218,26 @@ */ remoting.SessionConnectorImpl.prototype.updatePairingInfo = function(clientId, sharedSecret) { - this.clientPairingId_ = clientId; - this.clientPairedSecret_ = sharedSecret; + var pairingInfo = this.credentialsProvider_.getPairingInfo(); + pairingInfo.id = clientId; + pairingInfo.secret = sharedSecret; }; /** - * Initiate a Me2Me connection. + * Initiates a connection. * * @param {remoting.Host} host the Host to connect to. - * @param {function(boolean, function(string):void):void} fetchPin Function to - * interactively obtain the PIN from the user. - * @param {function(string, string, string, - * function(string, string): void): void} - * fetchThirdPartyToken Function to obtain a token from a third party - * authentication server. - * @param {string} clientPairingId The client id issued by the host when - * this device was paired, if it is already paired. - * @param {string} clientPairedSecret The shared secret issued by the host when - * this device was paired, if it is already paired. + * @param {remoting.CredentialsProvider} credentialsProvider * @return {void} Nothing. * @private */ -remoting.SessionConnectorImpl.prototype.connectMe2MeInternal_ = - function(host, fetchPin, fetchThirdPartyToken, - clientPairingId, clientPairedSecret) { +remoting.SessionConnectorImpl.prototype.connectInternal_ = + function(host, credentialsProvider) { // Cancel any existing connect operation. this.cancel(); this.host_ = host; - this.fetchPin_ = fetchPin; - this.fetchThirdPartyToken_ = fetchThirdPartyToken; - this.updatePairingInfo(clientPairingId, clientPairedSecret); - + this.credentialsProvider_ = credentialsProvider; this.connectSignaling_(); }; @@ -305,9 +260,10 @@ this.onError_(remoting.Error.INVALID_ACCESS_CODE); return; } - var hostId = normalizedAccessCode.substring(0, kSupportIdLen); - this.passPhrase_ = normalizedAccessCode; + this.credentialsProvider_ = new remoting.CredentialsProvider({ + accessCode: normalizedAccessCode + }); this.connectionMode_ = remoting.DesktopConnectedView.Mode.IT2ME; remoting.identity.getToken().then( this.connectIT2MeWithToken_.bind(this, hostId), @@ -325,9 +281,7 @@ return; } this.logHostOfflineErrors_ = false; - this.connectMe2MeInternal_(this.host_, this.fetchPin_, - this.fetchThirdPartyToken_, this.clientPairingId_, - this.clientPairedSecret_); + this.connectInternal_(this.host_, this.credentialsProvider_); }; /** @@ -484,13 +438,9 @@ this.clientSession_ = null; } - var authenticationMethods = - 'third_party,spake2_pair,spake2_hmac,spake2_plain'; this.clientSession_ = new remoting.ClientSession( - this.host_, this.signalStrategy_, this.clientContainer_, this.passPhrase_, - this.fetchPin_, this.fetchThirdPartyToken_, authenticationMethods, - this.connectionMode_, this.clientPairingId_, this.clientPairedSecret_, - this.defaultRemapKeys_); + this.host_, this.signalStrategy_, this.credentialsProvider_, + this.clientContainer_, this.connectionMode_, this.defaultRemapKeys_); this.clientSession_.logHostOfflineErrors(this.logHostOfflineErrors_); this.clientSession_.addEventListener( remoting.ClientSession.Events.stateChanged, @@ -533,7 +483,10 @@ break; case remoting.ClientSession.State.CONNECTING: - console.log('Connecting as ' + remoting.identity.getCachedEmail()); + remoting.identity.getEmail().then( + function(/** string */ email) { + console.log('Connecting as ' + email); + }); break; case remoting.ClientSession.State.INITIALIZING:
diff --git a/remoting/webapp/crd/js/smart_reconnector.js b/remoting/webapp/crd/js/smart_reconnector.js index ed76ac6f..0af7210 100644 --- a/remoting/webapp/crd/js/smart_reconnector.js +++ b/remoting/webapp/crd/js/smart_reconnector.js
@@ -68,7 +68,7 @@ remoting.SmartReconnector.prototype = { reconnect_: function() { this.cancelPending_(); - remoting.disconnect(); + remoting.app.disconnect(); remoting.setMode(remoting.AppMode.CLIENT_CONNECTING); this.connector_.reconnect(); },
diff --git a/remoting/webapp/crd/js/toolbar.js b/remoting/webapp/crd/js/toolbar.js index 95113aa..e901b87 100644 --- a/remoting/webapp/crd/js/toolbar.js +++ b/remoting/webapp/crd/js/toolbar.js
@@ -63,9 +63,10 @@ window.addEventListener('mousemove', remoting.Toolbar.onMouseMove, false); window.addEventListener('resize', this.center.bind(this), false); - registerEventListener('toolbar-disconnect', 'click', remoting.disconnect); - registerEventListener('toolbar-stub', 'click', - function() { remoting.toolbar.toggle(); }); + registerEventListener('toolbar-disconnect', 'click', + remoting.app.disconnect.bind(remoting.app)); + registerEventListener('toolbar-stub', + 'click', function() { remoting.toolbar.toggle(); }); // Prevent the preview canceling if the user is interacting with the tool-bar. /** @type {remoting.Toolbar} */
diff --git a/remoting/webapp/crd/js/ui_mode.js b/remoting/webapp/crd/js/ui_mode.js index 89c833e..96a2021d 100644 --- a/remoting/webapp/crd/js/ui_mode.js +++ b/remoting/webapp/crd/js/ui_mode.js
@@ -123,20 +123,9 @@ if (mode == remoting.AppMode.IN_SESSION) { document.removeEventListener('keydown', remoting.ConnectionStats.onKeydown, false); - if ('hidden' in document) { - document.addEventListener('visibilitychange', - remoting.onVisibilityChanged, false); - } else { - document.addEventListener('webkitvisibilitychange', - remoting.onVisibilityChanged, false); - } } else { document.addEventListener('keydown', remoting.ConnectionStats.onKeydown, false); - document.removeEventListener('visibilitychange', - remoting.onVisibilityChanged, false); - document.removeEventListener('webkitvisibilitychange', - remoting.onVisibilityChanged, false); // TODO(jamiewalch): crbug.com/252796: Remove this once crbug.com/240772 // is fixed. var scroller = document.getElementById('scroller');
diff --git a/remoting/webapp/crd/js/window_frame.js b/remoting/webapp/crd/js/window_frame.js index 5e6a841..f689759 100644 --- a/remoting/webapp/crd/js/window_frame.js +++ b/remoting/webapp/crd/js/window_frame.js
@@ -150,7 +150,7 @@ if (chrome.app.window.current().isFullscreen()) { chrome.app.window.current().restore(); } - remoting.disconnect(); + remoting.app.disconnect(); }; /**
diff --git a/remoting/webapp/crd/js/xmpp_login_handler.js b/remoting/webapp/crd/js/xmpp_login_handler.js index 74be464..f91ef55 100644 --- a/remoting/webapp/crd/js/xmpp_login_handler.js +++ b/remoting/webapp/crd/js/xmpp_login_handler.js
@@ -65,6 +65,12 @@ this.streamParser_ = null; } +/** @return {function(string, remoting.XmppStreamParser):void} */ +remoting.XmppLoginHandler.prototype.getHandshakeDoneCallbackForTesting = + function() { + return this.onHandshakeDoneCallback_; +}; + /** * States the handshake goes through. States are iterated from INIT to DONE * sequentially, except for ERROR state which may be accepted at any point.
diff --git a/remoting/webapp/crd/manifest.json.jinja2 b/remoting/webapp/crd/manifest.json.jinja2 index 2e71a42..029e096 100644 --- a/remoting/webapp/crd/manifest.json.jinja2 +++ b/remoting/webapp/crd/manifest.json.jinja2
@@ -60,11 +60,6 @@ "pages": [ "wcs_sandbox.html" ] }, {% endif %} - "externally_connectable": { - "matches": [ - "https://*.google.com/hangouts*" - ] - }, "permissions": [ "{{ OAUTH2_ACCOUNTS_HOST }}/*", "{{ OAUTH2_API_BASE_URL }}/*",
diff --git a/remoting/webapp/js_proto/chrome_cast_proto.js b/remoting/webapp/js_proto/chrome_cast_proto.js new file mode 100644 index 0000000..58fa914 --- /dev/null +++ b/remoting/webapp/js_proto/chrome_cast_proto.js
@@ -0,0 +1,129 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains various hacks needed to inform JSCompiler of various +// WebKit- and Chrome-specific properties and methods. It is used only with +// JSCompiler to verify the type-correctness of our code. + +/** @type {Object} */ +chrome.cast = {}; + +/** @constructor */ +chrome.cast.AutoJoinPolicy = function() {}; + +/** @type {chrome.cast.AutoJoinPolicy} */ +chrome.cast.AutoJoinPolicy.PAGE_SCOPED; + +/** @type {chrome.cast.AutoJoinPolicy} */ +chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED; + +/** @type {chrome.cast.AutoJoinPolicy} */ +chrome.cast.AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED; + +/** @constructor */ +chrome.cast.DefaultActionPolicy = function() {}; + +/** @type {chrome.cast.DefaultActionPolicy} */ +chrome.cast.DefaultActionPolicy.CAST_THIS_TAB; + +/** @type {chrome.cast.DefaultActionPolicy} */ +chrome.cast.DefaultActionPolicy.CREATE_SESSION; + +/** @constructor */ +chrome.cast.Error = function() {}; + +/** @constructor */ +chrome.cast.ReceiverAvailability = function() {}; + +/** @type {chrome.cast.ReceiverAvailability} */ +chrome.cast.ReceiverAvailability.AVAILABLE; + +/** @type {chrome.cast.ReceiverAvailability} */ +chrome.cast.ReceiverAvailability.UNAVAILABLE; + +/** @type {Object} */ +chrome.cast.media = {}; + +/** @constructor */ +chrome.cast.media.Media = function() { + /** @type {number} */ + this.mediaSessionId = 0; +}; + +/** @constructor */ +chrome.cast.Session = function() { + /** @type {Array<chrome.cast.media.Media>} */ + this.media = []; + + /** @type {string} */ + this.sessionId = ''; +}; + +/** + * @param {string} namespace + * @param {Object} message + * @param {function():void} successCallback + * @param {function(chrome.cast.Error):void} errorCallback + */ +chrome.cast.Session.prototype.sendMessage = + function(namespace, message, successCallback, errorCallback) {}; + +/** + * @param {function(chrome.cast.media.Media):void} listener + */ +chrome.cast.Session.prototype.addMediaListener = function(listener) {}; + +/** + * @param {function(boolean):void} listener + */ +chrome.cast.Session.prototype.addUpdateListener = function(listener) {}; + +/** + * @param {string} namespace + * @param {function(string, string):void} listener + */ +chrome.cast.Session.prototype.addMessageListener = + function(namespace, listener){}; + +/** + * @param {function():void} successCallback + * @param {function(chrome.cast.Error):void} errorCallback + */ +chrome.cast.Session.prototype.stop = + function(successCallback, errorCallback) {}; + +/** + * @constructor + * @param {string} applicationID + */ +chrome.cast.SessionRequest = function(applicationID) {}; + +/** + * @constructor + * @param {chrome.cast.SessionRequest} sessionRequest + * @param {function(chrome.cast.Session):void} sessionListener + * @param {function(chrome.cast.ReceiverAvailability):void} receiverListener + * @param {chrome.cast.AutoJoinPolicy=} opt_autoJoinPolicy + * @param {chrome.cast.DefaultActionPolicy=} opt_defaultActionPolicy + */ +chrome.cast.ApiConfig = function(sessionRequest, + sessionListener, + receiverListener, + opt_autoJoinPolicy, + opt_defaultActionPolicy) {}; + +/** + * @param {chrome.cast.ApiConfig} apiConfig + * @param {function():void} onInitSuccess + * @param {function(chrome.cast.Error):void} onInitError + */ +chrome.cast.initialize = + function(apiConfig, onInitSuccess, onInitError) {}; + +/** + * @param {function(chrome.cast.Session):void} successCallback + * @param {function(chrome.cast.Error):void} errorCallback + */ +chrome.cast.requestSession = + function(successCallback, errorCallback) {};
diff --git a/remoting/webapp/js_proto/chrome_event_proto.js b/remoting/webapp/js_proto/chrome_event_proto.js new file mode 100644 index 0000000..317f711f --- /dev/null +++ b/remoting/webapp/js_proto/chrome_event_proto.js
@@ -0,0 +1,12 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** @constructor */ +chrome.Event = function() {}; + +/** @param {Function} callback */ +chrome.Event.prototype.addListener = function(callback) {}; + +/** @param {Function} callback */ +chrome.Event.prototype.removeListener = function(callback) {};
diff --git a/remoting/webapp/js_proto/chrome_proto.js b/remoting/webapp/js_proto/chrome_proto.js index afa0d03..6ecead2 100644 --- a/remoting/webapp/js_proto/chrome_proto.js +++ b/remoting/webapp/js_proto/chrome_proto.js
@@ -6,15 +6,6 @@ // WebKit- and Chrome-specific properties and methods. It is used only with // JSCompiler to verify the type-correctness of our code. -/** @constructor */ -chrome.Event = function() {}; - -/** @param {Function} callback */ -chrome.Event.prototype.addListener = function(callback) {}; - -/** @param {Function} callback */ -chrome.Event.prototype.removeListener = function(callback) {}; - /** @type {Object} */ chrome.app = {}; @@ -438,128 +429,6 @@ } /** @type {Object} */ -chrome.cast = {}; - -/** @constructor */ -chrome.cast.AutoJoinPolicy = function() {}; - -/** @type {chrome.cast.AutoJoinPolicy} */ -chrome.cast.AutoJoinPolicy.PAGE_SCOPED; - -/** @type {chrome.cast.AutoJoinPolicy} */ -chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED; - -/** @type {chrome.cast.AutoJoinPolicy} */ -chrome.cast.AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED; - -/** @constructor */ -chrome.cast.DefaultActionPolicy = function() {}; - -/** @type {chrome.cast.DefaultActionPolicy} */ -chrome.cast.DefaultActionPolicy.CAST_THIS_TAB; - -/** @type {chrome.cast.DefaultActionPolicy} */ -chrome.cast.DefaultActionPolicy.CREATE_SESSION; - -/** @constructor */ -chrome.cast.Error = function() {}; - -/** @constructor */ -chrome.cast.ReceiverAvailability = function() {}; - -/** @type {chrome.cast.ReceiverAvailability} */ -chrome.cast.ReceiverAvailability.AVAILABLE; - -/** @type {chrome.cast.ReceiverAvailability} */ -chrome.cast.ReceiverAvailability.UNAVAILABLE; - -/** @type {Object} */ -chrome.cast.media = {}; - -/** @constructor */ -chrome.cast.media.Media = function() { - /** @type {number} */ - this.mediaSessionId = 0; -}; - -/** @constructor */ -chrome.cast.Session = function() { - /** @type {Array<chrome.cast.media.Media>} */ - this.media = []; - - /** @type {string} */ - this.sessionId = ''; -}; - -/** - * @param {string} namespace - * @param {Object} message - * @param {function():void} successCallback - * @param {function(chrome.cast.Error):void} errorCallback - */ -chrome.cast.Session.prototype.sendMessage = - function(namespace, message, successCallback, errorCallback) {}; - -/** - * @param {function(chrome.cast.media.Media):void} listener - */ -chrome.cast.Session.prototype.addMediaListener = function(listener) {}; - -/** - * @param {function(boolean):void} listener - */ -chrome.cast.Session.prototype.addUpdateListener = function(listener) {}; - -/** - * @param {string} namespace - * @param {function(string, string):void} listener - */ -chrome.cast.Session.prototype.addMessageListener = - function(namespace, listener){}; - -/** - * @param {function():void} successCallback - * @param {function(chrome.cast.Error):void} errorCallback - */ -chrome.cast.Session.prototype.stop = - function(successCallback, errorCallback) {}; - -/** - * @constructor - * @param {string} applicationID - */ -chrome.cast.SessionRequest = function(applicationID) {}; - -/** - * @constructor - * @param {chrome.cast.SessionRequest} sessionRequest - * @param {function(chrome.cast.Session):void} sessionListener - * @param {function(chrome.cast.ReceiverAvailability):void} receiverListener - * @param {chrome.cast.AutoJoinPolicy=} opt_autoJoinPolicy - * @param {chrome.cast.DefaultActionPolicy=} opt_defaultActionPolicy - */ -chrome.cast.ApiConfig = function(sessionRequest, - sessionListener, - receiverListener, - opt_autoJoinPolicy, - opt_defaultActionPolicy) {}; - -/** - * @param {chrome.cast.ApiConfig} apiConfig - * @param {function():void} onInitSuccess - * @param {function(chrome.cast.Error):void} onInitError - */ -chrome.cast.initialize = - function(apiConfig, onInitSuccess, onInitError) {}; - -/** - * @param {function(chrome.cast.Session):void} successCallback - * @param {function(chrome.cast.Error):void} errorCallback - */ -chrome.cast.requestSession = - function(successCallback, errorCallback) {}; - -/** @type {Object} */ chrome.sockets = {}; /** @type {Object} */
diff --git a/remoting/webapp/js_proto/dom_proto.js b/remoting/webapp/js_proto/dom_proto.js index 14d8abb3..f8233bd 100644 --- a/remoting/webapp/js_proto/dom_proto.js +++ b/remoting/webapp/js_proto/dom_proto.js
@@ -45,6 +45,12 @@ /** @type {string} */ Element.prototype.localName; +/** @type {number} */ +Element.prototype.offsetRight; + +/** @type {number} */ +Element.prototype.offsetBottom; + /** @type {string} */ Element.prototype.textContent;
diff --git a/remoting/webapp/js_proto/qunit_proto.js b/remoting/webapp/js_proto/qunit_proto.js new file mode 100644 index 0000000..f826af8 --- /dev/null +++ b/remoting/webapp/js_proto/qunit_proto.js
@@ -0,0 +1,89 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains various hacks needed to inform JSCompiler of various +// QUnit-specific properties and methods. It is used only with JSCompiler to +// verify the type-correctness of our code. + + +/** @type {Object} */ +var QUnit = QUnit || {}; + +/** @constructor */ +QUnit.Test = function() {}; + +/** @type {QUnit.Clock} */ +QUnit.Test.prototype.clock = new QUnit.Clock(); + +/** @constructor */ +QUnit.Clock = function() {}; + +/** @param {number} ticks */ +QUnit.Clock.prototype.tick = function(ticks) {}; + + +/** + * @param {string} desc + * @param {Function} f + */ +QUnit.asyncTest = function(desc, f) {}; + +/** + * @param {*} a + * @param {*} b + * @param {string=} opt_message + */ +QUnit.deepEqual = function(a, b, opt_message) {}; + +/** + * @param {*} a + * @param {*} b + * @param {string=} opt_message + */ +QUnit.equal = function(a, b, opt_message) {}; + +/** + * @param {*} a + */ +QUnit.expect = function(a) {}; + +/** + * @param {string} desc + * @param {Object=} dict + */ +QUnit.module = function(desc, dict) {}; + +/** + * @param {*} a + * @param {*} b + * @param {string} desc + */ +QUnit.notEqual = function(a, b, desc) {}; + +/** + * @param {boolean} cond + * @param {string=} desc + * @return {boolean} + */ +QUnit.ok = function(cond, desc) {}; + +QUnit.start = function() {}; + +/** + * @param {string} desc + * @param {Function} f + */ +QUnit.test = function(desc, f) {}; + +/** @param {Function} f */ +QUnit.testStart = function(f) {}; + + +var deepEqual = QUnit.deepEqual; +var equal = QUnit.equal; +var expect = QUnit.expect; +var module = QUnit.module; +var notEqual = QUnit.notEqual; +var ok = QUnit.ok; +var test = QUnit.test;
diff --git a/remoting/webapp/js_proto/sinon_proto.js b/remoting/webapp/js_proto/sinon_proto.js new file mode 100644 index 0000000..f33d15f --- /dev/null +++ b/remoting/webapp/js_proto/sinon_proto.js
@@ -0,0 +1,114 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var sinon = sinon || {}; + +/** @type {Object} */ +sinon.assert = {}; + +/** + * @param {(sinon.Spy|Function)} f + */ +sinon.assert.called = function(f) {}; + +/** + * @param {(sinon.Spy|Function)} f + */ +sinon.assert.calledOnce = function(f) {}; + +/** + * @param {(sinon.Spy|Function)} f + * @param {...} data + */ +sinon.assert.calledWith = function(f, data) {}; + +/** + * @param {(sinon.Spy|Function)} f + */ +sinon.assert.notCalled = function(f) {}; + +/** @constructor */ +sinon.Expectation = function() {}; + +/** @return {sinon.Expectation} */ +sinon.Expectation.prototype.once = function() {}; + +/** + * @param {...} data + * @return {sinon.Expectation} + */ +sinon.Expectation.prototype.withArgs = function(data) {}; + +/** @return {boolean} */ +sinon.Expectation.prototype.verify = function() {}; + +/** @param {...} data */ +sinon.Expectation.prototype.returns = function(data) {}; + +/** + * @param {Object} obj + * @return {sinon.Mock} + */ +sinon.mock = function(obj) {}; + +/** @constructor */ +sinon.Mock = function() {}; + +/** + * @param {string} method + * @return {sinon.Expectation} + */ +sinon.Mock.prototype.expects = function(method) {}; + +/** @type {function(...):Function} */ +sinon.spy = function() {}; + +/** + * This is a jscompile type that can be OR'ed with the actual type to make + * jscompile aware of the sinon.spy functions that are added to the base + * type. + * Example: Instead of specifying a type of + * {function():void} + * the following can be used to add the sinon.spy functions: + * {(sinon.Spy|function():void)} + * + * @constructor + */ +sinon.Spy = function() {}; + +/** @type {number} */ +sinon.Spy.prototype.callCount; + +/** @type {boolean} */ +sinon.Spy.prototype.called = false; + +/** @type {function(...):boolean} */ +sinon.Spy.prototype.calledWith = function() {}; + +/** @type {function(number):{args:Array}} */ +sinon.Spy.prototype.getCall = function(index) {}; + +sinon.Spy.prototype.reset = function() {}; + +/** + * @param {Object} obj + * @param {string} method + * @param {Function=} opt_stubFunction + * @return {sinon.TestStub} + */ +sinon.stub = function(obj, method, opt_stubFunction) {}; + +/** @constructor */ +sinon.TestStub = function() {}; + +/** @type {function(number):{args:Array}} */ +sinon.TestStub.prototype.getCall = function(index) {}; + +sinon.TestStub.prototype.restore = function() {}; + +/** @param {*} a */ +sinon.TestStub.prototype.returns = function(a) {}; + +/** @type {function(string, (string|Array<string>)=):sinon.Expectation} */ +sinon.TestStub.prototype.withArgs = function(messageName, opt_args) {};
diff --git a/remoting/webapp/js_proto/sinon_stub_proto.js b/remoting/webapp/js_proto/sinon_stub_proto.js new file mode 100644 index 0000000..9abaa56 --- /dev/null +++ b/remoting/webapp/js_proto/sinon_stub_proto.js
@@ -0,0 +1,34 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// How to create sinon.stubs that work with jscompile. +// +// To create the stub: +// sinon.$setupStub(<object>, <function-name>) +// +// To access the stub in unittests: +// <object>.<function-name>.$testStub.<sinon-test> +// +// For example: +// sinon.$setupStub(chrome.socket, 'create'); +// chrome.socket.create.$testStub.restore(); +// +// For jscompile to analyze these corectly, you'll also need to add an entry +// in this file for any object you stub out this way. For example: +// chrome.socket.create.$testStub = new sinon.TestStub(); + +base.debug.assert.$testStub = new sinon.TestStub(); +base.isAppsV2.$testStub = new sinon.TestStub(); + +chrome.i18n.getMessage.$testStub = new sinon.TestStub(); + +chrome.socket.connect.$testStub = new sinon.TestStub(); +chrome.socket.create.$testStub = new sinon.TestStub(); +chrome.socket.destroy.$testStub = new sinon.TestStub(); +chrome.socket.read.$testStub = new sinon.TestStub(); +chrome.socket.secure.$testStub = new sinon.TestStub(); +chrome.socket.write.$testStub = new sinon.TestStub(); + +remoting.setMode.$testStub = new sinon.TestStub(); +remoting.Host.needsUpdate.$testStub = new sinon.TestStub();
diff --git a/remoting/webapp/js_proto/test_proto.js b/remoting/webapp/js_proto/test_proto.js index 41124ba9..6689cfd 100644 --- a/remoting/webapp/js_proto/test_proto.js +++ b/remoting/webapp/js_proto/test_proto.js
@@ -9,16 +9,12 @@ /** @suppress {duplicate} */ var browserTest = browserTest || {}; -/** @suppress {duplicate} */ -var sinon = sinon || {}; - /** @interface */ browserTest.TestableClass = function() {}; /** @param {*} data */ browserTest.TestableClass.prototype.run = function(data) {}; -sinon.spy = function() {}; /** @constructor */ window.DomAutomationControllerMessage = function() {
diff --git a/remoting/webapp/unittests/apps_v2_migration_unittest.js b/remoting/webapp/unittests/apps_v2_migration_unittest.js index 6bc8db9..805995aa 100644 --- a/remoting/webapp/unittests/apps_v2_migration_unittest.js +++ b/remoting/webapp/unittests/apps_v2_migration_unittest.js
@@ -2,10 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +/** + * @fileoverview + * @suppress {checkTypes|checkVars|reportUnknownTypes|visibility} + */ + (function() { 'use strict'; +/** @type {sinon.TestStub} */ var mockIsAppsV2 = null; var mockChromeStorage = {}; @@ -22,10 +28,10 @@ /** * @param {string} v1UserName * @param {string} v1UserEmail - * @param {string} currentEmail - * @param {boolean} v1HasHost + * @param {boolean} v1HasHosts */ function setMigrationData_(v1UserName, v1UserEmail, v1HasHosts) { + /** @return {!Promise} */ remoting.identity.getUserInfo = function() { if (base.isAppsV2()) { return Promise.resolve( @@ -35,10 +41,13 @@ {email: v1UserEmail, name: v1UserName}); } }; + /** @return {!Promise} */ remoting.identity.getEmail = function() { - return remoting.identity.getUserInfo().then(function(info) { - return info.email; - }); + return remoting.identity.getUserInfo().then( + /** @param {{email:string, name:string}} info */ + function(info) { + return info.email; + }); }; mockIsAppsV2.returns(false); @@ -50,8 +59,8 @@ module('AppsV2Migration', { setup: function() { chromeMocks.activate(['storage']); - mockIsAppsV2 = sinon.stub(base, 'isAppsV2'); - remoting.identity = {}; + mockIsAppsV2 = sinon.$setupStub(base, 'isAppsV2'); + remoting.identity = new remoting.Identity(); }, teardown: function() { chromeMocks.restore(); @@ -89,6 +98,7 @@ setMigrationData_('v1userName', 'v1user@gmail.com', true); mockIsAppsV2.returns(true); remoting.AppsV2Migration.hasHostsInV1App().then( + /** @param {{email:string, name:string}} result */ function(result) { QUnit.equal(result.email, 'v1user@gmail.com'); QUnit.equal(result.fullName, 'v1userName'); @@ -100,10 +110,9 @@ QUnit.asyncTest( 'saveUserInfo() should clear the preferences on v2', function() { - setMigrationData_('v1userName', 'v1user@gmail.com', 'v2user@gmail.com', - true); + setMigrationData_('v1userName', 'v1user@gmail.com', true); mockIsAppsV2.returns(true); - remoting.AppsV2Migration.saveUserInfo(true); + remoting.AppsV2Migration.saveUserInfo(); remoting.AppsV2Migration.hasHostsInV1App().then(fail, pass); });
diff --git a/remoting/webapp/unittests/base_unittest.js b/remoting/webapp/unittests/base_unittest.js index 6ffc8c9..288ff91 100644 --- a/remoting/webapp/unittests/base_unittest.js +++ b/remoting/webapp/unittests/base_unittest.js
@@ -22,14 +22,14 @@ var src = { a: 'a', b: 'b'}; var dest = { a: 'a'}; - sinon.spy(base.debug, 'assert'); + sinon.$setupStub(base.debug, 'assert'); try { base.mix(dest, src); } catch (e) { } finally { sinon.assert.called(base.debug.assert); - base.debug.assert.restore(); + base.debug.assert.$testStub.restore(); } }); @@ -72,9 +72,14 @@ test('dispose(obj) should invoke the dispose method on |obj|', function() { - var obj = { - dispose: sinon.spy() - }; + /** + * @constructor + * @implements {base.Disposable} + */ + base.MockDisposable = function() {}; + base.MockDisposable.prototype.dispose = sinon.spy(); + + var obj = new base.MockDisposable(); base.dispose(obj); sinon.assert.called(obj.dispose); }); @@ -111,9 +116,14 @@ }); QUnit.asyncTest('Promise.sleep(delay) should fulfill the promise after |delay|', + /** + * 'this' is not defined for jscompile, so it can't figure out the type of + * this.clock. + * @suppress {reportUnknownTypes|checkVars|checkTypes} + */ function() { var isCalled = false; - var clock = this.clock; + var clock = /** @type {QUnit.Clock} */ (this.clock); base.Promise.sleep(100).then(function(){ isCalled = true; @@ -129,18 +139,18 @@ window.requestAnimationFrame(function(){ ok(!isCalled, 'Promise.sleep() should not be fulfilled prematurely.'); clock.tick(101); - }.bind(this)); + }); }); QUnit.asyncTest('Promise.negate should fulfill iff the promise does not.', function() { base.Promise.negate(Promise.reject()).then( - ok.bind(null, true), - ok.bind(null, false)); + QUnit.ok.bind(null, true), + /** @type {Function} */ (QUnit.ok.bind(null, false))); base.Promise.negate(Promise.resolve()).then( - ok.bind(null, false), - ok.bind(null, true)); + QUnit.ok.bind(null, false), + /** @type {Function} */ (QUnit.ok.bind(null, true))); window.requestAnimationFrame(function(){ QUnit.start(); }); @@ -149,21 +159,25 @@ module('base.Deferred'); QUnit.asyncTest('resolve() should fulfill the underlying promise.', function() { + /** @returns {Promise} */ function async() { var deferred = new base.Deferred(); deferred.resolve('bar'); return deferred.promise(); } - async().then(function(value){ - QUnit.equal(value, 'bar'); - QUnit.start(); - }, function() { - QUnit.ok(false, 'The reject handler should not be invoked.'); - }); + async().then( + /** @param {string} value */ + function(value){ + QUnit.equal(value, 'bar'); + QUnit.start(); + }, function() { + QUnit.ok(false, 'The reject handler should not be invoked.'); + }); }); QUnit.asyncTest('reject() should fail the underlying promise.', function() { + /** @returns {Promise} */ function async() { var deferred = new base.Deferred(); deferred.reject('bar'); @@ -179,6 +193,7 @@ }); +/** @type {base.EventSourceImpl} */ var source = null; var listener = null; @@ -229,13 +244,13 @@ test('raiseEvent() should assert when undeclared events are raised', function() { - sinon.spy(base.debug, 'assert'); + sinon.$setupStub(base.debug, 'assert'); try { source.raiseEvent('undefined'); } catch (e) { } finally { sinon.assert.called(base.debug.assert); - base.debug.assert.restore(); + base.debug.assert.$testStub.restore(); } }); @@ -268,6 +283,7 @@ }); test('encodeUtf8() can encode UTF8 strings', function() { + /** @type {function(ArrayBuffer):Array} */ function toJsArray(arrayBuffer) { var result = []; var array = new Uint8Array(arrayBuffer);
diff --git a/remoting/webapp/unittests/chrome_mocks.js b/remoting/webapp/unittests/chrome_mocks.js index be55785..fb65437 100644 --- a/remoting/webapp/unittests/chrome_mocks.js +++ b/remoting/webapp/unittests/chrome_mocks.js
@@ -9,6 +9,16 @@ var chromeMocks = {}; +/** @constructor */ +chrome.Event = function() {}; + +/** @param {Function} callback */ +chrome.Event.prototype.addListener = function(callback) {}; + +/** @param {Function} callback */ +chrome.Event.prototype.removeListener = function(callback) {}; + + (function(){ /**
diff --git a/remoting/webapp/unittests/desktop_viewport_unittest.js b/remoting/webapp/unittests/desktop_viewport_unittest.js index 054bf57..238c925 100644 --- a/remoting/webapp/unittests/desktop_viewport_unittest.js +++ b/remoting/webapp/unittests/desktop_viewport_unittest.js
@@ -6,16 +6,26 @@ 'use strict'; -module('DesktopViewport'); - +/** + * @param {number} width + * @param {number} height + * @return {{width:number, height:number}} + */ function size(width, height) { return {width: width, height: height}; } +/** + * @param {number} x + * @param {number} y + * @return {{x:number, y:number}} + */ function dpi(x, y) { return {x: x, y: y}; } +module('DesktopViewport'); + test('choosePluginSize() handles low-DPI client & host', function() { // 1. Client & host size the same.
diff --git a/remoting/webapp/unittests/dns_blackhole_checker_unittest.js b/remoting/webapp/unittests/dns_blackhole_checker_unittest.js index d6e7d22..6f5b0b2e 100644 --- a/remoting/webapp/unittests/dns_blackhole_checker_unittest.js +++ b/remoting/webapp/unittests/dns_blackhole_checker_unittest.js
@@ -2,13 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +/** + * @fileoverview + * TODO(garykac): Create interface for SignalStrategy. + * @suppress {checkTypes|checkVars|reportUnknownTypes|visibility} + */ + (function() { 'use strict'; +/** @type {(sinon.Spy|function(remoting.SignalStrategy.State))} */ var onStateChange = null; + +/** @type {(sinon.Spy|function(Element):void)} */ var onIncomingStanzaCallback = null; + +/** @type {remoting.DnsBlackholeChecker} */ var checker = null; + +/** @type {remoting.MockSignalStrategy} */ var signalStrategy = null; var fakeXhrs; @@ -19,7 +32,6 @@ fakeXhrs.push(xhr); }; - onStateChange = sinon.spy(); onIncomingStanzaCallback = sinon.spy(); signalStrategy = new remoting.MockSignalStrategy();
diff --git a/remoting/webapp/unittests/event_hook_unittest.js b/remoting/webapp/unittests/event_hook_unittest.js index ee67d1f4..15135bde 100644 --- a/remoting/webapp/unittests/event_hook_unittest.js +++ b/remoting/webapp/unittests/event_hook_unittest.js
@@ -2,19 +2,40 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +/** + * @fileoverview + * TODO(garykac) Remove suppression once chromeMocks has been replaced. + * @suppress {checkTypes|checkVars|reportUnknownTypes} + */ + (function() { 'use strict'; +/** @type {base.EventSourceImpl} */ var eventSource = null; + +/** @type {HTMLElement} */ var domElement = null; + +/** @type {chromeMocks.Event} */ var myChromeEvent = null; + +/** @type {Listener} */ var listener = null; +/** + * @param {HTMLElement} element + * @constructor + */ var Listener = function(element) { - this.onChromeEvent = sinon.stub(); - this.onClickEvent = sinon.stub(); - this.onCustomEvent = sinon.stub(); + /** @type {(sinon.Spy|function(...?))} */ + this.onChromeEvent = sinon.spy(); + /** @type {(sinon.Spy|function(...?))} */ + this.onClickEvent = sinon.spy(); + /** @type {(sinon.Spy|function(...?))} */ + this.onCustomEvent = sinon.spy(); + this.eventHooks_ = new base.Disposables( new base.DomEventHook(element, 'click', this.onClickEvent.bind(this), false), @@ -35,7 +56,7 @@ module('base.EventHook', { setup: function() { - domElement = document.createElement('div'); + domElement = /** @type {HTMLElement} */ (document.createElement('div')); eventSource = new base.EventSourceImpl(); eventSource.defineEvents(['customEvent']); myChromeEvent = new chromeMocks.Event();
diff --git a/remoting/webapp/unittests/fallback_signal_strategy_unittest.js b/remoting/webapp/unittests/fallback_signal_strategy_unittest.js index 959902ba..9f97a729 100644 --- a/remoting/webapp/unittests/fallback_signal_strategy_unittest.js +++ b/remoting/webapp/unittests/fallback_signal_strategy_unittest.js
@@ -2,15 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +/** + * @fileoverview + * TODO(garykac): Create interfaces for LogToServer and SignalStrategy. + * @suppress {checkTypes|checkVars|reportUnknownTypes|visibility} + */ + (function() { 'use strict'; - +/** @constructor */ var MockLogToServer = function() { + /** @type {(sinon.Spy|Function)} */ this.logSignalStrategyProgress = sinon.spy(); }; +/** @type {function(...)} */ MockLogToServer.prototype.assertProgress = function() { equal(this.logSignalStrategyProgress.callCount * 2, arguments.length); for (var i = 0; i < this.logSignalStrategyProgress.callCount; ++i) { @@ -20,13 +28,29 @@ } }; +/** @type {(sinon.Spy|function(remoting.SignalStrategy.State))} */ var onStateChange = null; + +/** @type {(sinon.Spy|function(Element):void)} */ var onIncomingStanzaCallback = null; + +/** @type {remoting.FallbackSignalStrategy} */ var strategy = null; + +/** @type {remoting.SignalStrategy} */ var primary = null; + +/** @type {remoting.SignalStrategy} */ var secondary = null; + +/** @type {MockLogToServer} */ var logToServer = null; +/** + * @param {remoting.MockSignalStrategy} baseSignalStrategy + * @param {remoting.SignalStrategy.State} state + * @param {boolean} expectCallback + */ function setState(baseSignalStrategy, state, expectCallback) { onStateChange.reset(); baseSignalStrategy.setStateForTesting(state);
diff --git a/remoting/webapp/unittests/host_table_entry_unittest.js b/remoting/webapp/unittests/host_table_entry_unittest.js new file mode 100644 index 0000000..053080a --- /dev/null +++ b/remoting/webapp/unittests/host_table_entry_unittest.js
@@ -0,0 +1,212 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +(function() { + +'use strict'; + +/** @type {remoting.HostTableEntry} */ +var hostTableEntry_ = null; +var onConnect_ = null; +var onRename_ = null; +var onDelete_ = null; + +module('HostTableEntry', { + setup: function() { + onConnect_ = /** @type {function(string)} */ (sinon.spy()); + onRename_ = /** @type {function(remoting.HostTableEntry)} */ (sinon.spy()); + onDelete_ = /** @type {function(remoting.HostTableEntry)} */ (sinon.spy()); + hostTableEntry_ = + new remoting.HostTableEntry(10, + onConnect_, onRename_, onDelete_); + + // Setup the DOM dependencies on the confirm delete dialog. + var fixture = document.getElementById('qunit-fixture'); + fixture.innerHTML = '<div id="confirm-host-delete-message"></div>' + + '<div id="confirm-host-delete"></div>' + + '<div id="cancel-host-delete"></div>'; + setHost('LocalHost', 'ONLINE'); + fixture.appendChild(hostTableEntry_.element()); + sinon.$setupStub(chrome.i18n, 'getMessage', function(/** string */ tag){ + return tag; + }); + }, + teardown: function() { + hostTableEntry_.dispose(); + hostTableEntry_ = null; + chrome.i18n.getMessage.$testStub.restore(); + } +}); + +/** + * @param {string} hostName + * @param {string} status + * @param {string=} opt_offlineReason + */ +function setHost(hostName, status, opt_offlineReason) { + var host = new remoting.Host(); + host.hostName = hostName; + host.status = status; + if (opt_offlineReason) { + host.hostOfflineReason = opt_offlineReason; + } + hostTableEntry_.setHost(host); +} + + +/** @suppress {checkTypes|reportUnknownTypes} */ +function sendKeydown(/** HTMLElement */ target, /** number */ keyCode) { + var event = document.createEvent('KeyboardEvent'); + Object.defineProperty( + event, 'which', {get: function() { return keyCode; }}); + event.initKeyboardEvent("keydown", true, true, document.defaultView, + false, false, false, false, keyCode, keyCode); + target.dispatchEvent(event); +} + +function verifyVisible( + /** HTMLElement*/ element, + /** boolean */ isVisible, + /** string= */ opt_name) { + var expectedVisibility = (isVisible) ? 'visible' : 'hidden'; + QUnit.equal(element.hidden, !isVisible, + 'Element ' + opt_name + ' should be ' + expectedVisibility); +} + +test('Clicking on the confirm button in the confirm dialog deletes the host', + function() { + // Setup. + sinon.$setupStub(remoting, 'setMode', function(/** remoting.AppMode */ mode) { + if (mode === remoting.AppMode.CONFIRM_HOST_DELETE) { + document.getElementById('confirm-host-delete').click(); + } + }); + + // Invoke. + hostTableEntry_.element().querySelector('.delete-button').click(); + + // Verify. + sinon.assert.calledWith(onDelete_, hostTableEntry_); + + // Cleanup. + remoting.setMode.$testStub.restore(); +}); + +test( + 'Clicking on the cancel button in the confirm dialog cancels host deletion', + function() { + // Setup. + sinon.$setupStub(remoting, 'setMode', function(/** remoting.AppMode */ mode) { + if (mode === remoting.AppMode.CONFIRM_HOST_DELETE) { + document.getElementById('cancel-host-delete').click(); + } + }); + + // Invoke. + hostTableEntry_.element().querySelector('.delete-button').click(); + + // Verify. + sinon.assert.notCalled(onDelete_); + + // Cleanup. + remoting.setMode.$testStub.restore(); +}); + +test('Clicking on the rename button shows the input field.', function() { + // Invoke. + hostTableEntry_.element().querySelector('.rename-button').click(); + + // Verify. + var inputField = + hostTableEntry_.element().querySelector('.host-rename-input'); + + verifyVisible(inputField, true, 'inputField'); + QUnit.equal(document.activeElement, inputField); +}); + +test('Host renaming is canceled when input field losses focus.', function() { + // Invoke. + hostTableEntry_.element().querySelector('.rename-button').click(); + + // Verify. + var inputField = + hostTableEntry_.element().querySelector('.host-rename-input'); + + verifyVisible(inputField, true, 'inputField'); + QUnit.equal(document.activeElement, inputField); + inputField.blur(); + verifyVisible(inputField, false, 'inputField'); +}); + +test('Host renaming is canceled on ESCAPE key.', function() { + // Invoke. + var inputField = + hostTableEntry_.element().querySelector('.host-rename-input'); + hostTableEntry_.element().querySelector('.rename-button').click(); + + // Verify. + verifyVisible(inputField, true, 'inputField'); + QUnit.equal(document.activeElement, inputField); + sendKeydown(inputField, 27 /* ESCAPE */); + verifyVisible(inputField, false, 'inputField'); +}); + +test('Host renaming commits on ENTER.', function() { + // Invoke. + var inputField = + hostTableEntry_.element().querySelector('.host-rename-input'); + hostTableEntry_.element().querySelector('.rename-button').click(); + inputField.value = 'Renamed Host'; + sendKeydown(inputField, 13 /* ENTER */); + + // Verify + verifyVisible(inputField, false, 'inputField'); + sinon.assert.called(onRename_); + QUnit.equal(hostTableEntry_.host.hostName, 'Renamed Host'); + + // Renaming shouldn't trigger a connection request. + sinon.assert.notCalled(onConnect_); +}); + +test('HostTableEntry renders the host name correctly.', function() { + var label = hostTableEntry_.element().querySelector('.host-name-label'); + QUnit.equal(label.innerText, 'LocalHost'); +}); + +test('HostTableEntry renders an offline host correctly.', function() { + setHost('LocalHost', 'OFFLINE', 'INITIALIZATION_FAILED'); + var label = hostTableEntry_.element().querySelector('.host-name-label'); + QUnit.equal(label.innerText, 'OFFLINE'); + QUnit.equal(label.title, 'OFFLINE_REASON_INITIALIZATION_FAILED'); +}); + +test('HostTableEntry renders an out-of-date host correctly', function() { + sinon.$setupStub(remoting.Host, 'needsUpdate').returns(true); + setHost('LocalHost', 'ONLINE'); + var warningOverlay = + hostTableEntry_.element().querySelector('.warning-overlay'); + var label = hostTableEntry_.element().querySelector('.host-name-label'); + verifyVisible(warningOverlay, true, 'warning overlay'); + QUnit.equal(label.innerText, 'UPDATE_REQUIRED'); +}); + +test('Clicking on an online host connects it', function() { + hostTableEntry_.element().querySelector('.host-name-label').click(); + sinon.assert.calledWith(onConnect_, + encodeURIComponent(hostTableEntry_.host.hostId)); +}); + +test('Clicking on an offline host should be a no-op', function() { + setHost('LocalHost', 'OFFLINE'); + hostTableEntry_.element().querySelector('.host-name-label').click(); + sinon.assert.notCalled(onConnect_); +}); + +test('HostTableEntry handles host that is null', function() { + hostTableEntry_.setHost(null); + hostTableEntry_.element().querySelector('.host-name-label').click(); + sinon.assert.notCalled(onConnect_); +}); + +})();
diff --git a/remoting/webapp/unittests/ipc_unittest.js b/remoting/webapp/unittests/ipc_unittest.js index 9434cab..e786147 100644 --- a/remoting/webapp/unittests/ipc_unittest.js +++ b/remoting/webapp/unittests/ipc_unittest.js
@@ -6,6 +6,7 @@ 'use strict'; +/** @type {base.Ipc} */ var ipc_; function pass() { @@ -62,7 +63,7 @@ function() { var handler = sinon.spy(); ipc_.register('foo', handler); - ipc_.unregister('foo', handler); + ipc_.unregister('foo'); base.Ipc.invoke('foo', 'hello', 'world').then(fail, function(error) { sinon.assert.notCalled(handler); QUnit.equal(error, base.Ipc.Error.UNSUPPORTED_REQUEST_TYPE);
diff --git a/remoting/webapp/unittests/it2me_helpee_channel_unittest.js b/remoting/webapp/unittests/it2me_helpee_channel_unittest.js deleted file mode 100644 index 85bee2b..0000000 --- a/remoting/webapp/unittests/it2me_helpee_channel_unittest.js +++ /dev/null
@@ -1,168 +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. - -(function() { - -'use strict'; - -var hostInstaller = null; -var hangoutPort = null; -var host = null; -var helpeeChannel = null; -var onDisposedCallback = null; - -module('It2MeHelpeeChannel', { - setup: function() { - // HangoutPort - hangoutPort = new chromeMocks.runtime.Port(); - hangoutPort.postMessage = sinon.spy(hangoutPort, 'postMessage'); - hangoutPort.disconnect = sinon.spy(hangoutPort, 'disconnect'); - - // onDisposedCallback callback - onDisposedCallback = sinon.spy(); - - // Host - host = { - initialize: function() {}, - initialized: function() {}, - connect: function() {}, - disconnect: function() {}, - getAccessCode: function() {}, - unhookCallbacks: function() {} - }; - - // HostInstaller - hostInstaller = { - download: function() {} - }; - - // HelpeeChannel - helpeeChannel = new remoting.It2MeHelpeeChannel( - hangoutPort, - host, - hostInstaller, - onDisposedCallback); - helpeeChannel.init(); - - // remoting.settings - remoting.settings = new remoting.Settings(); - remoting.identity = new remoting.Identity(); - }, - tearDown: function() { - remoting.settings = null; - remoting.identity = null; - } -}); - -test('hello() should return supportedFeatures', function() { - hangoutPort.onMessage.mock$fire( - { method: remoting.It2MeHelpeeChannel.HangoutMessageTypes.HELLO }); - - sinon.assert.calledWith(hangoutPort.postMessage, { - method: remoting.It2MeHelpeeChannel.HangoutMessageTypes.HELLO_RESPONSE, - supportedFeatures: base.values(remoting.It2MeHelperChannel.Features) - }); -}); - -QUnit.asyncTest( - 'isHostInstalled() should return false if host is not installed', - function() { - sinon.stub(remoting.HostInstaller, 'isInstalled') - .returns(Promise.resolve(false)); - - var MessageTypes = remoting.It2MeHelpeeChannel.HangoutMessageTypes; - hangoutPort.onMessage.mock$fire({ - method: MessageTypes.IS_HOST_INSTALLED - }); - - window.requestAnimationFrame(function() { - remoting.HostInstaller.isInstalled.restore(); - sinon.assert.calledWith(hangoutPort.postMessage, { - method: MessageTypes.IS_HOST_INSTALLED_RESPONSE, - result: false - }); - QUnit.start(); - }); -}); - -QUnit.asyncTest('isHostInstalled() should return true if host is installed', - function() { - sinon.stub(remoting.HostInstaller, 'isInstalled') - .returns(Promise.resolve(true)); - - var MessageTypes = remoting.It2MeHelpeeChannel.HangoutMessageTypes; - hangoutPort.onMessage.mock$fire({ - method: MessageTypes.IS_HOST_INSTALLED - }); - - window.requestAnimationFrame(function() { - remoting.HostInstaller.isInstalled.restore(); - sinon.assert.calledWith(hangoutPort.postMessage, { - method: MessageTypes.IS_HOST_INSTALLED_RESPONSE, - result: true - }); - QUnit.start(); - }); -}); - -test('downloadHost() should trigger a host download', - function() { - sinon.stub(hostInstaller, 'download').returns(Promise.resolve(true)); - - hangoutPort.onMessage.mock$fire({ - method: remoting.It2MeHelpeeChannel.HangoutMessageTypes.DOWNLOAD_HOST - }); - - sinon.assert.called(hostInstaller.download); -}); - -QUnit.asyncTest('connect() should return access code', - function() { - // Stubs authentication. - sinon.stub(base, 'isAppsV2').returns(true); - sinon.stub(remoting.HangoutConsentDialog, 'getInstance').returns({ - show : function() { - return Promise.resolve(); - } - }); - sinon.stub(chrome.identity, 'getAuthToken') - .callsArgWith(1, 'token'); - sinon.stub(remoting.identity, 'getToken') - .returns(Promise.resolve('token')); - sinon.stub(remoting.identity, 'getEmail') - .returns(Promise.resolve('test@chromium.org')); - // Stubs Host behavior. - sinon.stub(host, 'initialized').returns(true); - sinon.stub(host, 'connect') - .callsArgWith(2, remoting.HostSession.State.RECEIVED_ACCESS_CODE); - sinon.stub(host, 'getAccessCode').returns('accessCode'); - - var MessageTypes = remoting.It2MeHelpeeChannel.HangoutMessageTypes; - hangoutPort.onMessage.mock$fire({ - method: MessageTypes.CONNECT, - hangoutBounds: {widht: 10, height: 10, left:10, top: 10} - }); - - window.requestAnimationFrame(function(){ - // Verify that access code is correct in the response. - sinon.assert.calledWithMatch(hangoutPort.postMessage, { - method: MessageTypes.CONNECT_RESPONSE, - accessCode: 'accessCode' - }); - - chrome.identity.getAuthToken.restore(); - base.isAppsV2.restore(); - QUnit.start(); - }); -}); - -test('should disconnect the session if Hangout crashes', function() { - sinon.spy(host, 'disconnect'); - hangoutPort.onDisconnect.mock$fire(); - - sinon.assert.called(onDisposedCallback); - sinon.assert.called(host.disconnect); -}); - -})();
diff --git a/remoting/webapp/unittests/it2me_helper_channel_unittest.js b/remoting/webapp/unittests/it2me_helper_channel_unittest.js deleted file mode 100644 index f0a0fa2..0000000 --- a/remoting/webapp/unittests/it2me_helper_channel_unittest.js +++ /dev/null
@@ -1,189 +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. - -(function() { - -'use strict'; - -var appLauncher = null; -var hangoutPort = null; -var webappPort = null; -var helperChannel = null; -var disconnectCallback = null; - -module('It2MeHelperChannel', { - setup: function() { - // App Launcher. - appLauncher = { - launch: function () { - return promiseResolveSynchronous('tabId'); - }, - close: function () {} - }; - appLauncher.launch = sinon.spy(appLauncher, 'launch'); - appLauncher.close = sinon.spy(appLauncher, 'close'); - - // HangoutPort. - hangoutPort = new chromeMocks.runtime.Port(); - hangoutPort.postMessage = sinon.spy(hangoutPort, 'postMessage'); - hangoutPort.disconnect = sinon.spy(hangoutPort, 'disconnect'); - - // WebappPort. - webappPort = new chromeMocks.runtime.Port(); - webappPort.sender = { - tab : { - id : 'tabId' - } - }; - webappPort.postMessage = sinon.spy(webappPort, 'postMessage'); - webappPort.disconnect = sinon.spy(webappPort, 'disconnect'); - - // disconnect callback - disconnectCallback = sinon.spy(); - - // HelperChannel. - helperChannel = new remoting.It2MeHelperChannel( - appLauncher, hangoutPort, disconnectCallback); - helperChannel.init(); - hangoutPort.onMessage.mock$fire({ - method: remoting.It2MeHelperChannel.HangoutMessageTypes.CONNECT, - accessCode: "123412341234" - }); - }, -}); - -function promiseResolveSynchronous(value) { - return { - then: function(callback) { - callback('tabId'); - } - }; -} - -test('onHangoutMessage_("hello") should return supportedFeatures', function() { - hangoutPort.onMessage.mock$fire( - { method: remoting.It2MeHelperChannel.HangoutMessageTypes.HELLO }); - - sinon.assert.calledWith(hangoutPort.postMessage, { - method: remoting.It2MeHelperChannel.HangoutMessageTypes.HELLO_RESPONSE, - supportedFeatures: base.values(remoting.It2MeHelperChannel.Features) - }); -}); - -test('onHangoutMessage_(|connect|) should launch the webapp', - function() { - sinon.assert.called(appLauncher.launch); - QUnit.equal(helperChannel.instanceId(), 'tabId'); -}); - -test('onWebappMessage() should forward messages to hangout', function() { - // Execute. - helperChannel.onWebappConnect(webappPort); - webappPort.onMessage.mock$fire({ - method:'sessionStateChanged', - state:remoting.ClientSession.State.CONNECTING - }); - webappPort.onMessage.mock$fire({ - method:'sessionStateChanged', - state:remoting.ClientSession.State.CONNECTED - }); - - // Verify events are forwarded. - sinon.assert.calledWith(hangoutPort.postMessage, { - method:'sessionStateChanged', - state:remoting.ClientSession.State.CONNECTING - }); - - sinon.assert.calledWith(hangoutPort.postMessage, { - method:'sessionStateChanged', - state:remoting.ClientSession.State.CONNECTED - }); -}); - -test('should notify hangout when the webapp crashes', function() { - // Execute. - helperChannel.onWebappConnect(webappPort); - webappPort.onDisconnect.mock$fire(); - - // Verify events are forwarded. - sinon.assert.calledWith(hangoutPort.postMessage, { - method:'sessionStateChanged', - state: remoting.ClientSession.State.FAILED - }); - sinon.assert.called(hangoutPort.disconnect); - sinon.assert.calledOnce(disconnectCallback); -}); - -test('should notify hangout when the session is ended', function() { - // Execute. - helperChannel.onWebappConnect(webappPort); - webappPort.onMessage.mock$fire({ - method:'sessionStateChanged', - state:remoting.ClientSession.State.CLOSED - }); - - webappPort.onDisconnect.mock$fire(); - - // Verify events are forwarded. - sinon.assert.calledWith(hangoutPort.postMessage, { - method:'sessionStateChanged', - state:remoting.ClientSession.State.CLOSED - }); - sinon.assert.called(hangoutPort.disconnect); - sinon.assert.calledOnce(disconnectCallback); -}); - -test('should notify hangout when the session has error', function() { - helperChannel.onWebappConnect(webappPort); - webappPort.onMessage.mock$fire({ - method:'sessionStateChanged', - state:remoting.ClientSession.State.FAILED - }); - - webappPort.onDisconnect.mock$fire(); - - // Verify events are forwarded. - sinon.assert.calledWith(hangoutPort.postMessage, { - method:'sessionStateChanged', - state:remoting.ClientSession.State.FAILED - }); - sinon.assert.called(hangoutPort.disconnect); - sinon.assert.calledOnce(disconnectCallback); -}); - - -test('onHangoutMessages_(disconnect) should close the webapp', function() { - // Execute. - helperChannel.onWebappConnect(webappPort); - hangoutPort.onMessage.mock$fire({ - method: remoting.It2MeHelperChannel.HangoutMessageTypes.DISCONNECT - }); - - sinon.assert.calledOnce(appLauncher.close); - - // Webapp will respond by disconnecting the port - webappPort.onDisconnect.mock$fire(); - - // Verify events are forwarded. - sinon.assert.calledWith(hangoutPort.postMessage, { - method:'sessionStateChanged', - state:remoting.ClientSession.State.CLOSED - }); - sinon.assert.called(webappPort.disconnect); - sinon.assert.called(hangoutPort.disconnect); -}); - -test('should close the webapp when hangout crashes', function() { - // Execute. - helperChannel.onWebappConnect(webappPort); - hangoutPort.onDisconnect.mock$fire(); - - sinon.assert.calledOnce(appLauncher.close); - sinon.assert.calledOnce(disconnectCallback); - - sinon.assert.called(hangoutPort.disconnect); - sinon.assert.called(webappPort.disconnect); -}); - -})();
diff --git a/remoting/webapp/unittests/it2me_service_unittest.js b/remoting/webapp/unittests/it2me_service_unittest.js deleted file mode 100644 index 1bd66f5..0000000 --- a/remoting/webapp/unittests/it2me_service_unittest.js +++ /dev/null
@@ -1,132 +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. - -(function() { - -'use strict'; - -var appLauncher = null; -var hangoutPort = null; -var webappPort = null; -var it2meService = null; - -function createPort(name, senderId) { - var port = new chromeMocks.runtime.Port(); - port.name = (senderId) ? name +'@' + senderId : name; - port.postMessage = sinon.spy(port, 'postMessage'); - port.disconnect = sinon.spy(port, 'disconnect'); - - return port; -} - -function promiseResolveSynchronous(value) { - return { - then: function(callback) { - callback(value); - } - }; -} - -module('It2MeService', { - setup: function() { - // App Launcher. - appLauncher = { - launch: function () { - return promiseResolveSynchronous('tabId'); - }, - close: function () {} - }; - // HangoutPort. - hangoutPort = createPort('it2me.helper.hangout'); - it2meService = new remoting.It2MeService(appLauncher); - it2meService.onConnectExternal_(hangoutPort); - webappPort = createPort('it2me.helper.webapp', 'tabId'); - } -}); - -test('should establish a channel two way channel when the webapp connects', - function() { - // Hangout ---- connect ----> It2MeService. - hangoutPort.onMessage.mock$fire({ - method: 'connect', - accessCode: "123412341234" - }); - - // Webapp ---- connect ----> It2MeService. - it2meService.onWebappConnect_(webappPort); - - // Webapp ---- sessionStateChanged ----> It2MeService. - webappPort.onMessage.mock$fire({ - method: 'sessionStateChanged', - state: remoting.ClientSession.State.CONNECTED - }); - - // verify that hangout can receive message events. - sinon.assert.calledWith(hangoutPort.postMessage, { - method: 'sessionStateChanged', - state: remoting.ClientSession.State.CONNECTED - }); - - hangoutPort.onDisconnect.mock$fire(); - QUnit.equal(it2meService.helpers_.length, 0); -}); - -test('should handle multiple helper connections', function() { - // Hangout ---- connect ----> It2MeService. - hangoutPort.onMessage.mock$fire({ - method: 'connect', - accessCode: "123412341234" - }); - - // Hangout2 ---- connect ----> It2MeService. - var hangoutPort2 = createPort('it2me.helper.hangout'); - it2meService.onConnectExternal_(hangoutPort2); - - appLauncher.launch = function () { - return promiseResolveSynchronous('tabId2'); - }; - - hangoutPort2.onMessage.mock$fire({ - method: 'connect', - accessCode: "123412341234" - }); - - it2meService.onWebappConnect_(webappPort); - - var webappPort2 = createPort('it2me.helper.webapp', 'tabId2'); - it2meService.onWebappConnect_(webappPort2); - - webappPort.onMessage.mock$fire({ - method: 'sessionStateChanged', - state: remoting.ClientSession.State.CONNECTED - }); - - // verify that hangout can receive message events from webapp 1 - sinon.assert.calledWith(hangoutPort.postMessage, { - method: 'sessionStateChanged', - state: remoting.ClientSession.State.CONNECTED - }); - - webappPort2.onMessage.mock$fire({ - method: 'sessionStateChanged', - state: remoting.ClientSession.State.CLOSED - }); - - // verify that hangout can receive message events from webapp 2. - sinon.assert.calledWith(hangoutPort2.postMessage, { - method: 'sessionStateChanged', - state: remoting.ClientSession.State.CLOSED - }); -}); - -test('should reject unknown connection', function() { - it2meService.onWebappConnect_(webappPort); - sinon.assert.called(webappPort.disconnect); - - var randomPort = createPort('unsupported.port.name'); - it2meService.onConnectExternal_(randomPort); - sinon.assert.called(randomPort.disconnect); -}); - -})(); \ No newline at end of file
diff --git a/remoting/webapp/unittests/l10n_unittest.js b/remoting/webapp/unittests/l10n_unittest.js index 6ac3680f..043aaab 100644 --- a/remoting/webapp/unittests/l10n_unittest.js +++ b/remoting/webapp/unittests/l10n_unittest.js
@@ -8,10 +8,10 @@ module('l10n', { setup: function() { - sinon.stub(chrome.i18n, 'getMessage'); + sinon.$setupStub(chrome.i18n, 'getMessage'); }, teardown: function() { - chrome.i18n.getMessage.restore(); + chrome.i18n.getMessage.$testStub.restore(); } }); @@ -23,7 +23,8 @@ test('localizeElementFromTag() should replace innerText by default', function() { var element = document.createElement('div'); - chrome.i18n.getMessage.withArgs('tag').returns('<b>Hello World</b>'); + chrome.i18n.getMessage.$testStub.withArgs('tag') + .returns('<b>Hello World</b>'); l10n.localizeElementFromTag(element, 'tag'); @@ -33,7 +34,8 @@ test('localizeElementFromTag() should replace innerHTML if flag is set', function() { var element = document.createElement('div'); - chrome.i18n.getMessage.withArgs('tag').returns('<b>Hello World</b>'); + chrome.i18n.getMessage.$testStub.withArgs('tag') + .returns('<b>Hello World</b>'); l10n.localizeElementFromTag(element, 'tag', null, true); @@ -46,7 +48,8 @@ function() { var element = document.createElement('div'); element.setAttribute('i18n-content', 'tag'); - chrome.i18n.getMessage.withArgs('tag').returns('<b>Hello World</b>'); + chrome.i18n.getMessage.$testStub.withArgs('tag') + .returns('<b>Hello World</b>'); l10n.localizeElement(element); @@ -59,7 +62,7 @@ function() { var fixture = document.getElementById('qunit-fixture'); fixture.innerHTML = '<div class="target" i18n-title="tag"></div>'; - chrome.i18n.getMessage.withArgs('tag').returns('localized title'); + chrome.i18n.getMessage.$testStub.withArgs('tag').returns('localized title'); l10n.localize(); @@ -76,7 +79,7 @@ 'i18n-value-2="param2">' + '</div>'; - chrome.i18n.getMessage.withArgs('tag', ['param1', 'param2']) + chrome.i18n.getMessage.$testStub.withArgs('tag', ['param1', 'param2']) .returns('localized'); l10n.localize(); @@ -91,7 +94,7 @@ '<div class="target" i18n-content="tag"' + ' i18n-value-name-1="tag1" i18n-value-name-2="tag2"></div>'; - var getMessage = chrome.i18n.getMessage; + var getMessage = chrome.i18n.getMessage.$testStub; getMessage.withArgs('tag1').returns('param1'); getMessage.withArgs('tag2').returns('param2'); getMessage.withArgs('tag', ['param1', 'param2']).returns('localized');
diff --git a/remoting/webapp/unittests/menu_button_unittest.js b/remoting/webapp/unittests/menu_button_unittest.js index 7337134..1367b0da 100644 --- a/remoting/webapp/unittests/menu_button_unittest.js +++ b/remoting/webapp/unittests/menu_button_unittest.js
@@ -6,8 +6,11 @@ 'use strict'; +/** @type {(sinon.Spy|function():void)} */ var onShow = null; +/** @type {(sinon.Spy|function():void)} */ var onHide = null; +/** @type {remoting.MenuButton} */ var menuButton = null; module('MenuButton', { @@ -20,11 +23,12 @@ '<li id="menu-option-1">Option 1</li>' + '</ul>' + '</span>'; - onShow = sinon.spy(); - onHide = sinon.spy(); + onShow = /** @type {(sinon.Spy|function():void)} */ (sinon.spy()); + onHide = /** @type {(sinon.Spy|function():void)} */ (sinon.spy()); menuButton = new remoting.MenuButton( document.getElementById('menu-button-container'), - onShow, onHide); + /** @type {function():void} */ (onShow), + /** @type {function():void} */ (onHide)); }, teardown: function() { onShow = null; @@ -87,4 +91,4 @@ ok(style.backgroundImage == 'none'); }); -}()); \ No newline at end of file +}());
diff --git a/remoting/webapp/unittests/mock_signal_strategy.js b/remoting/webapp/unittests/mock_signal_strategy.js index 46e27f36..6935b05 100644 --- a/remoting/webapp/unittests/mock_signal_strategy.js +++ b/remoting/webapp/unittests/mock_signal_strategy.js
@@ -9,8 +9,8 @@ /** - * @param {string} jid - * @param {remoting.SignalStrategy.Type} type + * @param {string=} jid + * @param {remoting.SignalStrategy.Type=} type * * @implements {remoting.SignalStrategy} * @constructor
diff --git a/remoting/webapp/unittests/sinon_helpers.js b/remoting/webapp/unittests/sinon_helpers.js new file mode 100644 index 0000000..1524b40 --- /dev/null +++ b/remoting/webapp/unittests/sinon_helpers.js
@@ -0,0 +1,22 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var sinonHelpers = {}; + +sinonHelpers.reset = function() { + +/** + * @param {Object} obj + * @param {string} method + * @param {Function=} opt_stubFunction + * @return {sinon.TestStub} + * @suppress {reportUnknownTypes} + */ +sinon.$setupStub = function(obj, method, opt_stubFunction) { + sinon.stub(obj, method, opt_stubFunction); + obj[method].$testStub = /** @type {sinon.TestStub} */ (obj[method]); + return obj[method].$testStub; +}; + +};
diff --git a/remoting/webapp/unittests/test_start.js b/remoting/webapp/unittests/test_start.js new file mode 100644 index 0000000..8159ce7 --- /dev/null +++ b/remoting/webapp/unittests/test_start.js
@@ -0,0 +1,12 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Global test setup. +// This code is run before each test in every module. + +QUnit.testStart( + /** @param {{module:string, name:string}} details */ + function(details) { + sinonHelpers.reset(); + });
diff --git a/remoting/webapp/unittests/xhr_unittest.js b/remoting/webapp/unittests/xhr_unittest.js index 804f7159..ea32042 100644 --- a/remoting/webapp/unittests/xhr_unittest.js +++ b/remoting/webapp/unittests/xhr_unittest.js
@@ -2,6 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +/** + * @fileoverview + * @suppress {checkTypes|checkVars|reportUnknownTypes} + */ + (function() { 'use strict';
diff --git a/remoting/webapp/unittests/xmpp_connection_unittest.js b/remoting/webapp/unittests/xmpp_connection_unittest.js index a36261f..38aa6c2 100644 --- a/remoting/webapp/unittests/xmpp_connection_unittest.js +++ b/remoting/webapp/unittests/xmpp_connection_unittest.js
@@ -10,37 +10,44 @@ var testToken = 'testToken'; var socketId = 3; -var onStateChange = null; +/** @type {(sinon.Spy|function(remoting.SignalStrategy.State):void)} */ +var onStateChange = function() {}; + var onStanzaStr = null; + +/** @type {remoting.XmppConnection} */ var connection = null; module('XmppConnection', { setup: function() { onStateChange = sinon.spy(); onStanzaStr = sinon.spy(); + /** @param {Element} stanza */ function onStanza(stanza) { onStanzaStr(new XMLSerializer().serializeToString(stanza)); } - sinon.stub(chrome.socket, 'create'); - sinon.stub(chrome.socket, 'connect'); - sinon.stub(chrome.socket, 'write'); - sinon.stub(chrome.socket, 'read'); - sinon.stub(chrome.socket, 'destroy'); - sinon.stub(chrome.socket, 'secure'); + sinon.$setupStub(chrome.socket, 'create'); + sinon.$setupStub(chrome.socket, 'connect'); + sinon.$setupStub(chrome.socket, 'write'); + sinon.$setupStub(chrome.socket, 'read'); + sinon.$setupStub(chrome.socket, 'destroy'); + sinon.$setupStub(chrome.socket, 'secure'); connection = new remoting.XmppConnection(); - connection.setStateChangedCallback(onStateChange); + connection.setStateChangedCallback( + /** @type {function(remoting.SignalStrategy.State):void} */ + (onStateChange)); connection.setIncomingStanzaCallback(onStanza); }, teardown: function() { - chrome.socket.create.restore(); - chrome.socket.connect.restore(); - chrome.socket.write.restore(); - chrome.socket.read.restore(); - chrome.socket.destroy.restore(); - chrome.socket.secure.restore(); + chrome.socket.create.$testStub.restore(); + chrome.socket.connect.$testStub.restore(); + chrome.socket.write.$testStub.restore(); + chrome.socket.read.$testStub.restore(); + chrome.socket.destroy.$testStub.restore(); + chrome.socket.secure.$testStub.restore(); } }); @@ -50,11 +57,11 @@ sinon.assert.calledWith(onStateChange, remoting.SignalStrategy.State.CONNECTING); sinon.assert.calledWith(chrome.socket.create, "tcp", {}); - chrome.socket.create.getCall(0).args[2]({socketId: socketId}); + chrome.socket.create.$testStub.getCall(0).args[2]({socketId: socketId}); sinon.assert.calledWith( chrome.socket.connect, socketId, "xmpp.example.com", 123); - chrome.socket.connect.getCall(0).args[3](-1); + chrome.socket.connect.$testStub.getCall(0).args[3](-1); QUnit.equal(connection.getError(), remoting.Error.NETWORK_FAILURE); }); @@ -66,11 +73,11 @@ sinon.assert.calledWith(onStateChange, remoting.SignalStrategy.State.CONNECTING); sinon.assert.calledWith(chrome.socket.create, "tcp", {}); - chrome.socket.create.getCall(0).args[2]({socketId: socketId}); + chrome.socket.create.$testStub.getCall(0).args[2]({socketId: socketId}); sinon.assert.calledWith( chrome.socket.connect, socketId, "xmpp.example.com", 123); - chrome.socket.connect.getCall(0).args[3](0); + chrome.socket.connect.$testStub.getCall(0).args[3](0); sinon.assert.calledWith(onStateChange, remoting.SignalStrategy.State.HANDSHAKE); @@ -78,8 +85,9 @@ var parser = new remoting.XmppStreamParser(); var parserMock = sinon.mock(parser); var setCallbacksCalled = parserMock.expects('setCallbacks').once(); - connection.loginHandler_.onHandshakeDoneCallback_('test@example.com/123123', - parser); + var handshakeDoneCallback = + connection.loginHandler_.getHandshakeDoneCallbackForTesting(); + handshakeDoneCallback('test@example.com/123123', parser); sinon.assert.calledWith(onStateChange, remoting.SignalStrategy.State.CONNECTED); setCallbacksCalled.verify(); @@ -88,7 +96,7 @@ var data = base.encodeUtf8('<iq id="1">hello</iq>'); sinon.assert.calledWith(chrome.socket.read, socketId); var appendDataCalled = parserMock.expects('appendData').once().withArgs(data); - chrome.socket.read.getCall(0).args[1]({resultCode: 0, data: data}); + chrome.socket.read.$testStub.getCall(0).args[1]({resultCode: 0, data: data}); appendDataCalled.verify(); });
diff --git a/remoting/webapp/unittests/xmpp_login_handler_unittest.js b/remoting/webapp/unittests/xmpp_login_handler_unittest.js index 2b1adfd..1421651 100644 --- a/remoting/webapp/unittests/xmpp_login_handler_unittest.js +++ b/remoting/webapp/unittests/xmpp_login_handler_unittest.js
@@ -9,22 +9,45 @@ var testUsername = 'testUsername@gmail.com'; var testToken = 'testToken'; -var sendMessage = null; -var startTls = null; -var onHandshakeDone = null; -var onStanzaStr = null; -var onError = null; +/** @type {(sinon.Spy|function(string):void)} */ +var sendMessage_spy = function(msg) {}; +/** @type {function(string):void} */ +var sendMessage = function(msg) {}; + +/** @type {(sinon.Spy|function():void)} */ +var startTls_spy = function() {}; +/** @type {function():void} */ +var startTls = function() {}; + +/** @type {(sinon.Spy|function(string, remoting.XmppStreamParser):void)} */ +var onHandshakeDone_spy = function(name, parser) {}; +/** @type {function(string, remoting.XmppStreamParser):void} */ +var onHandshakeDone = function(name, parser) {}; + +/** @type {(sinon.Spy|function(remoting.Error, string):void)} */ +var onError_spy = function(error, message) {}; +/** @type {function(remoting.Error, string):void} */ +var onError = function(error, message) {}; + +/** @type {remoting.XmppLoginHandler} */ var loginHandler = null; module('XmppLoginHandler', { setup: function() { - sendMessage = sinon.spy(); - startTls = sinon.spy(); - onHandshakeDone = sinon.spy(); - onError = sinon.spy(); + sendMessage_spy = sinon.spy(); + sendMessage = /** @type {function(string):void} */ (sendMessage_spy); + startTls_spy = sinon.spy(); + startTls = /** @type {function():void} */ (startTls_spy); + onHandshakeDone_spy = sinon.spy(); + onHandshakeDone = + /** @type {function(string, remoting.XmppStreamParser):void} */ + (onHandshakeDone_spy); + onError_spy = sinon.spy(); + onError = /** @type {function(remoting.Error, string):void} */(onError_spy); + loginHandler = new remoting.XmppLoginHandler( - 'google.com', testUsername, testToken, false, sendMessage, - startTls, onHandshakeDone, onError); + 'google.com', testUsername, testToken, false, + sendMessage, startTls, onHandshakeDone, onError); } }); @@ -33,7 +56,7 @@ loginHandler.start(); sinon.assert.calledWith(startTls); - startTls.reset(); + startTls_spy.reset(); loginHandler.onTlsStarted(); var cookie = window.btoa("\0" + testUsername + "\0" + testToken); @@ -47,7 +70,7 @@ 'auth:allow-non-google-login="true" ' + 'xmlns:auth="http://www.google.com/talk/protocol/auth">' + cookie + '</auth>'); - sendMessage.reset(); + sendMessage_spy.reset(); loginHandler.onDataReceived(base.encodeUtf8( '<stream:stream from="google.com" id="DCDDE5171CB2154A" version="1.0" ' + @@ -79,7 +102,7 @@ '<iq type="set" id="1">' + '<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>' + '</iq>'); - sendMessage.reset(); + sendMessage_spy.reset(); loginHandler.onDataReceived(base.encodeUtf8( '<stream:stream from="google.com" id="104FA10576E2AA80" version="1.0" ' + @@ -110,7 +133,7 @@ '<stream:stream to="google.com" version="1.0" xmlns="jabber:client" ' + 'xmlns:stream="http://etherx.jabber.org/streams">' + '<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>'); - sendMessage.reset(); + sendMessage_spy.reset(); loginHandler.onDataReceived(base.encodeUtf8( '<stream:stream from="google.com" id="78A87C70559EF28A" version="1.0" ' +
diff --git a/remoting/webapp/unittests/xmpp_stream_parser_unittest.js b/remoting/webapp/unittests/xmpp_stream_parser_unittest.js index 21a972e..ec6cc45 100644 --- a/remoting/webapp/unittests/xmpp_stream_parser_unittest.js +++ b/remoting/webapp/unittests/xmpp_stream_parser_unittest.js
@@ -6,14 +6,20 @@ 'use strict'; +/** @type {Function} */ var onStanzaStr = null; -var onError = null; + +/** @type {function(string):void} */ +var onError = function(msg) {}; + +/** @type {remoting.XmppStreamParser} */ var parser = null; module('XmppStreamParser', { setup: function() { onStanzaStr = sinon.spy(); - onError = sinon.spy(); + onError = /** @type {function(string):void} */ (sinon.spy()); + /** @param {Element} stanza */ function onStanza(stanza) { onStanzaStr(new XMLSerializer().serializeToString(stanza)); }
diff --git a/rlz/chromeos/lib/rlz_value_store_chromeos.cc b/rlz/chromeos/lib/rlz_value_store_chromeos.cc index 2232b5a..45f2500 100644 --- a/rlz/chromeos/lib/rlz_value_store_chromeos.cc +++ b/rlz/chromeos/lib/rlz_value_store_chromeos.cc
@@ -211,14 +211,14 @@ void RlzValueStoreChromeOS::ReadStore() { int error_code = 0; std::string error_msg; - JSONFileValueSerializer serializer(store_path_); + JSONFileValueDeserializer deserializer(store_path_); scoped_ptr<base::Value> value( - serializer.Deserialize(&error_code, &error_msg)); + deserializer.Deserialize(&error_code, &error_msg)); switch (error_code) { - case JSONFileValueSerializer::JSON_NO_SUCH_FILE: + case JSONFileValueDeserializer::JSON_NO_SUCH_FILE: read_only_ = false; break; - case JSONFileValueSerializer::JSON_NO_ERROR: + case JSONFileValueDeserializer::JSON_NO_ERROR: read_only_ = false; rlz_store_.reset(static_cast<base::DictionaryValue*>(value.release())); break;
diff --git a/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc b/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc index 2d337c6..8e7e144b 100644 --- a/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc +++ b/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc
@@ -651,6 +651,10 @@ return UnsafeTrap(AllowRedirectedSyscall, NULL); } +#if !defined(ADDRESS_SANITIZER) +// ASan does not allow changing the signal handler for SIGBUS, and treats it as +// a fatal signal. + int bus_handler_fd_ = -1; void SigBusHandler(int, siginfo_t* info, void* void_context) { @@ -679,6 +683,7 @@ BPF_ASSERT(close(fds[1]) == 0); BPF_ASSERT(c == 0x55); } +#endif // !defined(ADDRESS_SANITIZER) BPF_TEST_C(SandboxBPF, SigMask, RedirectAllSyscallsPolicy) { // Signal masks are potentially tricky to handle. For instance, if we
diff --git a/sandbox/win/src/broker_services.cc b/sandbox/win/src/broker_services.cc index 8a29f9b..d88e5eb 100644 --- a/sandbox/win/src/broker_services.cc +++ b/sandbox/win/src/broker_services.cc
@@ -88,8 +88,8 @@ const sandbox::AppContainerAttributes* app_container = policy->GetAppContainer(); - // We cannot cache tokens with an app container. - if (app_container) + // We cannot cache tokens with an app container or lowbox. + if (app_container || policy->GetLowBoxSid()) return false; return true;
diff --git a/skia/BUILD.gn b/skia/BUILD.gn index 8c843c9c..3e3bc0c 100644 --- a/skia/BUILD.gn +++ b/skia/BUILD.gn
@@ -255,7 +255,6 @@ "/wd4554", # 'operator' : check operator precedence for possible error "/wd4748", # compiler will disable optimizations if a function has inline # assembly code contains flow control(jmp or jcc) statements. - "/wd4800", # forcing value to bool 'true/false'(assigning int to bool). ] } @@ -343,7 +342,6 @@ "//third_party/skia/include/utils/SkLayer.h", "//third_party/skia/include/utils/SkMeshUtils.h", "//third_party/skia/include/utils/SkNinePatch.h", - "//third_party/skia/include/utils/SkParse.h", "//third_party/skia/include/utils/SkParsePaint.h", "//third_party/skia/include/utils/SkParsePath.h", "//third_party/skia/include/utils/SkRandom.h", @@ -364,8 +362,6 @@ "//third_party/skia/src/utils/SkMeshUtils.cpp", "//third_party/skia/src/utils/SkNinePatch.cpp", "//third_party/skia/src/utils/SkOSFile.cpp", - "//third_party/skia/src/utils/SkParse.cpp", - "//third_party/skia/src/utils/SkParseColor.cpp", "//third_party/skia/src/utils/SkParsePath.cpp", "//third_party/skia/src/utils/SkPathUtils.cpp", "//third_party/skia/src/utils/SkSHA1.cpp",
diff --git a/skia/skia_library.gypi b/skia/skia_library.gypi index 2163a797..04e428a 100644 --- a/skia/skia_library.gypi +++ b/skia/skia_library.gypi
@@ -102,7 +102,6 @@ '../third_party/skia/include/utils/SkLayer.h', '../third_party/skia/include/utils/SkMeshUtils.h', '../third_party/skia/include/utils/SkNinePatch.h', - '../third_party/skia/include/utils/SkParse.h', '../third_party/skia/include/utils/SkParsePaint.h', '../third_party/skia/include/utils/SkParsePath.h', '../third_party/skia/include/utils/SkRandom.h', @@ -124,8 +123,6 @@ '../third_party/skia/src/utils/SkMeshUtils.cpp', '../third_party/skia/src/utils/SkNinePatch.cpp', '../third_party/skia/src/utils/SkOSFile.cpp', - '../third_party/skia/src/utils/SkParse.cpp', - '../third_party/skia/src/utils/SkParseColor.cpp', '../third_party/skia/src/utils/SkParsePath.cpp', '../third_party/skia/src/utils/SkPathUtils.cpp', '../third_party/skia/src/utils/SkSHA1.cpp',
diff --git a/storage/browser/blob/blob_storage_context.cc b/storage/browser/blob/blob_storage_context.cc index 5170ceb3..b673930 100644 --- a/storage/browser/blob/blob_storage_context.cc +++ b/storage/browser/blob/blob_storage_context.cc
@@ -375,8 +375,8 @@ bool BlobStorageContext::AppendBlob( const std::string& target_blob_uuid, const InternalBlobData& blob, - size_t offset, - size_t length, + uint64_t offset, + uint64_t length, InternalBlobData::Builder* target_blob_builder) { DCHECK(length > 0); @@ -395,10 +395,10 @@ for (; iter != items.end() && length > 0; ++iter) { scoped_refptr<ShareableBlobDataItem> shareable_item = iter->get(); const BlobDataItem& item = *(shareable_item->item()); - size_t item_length = item.length(); + uint64_t item_length = item.length(); DCHECK_GT(item_length, offset); - size_t current_length = item_length - offset; - size_t new_length = current_length > length ? length : current_length; + uint64_t current_length = item_length - offset; + uint64_t new_length = current_length > length ? length : current_length; bool reusing_blob_item = offset == 0 && new_length == item.length(); UMA_HISTOGRAM_BOOLEAN("Storage.Blob.ReusedItem", reusing_blob_item);
diff --git a/storage/browser/blob/blob_storage_context.h b/storage/browser/blob/blob_storage_context.h index 175e90020..cf73c8a2 100644 --- a/storage/browser/blob/blob_storage_context.h +++ b/storage/browser/blob/blob_storage_context.h
@@ -122,8 +122,8 @@ // have to split an item. bool AppendBlob(const std::string& target_blob_uuid, const InternalBlobData& blob, - size_t offset, - size_t length, + uint64_t offset, + uint64_t length, InternalBlobData::Builder* target_blob_data); bool IsInUse(const std::string& uuid);
diff --git a/sync/api/sync_data.cc b/sync/api/sync_data.cc index 7fbdbc2f..0dd567d6 100644 --- a/sync/api/sync_data.cc +++ b/sync/api/sync_data.cc
@@ -218,10 +218,4 @@ attachment_service_.GetOrDownloadAttachments(attachment_ids, callback); } -void SyncDataRemote::DropAttachments( - const AttachmentIdList& attachment_ids, - const AttachmentService::DropCallback& callback) { - attachment_service_.DropAttachments(attachment_ids, callback); -} - } // namespace syncer
diff --git a/sync/api/sync_data.h b/sync/api/sync_data.h index 4e5acd3..6815896 100644 --- a/sync/api/sync_data.h +++ b/sync/api/sync_data.h
@@ -190,15 +190,6 @@ void GetOrDownloadAttachments( const AttachmentIdList& attachment_ids, const AttachmentService::GetOrDownloadCallback& callback); - - // Drop (delete from local storage) the attachments associated with this - // SyncData specified in |attachment_ids|. This method will not delete - // attachments from the server. - // - // |callback| will be invoked when the operation is complete (successfully - // or otherwise). - void DropAttachments(const AttachmentIdList& attachment_ids, - const AttachmentService::DropCallback& callback); }; // gmock printer helper.
diff --git a/sync/api/sync_data_unittest.cc b/sync/api/sync_data_unittest.cc index a0a83cdb..94c3f4c 100644 --- a/sync/api/sync_data_unittest.cc +++ b/sync/api/sync_data_unittest.cc
@@ -117,8 +117,8 @@ EXPECT_TRUE(data.GetAttachmentIds().empty()); } -// TODO(maniscalco): Add test cases that verify GetLocalAttachmentsForUpload and -// DropAttachments calls are passed through to the underlying AttachmentService. +// TODO(maniscalco): Add test cases that verify GetLocalAttachmentsForUpload +// calls are passed through to the underlying AttachmentService. } // namespace
diff --git a/sync/internal_api/attachments/attachment_service_impl.cc b/sync/internal_api/attachments/attachment_service_impl.cc index dab7aa73..cc04408 100644 --- a/sync/internal_api/attachments/attachment_service_impl.cc +++ b/sync/internal_api/attachments/attachment_service_impl.cc
@@ -176,16 +176,6 @@ state)); } -void AttachmentServiceImpl::DropAttachments( - const AttachmentIdList& attachment_ids, - const DropCallback& callback) { - DCHECK(CalledOnValidThread()); - attachment_store_->Drop(attachment_ids, - base::Bind(&AttachmentServiceImpl::DropDone, - weak_ptr_factory_.GetWeakPtr(), - callback)); -} - void AttachmentServiceImpl::ReadDone( const scoped_refptr<GetOrDownloadState>& state, const AttachmentStore::Result& result, @@ -234,18 +224,6 @@ } } -void AttachmentServiceImpl::DropDone(const DropCallback& callback, - const AttachmentStore::Result& result) { - AttachmentService::DropResult drop_result = - AttachmentService::DROP_UNSPECIFIED_ERROR; - if (result == AttachmentStore::SUCCESS) { - drop_result = AttachmentService::DROP_SUCCESS; - } - // TODO(maniscalco): Deal with case where an error occurred (bug 361251). - base::MessageLoop::current()->PostTask(FROM_HERE, - base::Bind(callback, drop_result)); -} - void AttachmentServiceImpl::UploadDone( const AttachmentUploader::UploadResult& result, const AttachmentId& attachment_id) {
diff --git a/sync/internal_api/attachments/attachment_service_proxy.cc b/sync/internal_api/attachments/attachment_service_proxy.cc index 6b1040b..92104ce 100644 --- a/sync/internal_api/attachments/attachment_service_proxy.cc +++ b/sync/internal_api/attachments/attachment_service_proxy.cc
@@ -26,15 +26,6 @@ FROM_HERE, base::Bind(callback, result, base::Passed(&attachments))); } -// Invokes |callback| with |result| and |attachments| in the |task_runner| -// thread. -void ProxyDropCallback( - const scoped_refptr<base::SequencedTaskRunner>& task_runner, - const AttachmentService::DropCallback& callback, - const AttachmentService::DropResult& result) { - task_runner->PostTask(FROM_HERE, base::Bind(callback, result)); -} - } // namespace AttachmentServiceProxy::AttachmentServiceProxy() { @@ -78,19 +69,6 @@ proxy_callback)); } -void AttachmentServiceProxy::DropAttachments( - const AttachmentIdList& attachment_ids, - const DropCallback& callback) { - DCHECK(wrapped_task_runner_.get()); - DropCallback proxy_callback = base::Bind( - &ProxyDropCallback, base::ThreadTaskRunnerHandle::Get(), callback); - wrapped_task_runner_->PostTask(FROM_HERE, - base::Bind(&AttachmentService::DropAttachments, - core_, - attachment_ids, - proxy_callback)); -} - void AttachmentServiceProxy::UploadAttachments( const AttachmentIdSet& attachment_ids) { DCHECK(wrapped_task_runner_.get()); @@ -120,15 +98,6 @@ wrapped_->GetOrDownloadAttachments(attachment_ids, callback); } -void AttachmentServiceProxy::Core::DropAttachments( - const AttachmentIdList& attachment_ids, - const DropCallback& callback) { - if (!wrapped_) { - return; - } - wrapped_->DropAttachments(attachment_ids, callback); -} - void AttachmentServiceProxy::Core::UploadAttachments( const AttachmentIdSet& attachment_ids) { if (!wrapped_) {
diff --git a/sync/internal_api/attachments/attachment_service_proxy_unittest.cc b/sync/internal_api/attachments/attachment_service_proxy_unittest.cc index 2353d26..41af1b23 100644 --- a/sync/internal_api/attachments/attachment_service_proxy_unittest.cc +++ b/sync/internal_api/attachments/attachment_service_proxy_unittest.cc
@@ -48,14 +48,6 @@ base::Passed(&attachments))); } - void DropAttachments(const AttachmentIdList& attachment_ids, - const DropCallback& callback) override { - CalledOnValidThread(); - Increment(); - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(callback, AttachmentService::DROP_SUCCESS)); - } - void UploadAttachments(const AttachmentIdSet& attachments_ids) override { CalledOnValidThread(); Increment(); @@ -101,10 +93,7 @@ callback_get_or_download = base::Bind(&AttachmentServiceProxyTest::IncrementGetOrDownload, base::Unretained(this)); - callback_drop = base::Bind(&AttachmentServiceProxyTest::IncrementDrop, - base::Unretained(this)); count_callback_get_or_download = 0; - count_callback_drop = 0; } void TearDown() override { @@ -124,12 +113,6 @@ ++count_callback_get_or_download; } - // a DropCallback - void IncrementDrop(const AttachmentService::DropResult&) { - CalledOnValidThread(); - ++count_callback_drop; - } - void WaitForStubThread() { base::WaitableEvent done(false, false); stub_thread->message_loop()->PostTask( @@ -144,12 +127,9 @@ scoped_ptr<AttachmentServiceProxy> proxy; AttachmentService::GetOrDownloadCallback callback_get_or_download; - AttachmentService::DropCallback callback_drop; // number of times callback_get_or_download was invoked int count_callback_get_or_download; - // number of times callback_drop was invoked - int count_callback_drop; }; TEST_F(AttachmentServiceProxyTest, GetStore) { @@ -161,11 +141,10 @@ // thread. TEST_F(AttachmentServiceProxyTest, MethodsAreProxied) { proxy->GetOrDownloadAttachments(AttachmentIdList(), callback_get_or_download); - proxy->DropAttachments(AttachmentIdList(), callback_drop); proxy->UploadAttachments(AttachmentIdSet()); // Wait for the posted calls to execute in the stub thread. WaitForStubThread(); - EXPECT_EQ(3, stub->GetCallCount()); + EXPECT_EQ(2, stub->GetCallCount()); // At this point the stub thread has finished executed the calls. However, the // result callbacks it has posted may not have executed yet. Wait a second // time to ensure the stub thread has executed the posted result callbacks. @@ -173,7 +152,6 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, count_callback_get_or_download); - EXPECT_EQ(1, count_callback_drop); } // Verify that it's safe to use an AttachmentServiceProxy even after its wrapped
diff --git a/sync/internal_api/public/attachments/attachment_service.h b/sync/internal_api/public/attachments/attachment_service.h index 758f960..944a71f 100644 --- a/sync/internal_api/public/attachments/attachment_service.h +++ b/sync/internal_api/public/attachments/attachment_service.h
@@ -36,15 +36,6 @@ void(const GetOrDownloadResult&, scoped_ptr<AttachmentMap> attachments)> GetOrDownloadCallback; - // The result of a DropAttachments operation. - enum DropResult { - DROP_SUCCESS, // No error, all attachments dropped. - DROP_UNSPECIFIED_ERROR, // An unspecified error occurred. Some or all - // attachments may not have been dropped. - }; - - typedef base::Callback<void(const DropResult&)> DropCallback; - // An interface that embedder code implements to be notified about different // events that originate from AttachmentService. // This interface will be called from the same thread AttachmentService was @@ -71,10 +62,6 @@ const AttachmentIdList& attachment_ids, const GetOrDownloadCallback& callback) = 0; - // See SyncData::DropAttachments. - virtual void DropAttachments(const AttachmentIdList& attachment_ids, - const DropCallback& callback) = 0; - // Schedules the attachments identified by |attachment_ids| to be uploaded to // the server. //
diff --git a/sync/internal_api/public/attachments/attachment_service_impl.h b/sync/internal_api/public/attachments/attachment_service_impl.h index c9992c0..e35f548 100644 --- a/sync/internal_api/public/attachments/attachment_service_impl.h +++ b/sync/internal_api/public/attachments/attachment_service_impl.h
@@ -62,8 +62,6 @@ AttachmentStore* GetStore() override; void GetOrDownloadAttachments(const AttachmentIdList& attachment_ids, const GetOrDownloadCallback& callback) override; - void DropAttachments(const AttachmentIdList& attachment_ids, - const DropCallback& callback) override; void UploadAttachments(const AttachmentIdSet& attachment_ids) override; // NetworkChangeObserver implementation. @@ -85,8 +83,6 @@ void WriteDone(const scoped_refptr<GetOrDownloadState>& state, const Attachment& attachment, const AttachmentStore::Result& result); - void DropDone(const DropCallback& callback, - const AttachmentStore::Result& result); void UploadDone(const AttachmentUploader::UploadResult& result, const AttachmentId& attachment_id); void DownloadDone(const scoped_refptr<GetOrDownloadState>& state,
diff --git a/sync/internal_api/public/attachments/attachment_service_proxy.h b/sync/internal_api/public/attachments/attachment_service_proxy.h index cab107ef..3a96660 100644 --- a/sync/internal_api/public/attachments/attachment_service_proxy.h +++ b/sync/internal_api/public/attachments/attachment_service_proxy.h
@@ -56,8 +56,6 @@ AttachmentStore* GetStore() override; void GetOrDownloadAttachments(const AttachmentIdList& attachment_ids, const GetOrDownloadCallback& callback) override; - void DropAttachments(const AttachmentIdList& attachment_ids, - const DropCallback& callback) override; void UploadAttachments(const AttachmentIdSet& attachment_ids) override; protected: @@ -85,8 +83,6 @@ void GetOrDownloadAttachments( const AttachmentIdList& attachment_ids, const GetOrDownloadCallback& callback) override; - void DropAttachments(const AttachmentIdList& attachment_ids, - const DropCallback& callback) override; void UploadAttachments(const AttachmentIdSet& attachment_ids) override; protected:
diff --git a/sync/internal_api/sync_encryption_handler_impl.cc b/sync/internal_api/sync_encryption_handler_impl.cc index 709b38d..4bf559fd 100644 --- a/sync/internal_api/sync_encryption_handler_impl.cc +++ b/sync/internal_api/sync_encryption_handler_impl.cc
@@ -174,7 +174,8 @@ &decrypted_keystore_bootstrap)) { return false; } - JSONStringValueSerializer json(&decrypted_keystore_bootstrap); + + JSONStringValueDeserializer json(decrypted_keystore_bootstrap); scoped_ptr<base::Value> deserialized_keystore_keys( json.Deserialize(NULL, NULL)); if (!deserialized_keystore_keys)
diff --git a/sync/internal_api/sync_encryption_handler_impl_unittest.cc b/sync/internal_api/sync_encryption_handler_impl_unittest.cc index 9fbfcfe2..829ecd2 100644 --- a/sync/internal_api/sync_encryption_handler_impl_unittest.cc +++ b/sync/internal_api/sync_encryption_handler_impl_unittest.cc
@@ -665,7 +665,7 @@ ASSERT_TRUE( GetCryptographer()->encryptor()->DecryptString(decoded_bootstrap, &decrypted_bootstrap)); - JSONStringValueSerializer json(decrypted_bootstrap); + JSONStringValueDeserializer json(decrypted_bootstrap); scoped_ptr<base::Value> deserialized_keystore_keys( json.Deserialize(NULL, NULL)); ASSERT_TRUE(deserialized_keystore_keys.get());
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json index 5ec0a54..f7ec88a 100644 --- a/testing/buildbot/chromium.perf.json +++ b/testing/buildbot/chromium.perf.json
@@ -12,6 +12,11 @@ { "name": "host_info", "script": "host_info.py" + }, + { + "name": "gpu_perftests", + "script": "gtest_perf_test.py", + "args": ["gpu_perftests"] } ] }, @@ -38,5 +43,50 @@ "script": "host_info.py" } ] + }, + "Win 7 ATI GPU Perf": { + "scripts": [ + { + "name": "gpu_perftests", + "script": "gtest_perf_test.py", + "args": ["gpu_perftests", "--test-launcher-print-test-stdio=always"] + } + ] + }, + "Win 7 Intel GPU Perf": { + "scripts": [ + { + "name": "gpu_perftests", + "script": "gtest_perf_test.py", + "args": ["gpu_perftests", "--test-launcher-print-test-stdio=always"] + } + ] + }, + "Win 7 Nvidia GPU Perf": { + "scripts": [ + { + "name": "gpu_perftests", + "script": "gtest_perf_test.py", + "args": ["gpu_perftests", "--test-launcher-print-test-stdio=always"] + } + ] + }, + "Mac 10.8 Perf (1)": { + "scripts": [ + { + "name": "gpu_perftests", + "script": "gtest_perf_test.py", + "args": ["gpu_perftests", "--test-launcher-print-test-stdio=always"] + } + ] + }, + "Mac 10.9 Perf (1)": { + "scripts": [ + { + "name": "gpu_perftests", + "script": "gtest_perf_test.py", + "args": ["gpu_perftests", "--test-launcher-print-test-stdio=always"] + } + ] } }
diff --git a/testing/buildbot/chromium.webkit.json b/testing/buildbot/chromium.webkit.json index 5831f7f2..7c13243b 100644 --- a/testing/buildbot/chromium.webkit.json +++ b/testing/buildbot/chromium.webkit.json
@@ -1,5 +1,83 @@ { + "WebKit XP": { + "gtest_tests": [ + "blink_heap_unittests", + "blink_platform_unittests", + "webkit_unit_tests", + "wtf_unittests" + ], + "scripts": [ + { + "name": "webkit_lint", + "script": "webkit_lint.py" + }, + { + "name": "webkit_python_tests", + "script": "webkit_python_tests.py" + } + ] + }, + "WebKit Win7": { + "gtest_tests": [ + "blink_heap_unittests", + "blink_platform_unittests", + "webkit_unit_tests", + "wtf_unittests" + ], + "scripts": [ + { + "name": "webkit_lint", + "script": "webkit_lint.py" + }, + { + "name": "webkit_python_tests", + "script": "webkit_python_tests.py" + } + ] + }, "WebKit Linux": { + "gtest_tests": [ + "blink_heap_unittests", + "blink_platform_unittests", + "webkit_unit_tests", + "wtf_unittests" + ], + "scripts": [ + { + "name": "webkit_lint", + "script": "webkit_lint.py" + }, + { + "name": "webkit_python_tests", + "script": "webkit_python_tests.py" + } + ] + }, + "WebKit Linux 32": { + "gtest_tests": [ + "blink_heap_unittests", + "blink_platform_unittests", + "webkit_unit_tests", + "wtf_unittests" + ], + "scripts": [ + { + "name": "webkit_lint", + "script": "webkit_lint.py" + }, + { + "name": "webkit_python_tests", + "script": "webkit_python_tests.py" + } + ] + }, + "WebKit Linux (dbg)": { + "gtest_tests": [ + "blink_heap_unittests", + "blink_platform_unittests", + "webkit_unit_tests", + "wtf_unittests" + ], "scripts": [ { "name": "webkit_lint",
diff --git a/testing/buildbot/trybot_analyze_config.json b/testing/buildbot/trybot_analyze_config.json index 7921d669..a469ddd 100644 --- a/testing/buildbot/trybot_analyze_config.json +++ b/testing/buildbot/trybot_analyze_config.json
@@ -34,12 +34,17 @@ "third_party/accessibility-audit/axs_testing.js", "third_party/hunspell_dictionaries/.*", "third_party/zlib/google/test/data/.*", - "tools/clang/scripts/plugin_flags.sh", + "tools/clang/scripts/plugin_flags.py", "tools/clang/scripts/update.py", "tools/clang/scripts/update.sh", "tools/metrics/histograms/histograms.xml", "tools/perf/.*", "tools/telemetry/.*" ] + }, + "ios": { + "exclusions": [ + "ios/build/bots/.*" + ] } }
diff --git a/testing/chromoting/chromoting_integration_tests.isolate b/testing/chromoting/chromoting_integration_tests.isolate index be04bd6..82bf5f1 100644 --- a/testing/chromoting/chromoting_integration_tests.isolate +++ b/testing/chromoting/chromoting_integration_tests.isolate
@@ -30,6 +30,7 @@ '../../remoting/tools/internal/test-account-host-config.json', '<(PRODUCT_DIR)/remoting/com.google.chrome.remote_desktop.json', '<(PRODUCT_DIR)/remoting/com.google.chrome.remote_assistance.json', + '<(PRODUCT_DIR)/remoting-me2me-host.deb', ], }, }], @@ -79,20 +80,7 @@ ], }, }], - ['OS=="mac"', { - 'variables': { - 'command': [ - '../test_env.py', - '<(PRODUCT_DIR)/browser_tests<(EXECUTABLE_SUFFIX)', - '--gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch', - '--run-manual', - '--ui-test-action-timeout=100000', - '--webapp-unpacked=<(PRODUCT_DIR)/remoting/remoting.webapp', - '--extension-name=Chromoting', - ], - }, - }], - ['OS=="win"', { + ['OS=="win" or OS=="mac"', { 'variables': { 'command': [ '../test_env.py', @@ -100,7 +88,7 @@ '--gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch:RemoteDesktopBrowserTest.MANUAL_Auth', '--run-manual', '--ui-test-action-timeout=100000', - '--webapp-unpacked=<(PRODUCT_DIR)/remoting/remoting.webapp', + '--webapp-unpacked=<(PRODUCT_DIR)/remoting/remoting.webapp.v2', '--extension-name=Chromoting', '--accounts-file=../../remoting/tools/internal/test_accounts.json', '--account-type=gmail',
diff --git a/testing/commit_queue/config.json b/testing/commit_queue/config.json index 8ae6e31..a335f78f 100644 --- a/testing/commit_queue/config.json +++ b/testing/commit_queue/config.json
@@ -5,6 +5,7 @@ "trybots": { "launched": { "tryserver.chromium.linux": { + "android_amp_rel_tests_recipe": ["defaulttests"], "cast_shell": ["defaulttests"], "cast_shell_apk": ["defaulttests"], "linux_android_rel_ng": ["defaulttests"],
diff --git a/testing/scripts/webkit_lint.py b/testing/scripts/webkit_lint.py index c33f87b..eeb9367 100755 --- a/testing/scripts/webkit_lint.py +++ b/testing/scripts/webkit_lint.py
@@ -14,6 +14,7 @@ def main_run(args): with common.temporary_file() as tempfile_path: rc = common.run_command([ + sys.executable, os.path.join(common.SRC_DIR, 'third_party', 'WebKit', 'Tools', 'Scripts', 'lint-test-expectations'), '--json', tempfile_path
diff --git a/testing/scripts/webkit_python_tests.py b/testing/scripts/webkit_python_tests.py index 582cf32..b0c2fbc 100755 --- a/testing/scripts/webkit_python_tests.py +++ b/testing/scripts/webkit_python_tests.py
@@ -14,6 +14,7 @@ def main_run(args): with common.temporary_file() as tempfile_path: rc = common.run_command([ + sys.executable, os.path.join(common.SRC_DIR, 'third_party', 'WebKit', 'Tools', 'Scripts', 'test-webkitpy'), '--write-full-results-to', tempfile_path,
diff --git a/third_party/closure_compiler/externs/developer_private.js b/third_party/closure_compiler/externs/developer_private.js index 9c156f4..a94b1998 100644 --- a/third_party/closure_compiler/externs/developer_private.js +++ b/third_party/closure_compiler/externs/developer_private.js
@@ -5,7 +5,7 @@ /** @fileoverview Externs generated from namespace: developerPrivate */ // Note: hand-modified to change Array to !Array in ItemInfo typedef, and add -// typedef {string} for idl enums. +// enum definitions. /** * @typedef {string} @@ -76,30 +76,57 @@ /** * @typedef {{ - * failQuietly: boolean + * failQuietly: (boolean|undefined) * }} */ var ReloadOptions; /** - * @typedef {string} + * @typedef {{ + * failQuietly: (boolean|undefined) + * }} */ -var PackStatus; +var LoadUnpackedOptions; /** - * @typedef {string} + * @enum {string} */ -var FileType; +chrome.developerPrivate.PackStatus = { + SUCCESS: 'SUCCESS', + ERROR: 'ERROR', + WARNING: 'WARNING', +}; /** - * @typedef {string} + * @enum {string} */ -var SelectType; +chrome.developerPrivate.FileType = { + LOAD: 'LOAD', + PEM: 'PEM', +}; /** - * @typedef {string} + * @enum {string} */ -var EventType; +chrome.developerPrivate.SelectType = { + FILE: 'FILE', + FOLDER: 'FOLDER', +}; + +/** + * @enum {string} + */ +chrome.developerPrivate.EventType = { + INSTALLED: 'INSTALLED', + UNINSTALLED: 'UNINSTALLED', + LOADED: 'LOADED', + UNLOADED: 'UNLOADED', + // New window / view opened. + VIEW_REGISTERED: 'VIEW_REGISTERED', + // window / view closed. + VIEW_UNREGISTERED: 'VIEW_UNREGISTERED', + ERROR_ADDED: 'ERROR_ADDED', +} /** * @typedef {{ @@ -107,7 +134,7 @@ * item_path: string, * pem_path: string, * override_flags: number, - * status: PackStatus + * status: chrome.developerPrivate.PackStatus * }} */ var PackDirectoryResponse; @@ -121,7 +148,7 @@ /** * @typedef {{ - * event_type: EventType, + * event_type: chrome.developerPrivate.EventType, * item_id: string * }} */ @@ -231,9 +258,10 @@ /** * Loads a user-selected unpacked item. + * @param {LoadUnpackedOptions=} options Additional configuration parameters. * @param {Function=} callback */ -chrome.developerPrivate.loadUnpacked = function(callback) {}; +chrome.developerPrivate.loadUnpacked = function(options, callback) {}; /** * Loads an extension / app. @@ -244,8 +272,10 @@ /** * Open Dialog to browse to an entry. - * @param {SelectType} selectType Select a file or a folder. - * @param {FileType} fileType Required file type. For example, pem type is for + * @param {chrome.developerPrivate.SelectType} selectType + * Select a file or a folder. + * @param {chrome.developerPrivate.FileType} fileType + * Required file type. For example, pem type is for * private key and load type is for an unpacked item. * @param {Function} callback called with selected item's path. */
diff --git a/third_party/google_input_tools/README.chromium b/third_party/google_input_tools/README.chromium index da32a65..e2ac725f 100644 --- a/third_party/google_input_tools/README.chromium +++ b/third_party/google_input_tools/README.chromium
@@ -1,8 +1,8 @@ Name: Google Input Tools Short Name: google_input_tools URL: https://github.com/googlei18n/google-input-tools.git -Version: 1.0.6.1 -Revision: @6e95b6e74690a04a6effe624bfe1c54ad802b7ec +Version: 1.0.6.2 +Revision: @1af2274f7a754bb3f18a3618f0e94981d682bc16 License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/am/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/am/messages.json index 5b754390..56db53c 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/am/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/am/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u12ed\u1245\u122d\u1273\u1363 \u12a0\u12cd\u1273\u1228 \u1218\u1228\u1265 \u1235\u1208\u121b\u12ed\u1308\u129d \u12e8\u12a5\u1305 \u133d\u1211\u134d \u1218\u1320\u1240\u121d \u12a0\u12ed\u127d\u1209\u120d\u121d\u1362" }, "handwriting_privacy_info": { - "message": "\u12e8\u12a5\u122d\u1235\u12ce \u130d\u1264\u1275 \u12c8\u12f0 Google \u12a0\u1308\u120d\u130b\u12ed \u133d\u1211\u134d\u1295 \u1208\u12ed\u1276 \u1208\u121b\u12c8\u1245 \u1232\u1263\u120d \u12ed\u120b\u12ab\u120d" + "message": "\u133d\u1211\u134d\u1295 \u1208\u12ed\u1276 \u1208\u121b\u12c8\u1245 \u1232\u1263\u120d \u12e8\u12a5\u122d\u1235\u12ce \u130d\u1264\u1275 \u12c8\u12f0 \u12e8Google \u12a0\u1308\u120d\u130b\u12ee\u127d \u12ed\u120b\u12ab\u120d" }, "hide_keyboard": { "message": "\u12e8\u1241\u120d\u134d \u1230\u120c\u12f3 \u12f0\u1265\u1245" @@ -2634,7 +2634,7 @@ "message": "\u1208\u121a\u12a8\u1270\u1208\u12cd \u12a5\u122d\u121b\u1276\u127d\u1295 \u127d\u120b \u1260\u120d" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u12a5\u122d\u121b\u1271\u1295 \u127d\u120b \u1260\u120d" }, "il_heb_settings_page": { "message": "\u12e8\u12a5\u1265\u122b\u12ed\u1235\u1325 \u1241\u120d\u134d \u1230\u120c\u12f3 \u1245\u1295\u1265\u122e\u127d \u1308\u133d" @@ -3300,7 +3300,7 @@ "message": "\u12f5\u121d\u1345" }, "voice_privacy_info": { - "message": "\u12e8\u12a5\u122d\u1235\u12ce \u12f5\u121d\u133d \u133d\u1211\u134d \u12a5\u1295\u12f2\u12eb\u12cd\u1245 \u12c8\u12f0 \u12a0\u1295\u12f5 \u12e8Google \u12a0\u1308\u120d\u130b\u12ed \u12ed\u120b\u12ab\u120d" + "message": "\u133d\u1211\u134d\u1295 \u1208\u12ed\u1276 \u1208\u121b\u12c8\u1245 \u1232\u1263\u120d \u12e8\u12a5\u122d\u1235\u12ce \u12e8\u12f5\u121d\u133d \u130d\u1264\u1275 \u12c8\u12f0 \u12e8Google \u12a0\u1308\u120d\u130b\u12ee\u127d \u12ed\u120b\u12ab\u120d" }, "voice_turn_off": { "message": "\u12e8\u12f5\u121d\u1345 \u130d\u1264\u1275 \u1218\u1223\u122a\u12eb\u1295 \u12a0\u1325\u134b"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ar/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ar/messages.json index 1d74865..382ce7e 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ar/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ar/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u0639\u0630\u0631\u064b\u0627\u060c \u0644\u0627 \u064a\u0645\u0643\u0646\u0643 \u0627\u0644\u0643\u062a\u0627\u0628\u0629 \u064a\u062f\u0648\u064a\u064b\u0627 \u0641\u0627\u0644\u0634\u0628\u0643\u0629 \u063a\u064a\u0631 \u0645\u062a\u0648\u0641\u0631\u0629." }, "handwriting_privacy_info": { - "message": "\u200f\u0633\u064a\u062a\u0645 \u0625\u0631\u0633\u0627\u0644 \u0625\u062f\u062e\u0627\u0644\u0643 \u0625\u0644\u0649 \u062e\u0627\u062f\u0645 Google \u0644\u0644\u062a\u0639\u0631\u0651\u0641 \u0639\u0644\u0649 \u0627\u0644\u0646\u0635" + "message": "\u200f\u0633\u064a\u062a\u0645 \u0625\u0631\u0633\u0627\u0644 \u0625\u062f\u062e\u0627\u0644\u0643 \u0625\u0644\u0649 \u062e\u0648\u0627\u062f\u0645 Google \u0644\u0644\u062a\u0639\u0631\u0651\u0641 \u0639\u0644\u0649 \u0627\u0644\u0646\u0635." }, "hide_keyboard": { "message": "\u0625\u062e\u0641\u0627\u0621 \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d" @@ -2634,7 +2634,7 @@ "message": "\u062a\u062c\u0627\u0647\u0644 \u062a\u0635\u062d\u064a\u062d \u0644\u0640" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u062a\u062c\u0627\u0647\u0644 \u0627\u0644\u062a\u0635\u062d\u064a\u062d" }, "il_heb_settings_page": { "message": "\u0635\u0641\u062d\u0629 \u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0627\u0644\u0639\u0628\u0631\u064a\u0629" @@ -3300,7 +3300,7 @@ "message": "\u0627\u0644\u0635\u0648\u062a" }, "voice_privacy_info": { - "message": "\u200f\u0633\u064a\u062a\u0645 \u0625\u0631\u0633\u0627\u0644 \u0635\u0648\u062a\u0643 \u0625\u0644\u0649 \u062e\u0627\u062f\u0645 Google \u0644\u0644\u062a\u0639\u0631\u0641 \u0639\u0644\u0649 \u0627\u0644\u0646\u0635" + "message": "\u200f\u0633\u064a\u062a\u0645 \u0625\u0631\u0633\u0627\u0644 \u0625\u062f\u062e\u0627\u0644\u0643 \u0627\u0644\u0635\u0648\u062a\u064a \u0625\u0644\u0649 \u062e\u0648\u0627\u062f\u0645 Google \u0644\u0644\u062a\u0639\u0631\u0651\u0641 \u0639\u0644\u0649 \u0627\u0644\u0646\u0635." }, "voice_turn_off": { "message": "\u0625\u064a\u0642\u0627\u0641 \u0623\u062f\u0627\u0629 \u0627\u0644\u0625\u062f\u062e\u0627\u0644 \u0627\u0644\u0635\u0648\u062a\u064a"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/bg/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/bg/messages.json index 0f94f84..3d2b772d 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/bg/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/bg/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u0417\u0430 \u0441\u044a\u0436\u0430\u043b\u0435\u043d\u0438\u0435 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0437\u0430 \u0440\u044a\u043a\u043e\u043f\u0438\u0441, \u0437\u0430\u0449\u043e\u0442\u043e \u043d\u044f\u043c\u0430 \u0434\u043e\u0441\u0442\u044a\u043f \u0434\u043e \u043c\u0440\u0435\u0436\u0430\u0442\u0430." }, "handwriting_privacy_info": { - "message": "\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u043e\u0442\u043e \u043e\u0442 \u0432\u0430\u0441 \u0449\u0435 \u0431\u044a\u0434\u0435 \u0438\u0437\u043f\u0440\u0430\u0442\u0435\u043d\u043e \u0434\u043e \u0441\u044a\u0440\u0432\u044a\u0440 \u043d\u0430 Google \u0441 \u0446\u0435\u043b \u0440\u0430\u0437\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u0442\u0435\u043a\u0441\u0442\u0430" + "message": "\u0412\u044a\u0432\u0435\u0434\u0435\u043d\u0438\u044f\u0442 \u043e\u0442 \u0432\u0430\u0441 \u0442\u0435\u043a\u0441\u0442 \u0449\u0435 \u0431\u044a\u0434\u0435 \u0438\u0437\u043f\u0440\u0430\u0442\u0435\u043d \u0434\u043e \u0441\u044a\u0440\u0432\u044a\u0440\u0438\u0442\u0435 \u043d\u0430 Google \u0441 \u0446\u0435\u043b \u0440\u0430\u0437\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0435." }, "hide_keyboard": { "message": "\u0441\u043a\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430\u0442\u0430" @@ -2634,7 +2634,7 @@ "message": "\u041f\u0440\u0435\u043d\u0435\u0431\u0440\u0435\u0433\u0432\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u0440\u0435\u043a\u0446\u0438\u044f\u0442\u0430 \u0437\u0430" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u041f\u0440\u0435\u043d\u0435\u0431\u0440\u0435\u0433\u0432\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u0440\u0435\u043a\u0446\u0438\u044f\u0442\u0430" }, "il_heb_settings_page": { "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0437\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430\u0442\u0430 \u043d\u0430 \u0438\u0432\u0440\u0438\u0442" @@ -3300,7 +3300,7 @@ "message": "\u0413\u043b\u0430\u0441" }, "voice_privacy_info": { - "message": "\u0413\u043b\u0430\u0441\u044a\u0442 \u0432\u0438 \u0449\u0435 \u0431\u044a\u0434\u0435 \u0438\u0437\u043f\u0440\u0430\u0442\u0435\u043d \u0434\u043e \u0441\u044a\u0440\u0432\u044a\u0440 \u043d\u0430 Google \u0441 \u0446\u0435\u043b \u0440\u0430\u0437\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u0442\u0435\u043a\u0441\u0442" + "message": "\u0412\u044a\u0432\u0435\u0434\u0435\u043d\u0438\u044f\u0442 \u0447\u0440\u0435\u0437 \u0433\u043b\u0430\u0441\u0430 \u0432\u0438 \u0442\u0435\u043a\u0441\u0442 \u0449\u0435 \u0431\u044a\u0434\u0435 \u0438\u0437\u043f\u0440\u0430\u0442\u0435\u043d \u0434\u043e \u0441\u044a\u0440\u0432\u044a\u0440\u0438\u0442\u0435 \u043d\u0430 Google \u0441 \u0446\u0435\u043b \u0440\u0430\u0437\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0435." }, "voice_turn_off": { "message": "\u0438\u0437\u043a\u043b\u044e\u0447\u0432\u0430\u043d\u0435 \u043d\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0437\u0430 \u0433\u043b\u0430\u0441\u043e\u0432\u043e \u0432\u044a\u0432\u0435\u0436\u0434\u0430\u043d\u0435"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/bn/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/bn/messages.json index dbe01582..b8b676e 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/bn/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/bn/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u09a6\u09c1\u0983\u0996\u09bf\u09a4, \u09a8\u09c7\u099f\u0993\u09af\u09bc\u09be\u09b0\u09cd\u0995 \u0985\u09a8\u09c1\u09aa\u09b2\u09ac\u09cd\u09a7 \u09a5\u09be\u0995\u09be\u09b0 \u0995\u09be\u09b0\u09a3\u09c7 \u0986\u09aa\u09a8\u09bf \u09b9\u09b8\u09cd\u09a4\u09be\u0995\u09cd\u09b7\u09b0 \u09ac\u09cd\u09af\u09ac\u09b9\u09be\u09b0 \u0995\u09b0\u09a4\u09c7 \u09aa\u09be\u09b0\u09ac\u09c7\u09a8 \u09a8\u09be\u09f7" }, "handwriting_privacy_info": { - "message": "\u09aa\u09be\u09a0\u09cd\u09af \u09b8\u09a8\u09be\u0995\u09cd\u09a4 \u0995\u09b0\u09a4\u09c7 \u0986\u09aa\u09a8\u09be\u09b0 \u0987\u09a8\u09aa\u09c1\u099f Google \u09b8\u09be\u09b0\u09cd\u09ad\u09be\u09b0\u09c7 \u09aa\u09be\u09a0\u09be\u09a8\u09cb \u09b9\u09ac\u09c7" + "message": "\u09aa\u09be\u09a0\u09cd\u09af \u09b8\u09a8\u09be\u0995\u09cd\u09a4 \u0995\u09b0\u09a4\u09c7 \u0986\u09aa\u09a8\u09be\u09b0 \u0987\u09a8\u09aa\u09c1\u099f Google \u09b8\u09be\u09b0\u09cd\u09ad\u09be\u09b0\u0997\u09c1\u09b2\u09bf\u09a4\u09c7 \u09aa\u09be\u09a0\u09be\u09a8\u09cb \u09b9\u09ac\u09c7\u09f7" }, "hide_keyboard": { "message": "\u0995\u09c0\u09ac\u09cb\u09b0\u09cd\u09a1 \u09b2\u09c1\u0995\u09be\u09a8" @@ -2634,7 +2634,7 @@ "message": "\u098f\u09b0 \u099c\u09a8\u09cd\u09af \u0995\u09b0\u09be \u09b8\u0982\u09b6\u09cb\u09a7\u09a8 \u0989\u09aa\u09c7\u0995\u09cd\u09b7\u09be \u0995\u09b0\u09c1\u09a8" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u09b8\u0982\u09b6\u09cb\u09a7\u09a8 \u0989\u09aa\u09c7\u0995\u09cd\u09b7\u09be \u0995\u09b0\u09c1\u09a8" }, "il_heb_settings_page": { "message": "\u09b9\u09bf\u09ac\u09cd\u09b0\u09c1 \u0995\u09c0\u09ac\u09cb\u09b0\u09cd\u09a1 \u09b8\u09c7\u099f\u09bf\u0982\u09b8 \u09aa\u09c3\u09b7\u09cd\u09a0\u09be" @@ -3300,7 +3300,7 @@ "message": "\u09ad\u09df\u09c7\u09b8" }, "voice_privacy_info": { - "message": "\u09aa\u09be\u09a0\u09cd\u09af \u09b6\u09a8\u09be\u0995\u09cd\u09a4 \u0995\u09b0\u09a4\u09c7 \u0986\u09aa\u09a8\u09be\u09b0 \u09ad\u09df\u09c7\u09b8 Google \u09b8\u09be\u09b0\u09cd\u09ad\u09be\u09b0\u09c7 \u09aa\u09be\u09a0\u09be\u09a8\u09cb \u09b9\u09ac\u09c7" + "message": "\u09aa\u09be\u09a0\u09cd\u09af \u09b8\u09a8\u09be\u0995\u09cd\u09a4 \u0995\u09b0\u09a4\u09c7 \u0986\u09aa\u09a8\u09be\u09b0 \u09ad\u09df\u09c7\u09b8 \u0987\u09a8\u09aa\u09c1\u099f Google \u09b8\u09be\u09b0\u09cd\u09ad\u09be\u09b0\u0997\u09c1\u09b2\u09bf\u09a4\u09c7 \u09aa\u09be\u09a0\u09be\u09a8\u09cb \u09b9\u09ac\u09c7\u09f7" }, "voice_turn_off": { "message": "\u09ad\u09df\u09c7\u09b8 \u0987\u09a8\u09aa\u09c1\u099f \u09b8\u09b0\u099e\u09cd\u099c\u09be\u09ae \u09ac\u09a8\u09cd\u09a7 \u0995\u09b0\u09c1\u09a8"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ca/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ca/messages.json index 09a064b..1815a3d6 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ca/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ca/messages.json
@@ -2616,7 +2616,7 @@ "message": "No podeu fer servir l'escriptura a m\u00e0 perqu\u00e8 la xarxa no est\u00e0 disponible." }, "handwriting_privacy_info": { - "message": "El text que introdu\u00efu s'enviar\u00e0 a un servidor de Google per recon\u00e8ixer el text." + "message": "El text que escriviu s'enviar\u00e0 als servidors de Google per poder recon\u00e8ixer-lo." }, "hide_keyboard": { "message": "amaga el teclat" @@ -2634,7 +2634,7 @@ "message": "Ignora la correcci\u00f3 de" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignora la correcci\u00f3" }, "il_heb_settings_page": { "message": "P\u00e0gina de configuraci\u00f3 del teclat hebreu" @@ -3300,7 +3300,7 @@ "message": "Veu" }, "voice_privacy_info": { - "message": "La vostra veu s'enviar\u00e0 a un servidor de Google perqu\u00e8 en reconegui el text." + "message": "El text que digueu s'enviar\u00e0 als servidors de Google per poder recon\u00e8ixer-lo." }, "voice_turn_off": { "message": "desactiva l'eina d'entrada de veu"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/cs/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/cs/messages.json index e709c9d7..0057247 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/cs/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/cs/messages.json
@@ -2616,7 +2616,7 @@ "message": "Je n\u00e1m l\u00edto, psan\u00ed rukou nelze pou\u017e\u00edt, proto\u017ee s\u00ed\u0165 nen\u00ed k dispozici." }, "handwriting_privacy_info": { - "message": "Zad\u00e1n\u00ed bude za \u00fa\u010delem rozpozn\u00e1n\u00ed textu odesl\u00e1no na server Google" + "message": "Zad\u00e1n\u00ed bude za \u00fa\u010delem rozpozn\u00e1n\u00ed textu odesl\u00e1no na servery Google." }, "hide_keyboard": { "message": "skr\u00fdt kl\u00e1vesnici" @@ -2634,7 +2634,7 @@ "message": "Ignorovat opravu pro" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignorovat opravu" }, "il_heb_settings_page": { "message": "Str\u00e1nka nastaven\u00ed hebrejsk\u00e9 kl\u00e1vesnice" @@ -3300,7 +3300,7 @@ "message": "Hlas" }, "voice_privacy_info": { - "message": "V\u00e1\u0161 hlas bude za \u00fa\u010delem rozpozn\u00e1n\u00ed textu odesl\u00e1n na server Google." + "message": "Hlasov\u00e9 zad\u00e1n\u00ed bude za \u00fa\u010delem rozpozn\u00e1n\u00ed textu odesl\u00e1no na servery Google." }, "voice_turn_off": { "message": "vypnout n\u00e1stroj pro hlasov\u00fd vstup"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/da/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/da/messages.json index 2db1bd2..f0a8f4f 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/da/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/da/messages.json
@@ -2616,7 +2616,7 @@ "message": "Du kan desv\u00e6rre ikke bruge h\u00e5ndskrift, da netv\u00e6rket ikke er tilg\u00e6ngeligt." }, "handwriting_privacy_info": { - "message": "Din indtastning bliver sendt til en Google-server, som sikrer tekstgenkendelse" + "message": "Dit input bliver sendt til Google-servere, som udf\u00f8rer tekstgenkendelse." }, "hide_keyboard": { "message": "skjul tastaturet" @@ -2634,7 +2634,7 @@ "message": "Ignorer rettelsen af" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignorer rettelsen" }, "il_heb_settings_page": { "message": "Side med indstillinger for hebraisk tastatur" @@ -3300,7 +3300,7 @@ "message": "Tale" }, "voice_privacy_info": { - "message": "Din stemme bliver sendt til en Google-server, som sikrer tekstgenkendelse" + "message": "Dit taleinput bliver sendt til Google-servere, som udf\u00f8rer tekstgenkendelse." }, "voice_turn_off": { "message": "deaktiver v\u00e6rkt\u00f8j til taleinput"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/de/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/de/messages.json index b7245b5..32dee7e 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/de/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/de/messages.json
@@ -2616,7 +2616,7 @@ "message": "Sie k\u00f6nnen Handschrift nicht verwenden, da kein Netzwerk verf\u00fcgbar ist." }, "handwriting_privacy_info": { - "message": "Ihre Eingabe wird zwecks Texterkennung an einen Google-Server gesendet." + "message": "Ihre Eingabe wird zwecks Texterkennung an die Google-Server gesendet." }, "hide_keyboard": { "message": "Tastatur ausblenden" @@ -2634,7 +2634,7 @@ "message": "Korrektur ignorieren f\u00fcr" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Korrektur ignorieren" }, "il_heb_settings_page": { "message": "Seite mit Einstellungen f\u00fcr hebr\u00e4ische Tastatur" @@ -3300,7 +3300,7 @@ "message": "Spracheingabe" }, "voice_privacy_info": { - "message": "Ihre Spracheingabe wird zur Spracherkennung an einen Google-Server gesendet." + "message": "Ihre Spracheingabe wird zwecks Texterkennung an die Google-Server gesendet." }, "voice_turn_off": { "message": "Spracheingabetool deaktivieren"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/el/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/el/messages.json index 53dbfb72..d6bdab9 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/el/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/el/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u0394\u03c5\u03c3\u03c4\u03c5\u03c7\u03ce\u03c2, \u03b4\u03b5\u03bd \u03bc\u03c0\u03bf\u03c1\u03b5\u03af\u03c4\u03b5 \u03bd\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c4\u03b7 \u03b3\u03c1\u03b1\u03c6\u03ae, \u03b5\u03c0\u03b5\u03b9\u03b4\u03ae \u03c4\u03bf \u03b4\u03af\u03ba\u03c4\u03c5\u03bf \u03b4\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03b9\u03b1\u03b8\u03ad\u03c3\u03b9\u03bc\u03bf." }, "handwriting_privacy_info": { - "message": "\u03a4\u03b1 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1 \u03c0\u03bf\u03c5 \u03b5\u03b9\u03c3\u03b1\u03b3\u03ac\u03b3\u03b5\u03c4\u03b5 \u03b8\u03b1 \u03b1\u03c0\u03bf\u03c3\u03c4\u03b1\u03bb\u03bf\u03cd\u03bd \u03c3\u03b5 \u03ad\u03bd\u03b1\u03bd \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae \u03c4\u03b7\u03c2 Google \u03b3\u03b9\u03b1 \u03c4\u03b7\u03bd \u03b1\u03bd\u03b1\u03b3\u03bd\u03ce\u03c1\u03b9\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5" + "message": "\u0397 \u03b5\u03af\u03c3\u03bf\u03b4\u03cc\u03c2 \u03c3\u03b1\u03c2 \u03b8\u03b1 \u03b1\u03c0\u03bf\u03c3\u03c4\u03b1\u03bb\u03b5\u03af \u03c3\u03c4\u03bf\u03c5\u03c2 \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ad\u03c2 \u03c4\u03b7\u03c2 Google \u03b3\u03b9\u03b1 \u03b1\u03bd\u03b1\u03b3\u03bd\u03ce\u03c1\u03b9\u03c3\u03b7 \u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5." }, "hide_keyboard": { "message": "\u03b1\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u03c0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03bf\u03b3\u03af\u03bf\u03c5" @@ -2634,7 +2634,7 @@ "message": "\u03a0\u03b1\u03c1\u03ac\u03b2\u03bb\u03b5\u03c8\u03b7 \u03b4\u03b9\u03cc\u03c1\u03b8\u03c9\u03c3\u03b7\u03c2 \u03b3\u03b9\u03b1" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u03a0\u03b1\u03c1\u03ac\u03b2\u03bb\u03b5\u03c8\u03b7 \u03b4\u03b9\u03cc\u03c1\u03b8\u03c9\u03c3\u03b7\u03c2" }, "il_heb_settings_page": { "message": "\u03a3\u03b5\u03bb\u03af\u03b4\u03b1 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c9\u03bd \u03c0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03bf\u03b3\u03af\u03bf\u03c5 \u03b5\u03b2\u03c1\u03b1\u03ca\u03ba\u03ce\u03bd \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03c9\u03bd" @@ -3300,7 +3300,7 @@ "message": "\u03a6\u03c9\u03bd\u03ae" }, "voice_privacy_info": { - "message": "\u0397 \u03c6\u03c9\u03bd\u03b7\u03c4\u03b9\u03ba\u03ae \u03b5\u03af\u03c3\u03bf\u03b4\u03cc\u03c2 \u03c3\u03b1\u03c2 \u03b8\u03b1 \u03b1\u03c0\u03bf\u03c3\u03c4\u03b1\u03bb\u03b5\u03af \u03c3\u03b5 \u03ad\u03bd\u03b1\u03bd \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae \u03c4\u03b7\u03c2 Google \u03b3\u03b9\u03b1 \u03b1\u03bd\u03b1\u03b3\u03bd\u03ce\u03c1\u03b9\u03c3\u03b7 \u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5" + "message": "\u0397 \u03c6\u03c9\u03bd\u03b7\u03c4\u03b9\u03ba\u03ae \u03b5\u03af\u03c3\u03bf\u03b4\u03cc\u03c2 \u03c3\u03b1\u03c2 \u03b8\u03b1 \u03b1\u03c0\u03bf\u03c3\u03c4\u03b1\u03bb\u03b5\u03af \u03c3\u03c4\u03bf\u03c5\u03c2 \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ad\u03c2 \u03c4\u03b7\u03c2 Google \u03b3\u03b9\u03b1 \u03b1\u03bd\u03b1\u03b3\u03bd\u03ce\u03c1\u03b9\u03c3\u03b7 \u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5." }, "voice_turn_off": { "message": "\u03b1\u03c0\u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03b5\u03c1\u03b3\u03b1\u03bb\u03b5\u03af\u03bf\u03c5 \u03c6\u03c9\u03bd\u03b7\u03c4\u03b9\u03ba\u03ce\u03bd \u03b5\u03bd\u03c4\u03bf\u03bb\u03ce\u03bd"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/en/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/en/messages.json index 04ec569..feeeb0c1 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/en/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/en/messages.json
@@ -2616,7 +2616,7 @@ "message": "Sorry, you can not use handwriting, because network is unavailable." }, "handwriting_privacy_info": { - "message": "Your input will be sent to a Google server to recognize text" + "message": "Your input will be sent to Google servers to recognize text." }, "hide_keyboard": { "message": "hide keyboard" @@ -3300,7 +3300,7 @@ "message": "Voice" }, "voice_privacy_info": { - "message": "Your voice will be sent to a Google server to recognize text" + "message": "Your voice input will be sent to Google servers to recognize text." }, "voice_turn_off": { "message": "turn off voice input tool"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/en_GB/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/en_GB/messages.json index d0437a5..f09f6a8 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/en_GB/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/en_GB/messages.json
@@ -2616,7 +2616,7 @@ "message": "Sorry, you cannot use handwriting, because network is unavailable." }, "handwriting_privacy_info": { - "message": "Your input will be sent to a Google server to recognise text" + "message": "Your input will be sent to Google servers to recognise text." }, "hide_keyboard": { "message": "hide keyboard" @@ -3300,7 +3300,7 @@ "message": "Voice" }, "voice_privacy_info": { - "message": "Your voice will be sent to a Google server to recognise text" + "message": "Your voice input will be sent to Google servers to recognise text." }, "voice_turn_off": { "message": "turn off voice input tool"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/es/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/es/messages.json index a8969a8f..565bccf 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/es/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/es/messages.json
@@ -2616,7 +2616,7 @@ "message": "No se puede utilizar la escritura t\u00e1ctil porque la red no est\u00e1 disponible." }, "handwriting_privacy_info": { - "message": "Tu entrada se enviar\u00e1 a un servidor de Google para reconocer el texto" + "message": "Tu entrada se enviar\u00e1 a los servidores de Google para reconocer el texto." }, "hide_keyboard": { "message": "ocultar teclado" @@ -2634,7 +2634,7 @@ "message": "Ignorar correcci\u00f3n de" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignorar correcci\u00f3n" }, "il_heb_settings_page": { "message": "P\u00e1gina de configuraci\u00f3n del teclado hebreo" @@ -3300,7 +3300,7 @@ "message": "Voz" }, "voice_privacy_info": { - "message": "Tu voz se enviar\u00e1 a un servidor de Google para reconocer el texto" + "message": "Tu entrada de voz se enviar\u00e1 a los servidores de Google para reconocer el texto." }, "voice_turn_off": { "message": "desactivar herramienta de entrada de voz"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/es_419/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/es_419/messages.json index 72a688ea..dc6be3c 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/es_419/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/es_419/messages.json
@@ -2616,7 +2616,7 @@ "message": "No puedes usar escritura a mano porque la red no est\u00e1 disponible." }, "handwriting_privacy_info": { - "message": "La entrada se enviar\u00e1 a un servidor de Google para que reconozca el texto." + "message": "La entrada se enviar\u00e1 a los servidores de Google para que reconozcan el texto." }, "hide_keyboard": { "message": "ocultar teclado" @@ -2634,7 +2634,7 @@ "message": "Ignorar correcci\u00f3n de" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignorar correcci\u00f3n" }, "il_heb_settings_page": { "message": "P\u00e1gina de configuraci\u00f3n del teclado hebreo" @@ -3300,7 +3300,7 @@ "message": "Voz" }, "voice_privacy_info": { - "message": "Tu voz se enviar\u00e1 a un servidor de Google para reconocer el texto." + "message": "La entrada de voz se enviar\u00e1 a los servidores de Google para que reconozcan el texto." }, "voice_turn_off": { "message": "desactivar la herramienta de entrada de voz"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/et/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/et/messages.json index 9a30785..0489223 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/et/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/et/messages.json
@@ -2616,7 +2616,7 @@ "message": "Kahjuks ei saa te k\u00e4sitsi kirjutamist kasutada, kuna v\u00f5rk pole saadaval." }, "handwriting_privacy_info": { - "message": "Teie sisend saadetakse Google'i serveritesse teksti tuvastamiseks" + "message": "Teie sisestus saadetakse teksti tuvastamiseks Google'i serveritesse." }, "hide_keyboard": { "message": "klaviatuuri peitmine" @@ -2634,7 +2634,7 @@ "message": "Ignoreeri parandust:" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignoreeri parandust" }, "il_heb_settings_page": { "message": "Heebrea klaviatuuri seadete leht" @@ -3300,7 +3300,7 @@ "message": "H\u00e4\u00e4l" }, "voice_privacy_info": { - "message": "Teie h\u00e4\u00e4landmed saadetakse teksti tuvastamiseks Google'i serverisse." + "message": "Teie h\u00e4\u00e4lsisend saadetakse teksti tuvastamiseks Google'i serveritesse." }, "voice_turn_off": { "message": "h\u00e4\u00e4lsisendi t\u00f6\u00f6riista v\u00e4ljal\u00fclitamine"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fa/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fa/messages.json index dc3a1a2..df16602 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fa/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fa/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u0645\u062a\u0623\u0633\u0641\u06cc\u0645\u060c \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0627\u0632 \u062f\u0633\u062a\u200c\u062e\u0637 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u06a9\u0646\u06cc\u062f\u060c \u0632\u06cc\u0631\u0627 \u062f\u0633\u062a\u0631\u0633\u06cc \u0628\u0647 \u0634\u0628\u06a9\u0647 \u0645\u0645\u06a9\u0646 \u0646\u06cc\u0633\u062a." }, "handwriting_privacy_info": { - "message": "\u200f\u0648\u0631\u0648\u062f\u06cc \u0634\u0645\u0627 \u0628\u0647 \u06cc\u06a9\u06cc \u0627\u0632 \u0633\u0631\u0648\u0631\u0647\u0627\u06cc Google \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc\u200c\u0634\u0648\u062f \u062a\u0627 \u0646\u0648\u0634\u062a\u0627\u0631 \u0631\u0627 \u062a\u0634\u062e\u06cc\u0635 \u062f\u0647\u062f" + "message": "\u200f\u0648\u0631\u0648\u062f\u06cc \u0634\u0645\u0627 \u0628\u0647 \u0633\u0631\u0648\u0631\u0647\u0627\u06cc Google \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc\u200c\u0634\u0648\u062f \u062a\u0627 \u0646\u0648\u0634\u062a\u0627\u0631 \u0631\u0627 \u062a\u0634\u062e\u06cc\u0635 \u062f\u0647\u0646\u062f." }, "hide_keyboard": { "message": "\u067e\u0646\u0647\u0627\u0646 \u06a9\u0631\u062f\u0646 \u0635\u0641\u062d\u0647\u200c\u06a9\u0644\u06cc\u062f" @@ -2634,7 +2634,7 @@ "message": "\u0646\u0627\u062f\u06cc\u062f\u0647 \u06af\u0631\u0641\u062a\u0646 \u062a\u0635\u062d\u06cc\u062d \u0628\u0631\u0627\u06cc" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u0646\u0627\u062f\u06cc\u062f\u0647 \u06af\u0631\u0641\u062a\u0646 \u062a\u0635\u062d\u06cc\u062d" }, "il_heb_settings_page": { "message": "\u0635\u0641\u062d\u0647 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0635\u0641\u062d\u0647\u200c\u06a9\u0644\u06cc\u062f \u0639\u0628\u0631\u06cc" @@ -3300,7 +3300,7 @@ "message": "\u0635\u062f\u0627" }, "voice_privacy_info": { - "message": "\u200f\u0628\u0631\u0627\u06cc \u062a\u0634\u062e\u06cc\u0635 \u0646\u0648\u0634\u062a\u0627\u0631\u060c \u0635\u062f\u0627\u06cc \u0634\u0645\u0627 \u0628\u0647 \u06cc\u06a9\u06cc \u0627\u0632 \u0633\u0631\u0648\u0631\u0647\u0627\u06cc Google \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc\u200c\u0634\u0648\u062f" + "message": "\u200f\u0648\u0631\u0648\u062f\u06cc \u0635\u0648\u062a\u06cc \u0634\u0645\u0627 \u0628\u0647 \u0633\u0631\u0648\u0631\u0647\u0627\u06cc Google \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc\u200c\u0634\u0648\u062f \u062a\u0627 \u0646\u0648\u0634\u062a\u0627\u0631 \u0631\u0627 \u062a\u0634\u062e\u06cc\u0635 \u062f\u0647\u0646\u062f." }, "voice_turn_off": { "message": "\u062e\u0627\u0645\u0648\u0634 \u06a9\u0631\u062f\u0646 \u0627\u0628\u0632\u0627\u0631\u0647\u0627\u06cc \u0648\u0631\u0648\u062f\u06cc \u06af\u0641\u062a\u0627\u0631\u06cc"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fi/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fi/messages.json index ea73a4ba..2d9bdfc 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fi/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fi/messages.json
@@ -2616,7 +2616,7 @@ "message": "Et voi k\u00e4ytt\u00e4\u00e4 k\u00e4sinkirjoitusta, koska verkko ei ole k\u00e4ytett\u00e4viss\u00e4." }, "handwriting_privacy_info": { - "message": "Sy\u00f6tt\u00e4m\u00e4si teksti tunnistetaan Googlen palvelimella" + "message": "Sy\u00f6tteesi l\u00e4hetet\u00e4\u00e4n Googlen palvelimille, jotta teksti voidaan tunnistaa." }, "hide_keyboard": { "message": "piilota n\u00e4pp\u00e4imist\u00f6" @@ -2634,7 +2634,7 @@ "message": "\u00c4l\u00e4 korjaa:" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ohita korjaus" }, "il_heb_settings_page": { "message": "Hepreankielisen n\u00e4pp\u00e4imist\u00f6n asetukset" @@ -3300,7 +3300,7 @@ "message": "Puhe" }, "voice_privacy_info": { - "message": "Googlen palvelimelle l\u00e4hetet\u00e4\u00e4n \u00e4\u00e4nt\u00e4si, jotta teksti voidaan tunnistaa" + "message": "\u00c4\u00e4nisy\u00f6tteesi l\u00e4hetet\u00e4\u00e4n Googlen palvelimille, jotta teksti voidaan tunnistaa." }, "voice_turn_off": { "message": "poista \u00e4\u00e4nisy\u00f6tety\u00f6kalu k\u00e4yt\u00f6st\u00e4"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fil/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fil/messages.json index 8f6d111..9213c65 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fil/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fil/messages.json
@@ -2616,7 +2616,7 @@ "message": "Paumanhin, hindi mo magagamit ang sulatkamay, dahil hindi available ang network." }, "handwriting_privacy_info": { - "message": "Ipapadala ang iyong input sa isang Google server upang makilala ang text" + "message": "Ipapadala sa mga server ng Google ang input mo upang matukoy ang text." }, "hide_keyboard": { "message": "itago ang keyboard" @@ -2634,7 +2634,7 @@ "message": "Huwag pansinin ang pagwawasto para sa" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Balewalain ang pagwawasto" }, "il_heb_settings_page": { "message": "Page ng Mga Setting ng Hebrew na Keyboard" @@ -3300,7 +3300,7 @@ "message": "Boses" }, "voice_privacy_info": { - "message": "Ipapadala sa Google ang iyong boses upang makakilala ng text" + "message": "Ipapadala sa mga server ng Google ang voice input mo upang matukoy ang text." }, "voice_turn_off": { "message": "i-off ang voice input tool"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fr/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fr/messages.json index 989a421..8f475580 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fr/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fr/messages.json
@@ -2616,7 +2616,7 @@ "message": "Impossible d'utiliser l'\u00e9criture manuscrite, car le r\u00e9seau est indisponible." }, "handwriting_privacy_info": { - "message": "Votre saisie sera envoy\u00e9e \u00e0 un serveur de Google dans le cadre de la reconnaissance textuelle." + "message": "Votre saisie sera envoy\u00e9e aux serveurs de Google dans le cadre de la reconnaissance textuelle." }, "hide_keyboard": { "message": "masquer le clavier" @@ -2634,7 +2634,7 @@ "message": "Ignorer la correction pour" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignorer la correction" }, "il_heb_settings_page": { "message": "Page des param\u00e8tres du clavier h\u00e9breu" @@ -3300,7 +3300,7 @@ "message": "Voix" }, "voice_privacy_info": { - "message": "Votre voix sera envoy\u00e9e \u00e0 un serveur de Google dans le cadre de la reconnaissance textuelle." + "message": "Votre saisie vocale sera envoy\u00e9e aux serveurs de Google dans le cadre de la reconnaissance textuelle." }, "voice_turn_off": { "message": "d\u00e9sactiver l'outil de saisie vocale"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/gu/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/gu/messages.json index 01f5eb01..46bb238 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/gu/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/gu/messages.json
@@ -1500,10 +1500,10 @@ "message": "\u0aa6\u0ab8\u0acd\u0aa4\u0abe\u0ab5\u0ac7\u0a9c" }, "d83d_dcc5": { - "message": "\u0a95\u0ac5\u0ab2\u0ac7\u0aa8\u0acd\u0aa1\u0ab0" + "message": "\u0a95\u0ac7\u0ab2\u0ac7\u0aa8\u0acd\u0aa1\u0ab0" }, "d83d_dcc6": { - "message": "\u0a9f\u0ac0\u0a85\u0ab0-\u0a91\u0aab \u0a95\u0ac5\u0ab2\u0ac7\u0aa8\u0acd\u0aa1\u0ab0" + "message": "\u0a9f\u0ac0\u0a85\u0ab0-\u0a91\u0aab \u0a95\u0ac7\u0ab2\u0ac7\u0aa8\u0acd\u0aa1\u0ab0" }, "d83d_dcc7": { "message": "\u0a95\u0abe\u0ab0\u0acd\u0aa1 \u0a85\u0aa8\u0ac1\u0a95\u0acd\u0ab0\u0aae\u0aa3\u0abf\u0a95\u0abe" @@ -2526,28 +2526,28 @@ "message": "\u0a8f\u0ab8\u0acd\u0a9f\u0acb\u0aa8\u0abf\u0aaf\u0aa8 \u0a95\u0ac0\u0aac\u0acb\u0ab0\u0acd\u0aa1 \u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8 \u0aaa\u0ac3\u0ab7\u0acd\u0aa0" }, "emoji_tab_emoticon": { - "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac5\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0a87\u0aae\u0acb\u0a9f\u0abf\u0a95\u0aa8" + "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac7\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0a87\u0aae\u0acb\u0a9f\u0abf\u0a95\u0aa8" }, "emoji_tab_face": { - "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac5\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0a9a\u0ab9\u0ac7\u0ab0\u0acb" + "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac7\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0a9a\u0ab9\u0ac7\u0ab0\u0acb" }, "emoji_tab_hot": { - "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac5\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0a9a\u0ab0\u0acd\u0a9a\u0abe\u0aae\u0abe\u0a82" + "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac7\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0a9a\u0ab0\u0acd\u0a9a\u0abe\u0aae\u0abe\u0a82" }, "emoji_tab_nature": { - "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac5\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0aaa\u0acd\u0ab0\u0a95\u0ac3\u0aa4\u0abf" + "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac7\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0aaa\u0acd\u0ab0\u0a95\u0ac3\u0aa4\u0abf" }, "emoji_tab_object": { - "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac5\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0a91\u0aac\u0acd\u0a9c\u0ac7\u0a95\u0acd\u0a9f" + "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac7\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0a91\u0aac\u0acd\u0a9c\u0ac7\u0a95\u0acd\u0a9f" }, "emoji_tab_place": { - "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac5\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0ab8\u0acd\u0aa5\u0abe\u0aa8" + "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac7\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0ab8\u0acd\u0aa5\u0abe\u0aa8" }, "emoji_tab_recent": { - "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac5\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0aa4\u0abe\u0a9c\u0ac7\u0aa4\u0ab0\u0aa8\u0abe" + "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac7\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0aa4\u0abe\u0a9c\u0ac7\u0aa4\u0ab0\u0aa8\u0abe" }, "emoji_tab_symbol": { - "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac5\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0aaa\u0acd\u0ab0\u0aa4\u0ac0\u0a95" + "message": "\u0a87\u0aae\u0acb\u0a9c\u0ac0 \u0a95\u0ac7\u0a9f\u0ac7\u0a97\u0ab0\u0ac0 \u0aaa\u0acd\u0ab0\u0aa4\u0ac0\u0a95" }, "enable_capitalization": { "message": "\u0ab8\u0acd\u0ab5\u0aa4\u0a83-\u0a95\u0ac7\u0aaa\u0abf\u0a9f\u0ab2\u0abe\u0a87\u0a9d\u0ac7\u0ab6\u0aa8" @@ -2616,7 +2616,7 @@ "message": "\u0aae\u0abe\u0aab \u0a95\u0ab0\u0ab6\u0acb, \u0aa4\u0aae\u0ac7 \u0ab9\u0ab8\u0acd\u0aa4\u0abe\u0a95\u0acd\u0ab7\u0ab0\u0aa8\u0acb \u0a89\u0aaa\u0aaf\u0acb\u0a97 \u0a95\u0ab0\u0ac0 \u0ab6\u0a95\u0aa4\u0abe\u0a82 \u0aa8\u0aa5\u0ac0, \u0a95\u0abe\u0ab0\u0aa3 \u0a95\u0ac7 \u0aa8\u0ac7\u0a9f\u0ab5\u0ab0\u0acd\u0a95 \u0a85\u0aa8\u0ac1\u0aaa\u0ab2\u0aac\u0acd\u0aa7 \u0a9b\u0ac7." }, "handwriting_privacy_info": { - "message": "\u0a9f\u0ac7\u0a95\u0acd\u0ab8\u0acd\u0a9f \u0a93\u0ab3\u0a96\u0ab5\u0abe \u0aae\u0abe\u0a9f\u0ac7 \u0aa4\u0aae\u0abe\u0ab0\u0ac1\u0a82 \u0a87\u0aa8\u0aaa\u0ac1\u0a9f Google \u0ab8\u0ab0\u0acd\u0ab5\u0ab0\u0aa8\u0ac7 \u0aae\u0acb\u0a95\u0ab2\u0ab5\u0abe\u0aae\u0abe\u0a82 \u0a86\u0ab5\u0ab6\u0ac7" + "message": "\u0a9f\u0ac7\u0a95\u0acd\u0ab8\u0acd\u0a9f\u0aa8\u0ac7 \u0a93\u0ab3\u0a96\u0ab5\u0abe \u0aae\u0abe\u0a9f\u0ac7 \u0aa4\u0aae\u0abe\u0ab0\u0acb \u0a87\u0aa8\u0aaa\u0ac1\u0a9f Google \u0ab8\u0ab0\u0acd\u0ab5\u0ab0\u0acd\u0ab8\u0aa8\u0ac7 \u0aae\u0acb\u0a95\u0ab2\u0ab5\u0abe\u0aae\u0abe\u0a82 \u0a86\u0ab5\u0ab6\u0ac7." }, "hide_keyboard": { "message": "\u0a95\u0ac0\u0aac\u0acb\u0ab0\u0acd\u0aa1 \u0a9b\u0ac1\u0aaa\u0abe\u0ab5\u0acb" @@ -2634,7 +2634,7 @@ "message": "\u0a86 \u0aae\u0abe\u0a9f\u0ac7\u0aa8\u0abe \u0ab8\u0ac1\u0aa7\u0abe\u0ab0\u0aa8\u0ac7 \u0a85\u0ab5\u0a97\u0aa3\u0acb" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u0ab8\u0ac1\u0aa7\u0abe\u0ab0\u0aa8\u0ac7 \u0a85\u0ab5\u0a97\u0aa3\u0acb" }, "il_heb_settings_page": { "message": "\u0ab9\u0ac0\u0aac\u0acd\u0ab0\u0ac1 \u0a95\u0ac0\u0aac\u0acb\u0ab0\u0acd\u0aa1 \u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8 \u0aaa\u0ac3\u0ab7\u0acd\u0aa0" @@ -3300,7 +3300,7 @@ "message": "\u0ab5\u0ac9\u0a87\u0ab8" }, "voice_privacy_info": { - "message": "\u0a9f\u0ac7\u0a95\u0acd\u0ab8\u0acd\u0a9f\u0aa8\u0ac7 \u0a93\u0ab3\u0a96\u0ab5\u0abe \u0aae\u0abe\u0a9f\u0ac7 \u0aa4\u0aae\u0abe\u0ab0\u0acb \u0a85\u0ab5\u0abe\u0a9c Google \u0ab8\u0ab0\u0acd\u0ab5\u0ab0\u0aa8\u0ac7 \u0aae\u0acb\u0a95\u0ab2\u0ab5\u0abe\u0aae\u0abe\u0a82 \u0a86\u0ab5\u0ab6\u0ac7" + "message": "\u0a9f\u0ac7\u0a95\u0acd\u0ab8\u0acd\u0a9f\u0aa8\u0ac7 \u0a93\u0ab3\u0a96\u0ab5\u0abe \u0aae\u0abe\u0a9f\u0ac7 \u0aa4\u0aae\u0abe\u0ab0\u0acb \u0ab5\u0ac9\u0a87\u0ab8 \u0a87\u0aa8\u0aaa\u0ac1\u0a9f Google \u0ab8\u0ab0\u0acd\u0ab5\u0ab0\u0acd\u0ab8\u0aa8\u0ac7 \u0aae\u0acb\u0a95\u0ab2\u0ab5\u0abe\u0aae\u0abe\u0a82 \u0a86\u0ab5\u0ab6\u0ac7." }, "voice_turn_off": { "message": "\u0ab5\u0ac9\u0a87\u0ab8 \u0a87\u0aa8\u0aaa\u0ac1\u0a9f \u0ab8\u0abe\u0aa7\u0aa8 \u0aac\u0a82\u0aa7 \u0a95\u0ab0\u0acb"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/hi/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/hi/messages.json index 926044e..3a14ba1 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/hi/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/hi/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u0915\u094d\u0937\u092e\u093e \u0915\u0930\u0947\u0902, \u0906\u092a \u0939\u0938\u094d\u0924\u0932\u0947\u0916\u0928 \u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0928\u0939\u0940\u0902 \u0915\u0930 \u0938\u0915\u0924\u0947, \u0915\u094d\u092f\u094b\u0902\u0915\u093f \u0928\u0947\u091f\u0935\u0930\u094d\u0915 \u0905\u0928\u0941\u092a\u0932\u092c\u094d\u0927 \u0939\u0948." }, "handwriting_privacy_info": { - "message": "\u0932\u0947\u0916 \u092a\u0939\u091a\u093e\u0928\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f \u0906\u092a\u0915\u093e \u0907\u0928\u092a\u0941\u091f Google \u0938\u0930\u094d\u0935\u0930 \u0915\u094b \u092d\u0947\u091c\u093e \u091c\u093e\u090f\u0917\u093e" + "message": "\u0932\u0947\u0916 \u0915\u094b \u092a\u0939\u091a\u093e\u0928\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f \u0906\u092a\u0915\u093e \u0907\u0928\u092a\u0941\u091f Google \u0938\u0930\u094d\u0935\u0930 \u0915\u094b \u092d\u0947\u091c\u093e \u091c\u093e\u090f\u0917\u093e." }, "hide_keyboard": { "message": "\u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u091b\u093f\u092a\u093e\u090f\u0902" @@ -2634,7 +2634,7 @@ "message": "\u0907\u0938\u0915\u0947 \u0932\u093f\u090f \u0938\u0941\u0927\u093e\u0930 \u092a\u0930 \u0927\u094d\u092f\u093e\u0928 \u0928 \u0926\u0947\u0902" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u0938\u0941\u0927\u093e\u0930 \u092a\u0930 \u0927\u094d\u092f\u093e\u0928 \u0928 \u0926\u0947\u0902" }, "il_heb_settings_page": { "message": "\u0939\u093f\u092c\u094d\u0930\u0942 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917 \u092a\u0943\u0937\u094d\u200d\u0920" @@ -3300,7 +3300,7 @@ "message": "\u0927\u094d\u0935\u0928\u093f" }, "voice_privacy_info": { - "message": "\u0932\u0947\u0916 \u0915\u094b \u092a\u0939\u091a\u093e\u0928\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f \u0906\u092a\u0915\u0940 \u0906\u0935\u093e\u091c\u093c \u0915\u094b \u0915\u093f\u0938\u0940 Google \u0938\u0930\u094d\u0935\u0930 \u092a\u0930 \u092d\u0947\u091c\u093e \u091c\u093e\u090f\u0917\u093e" + "message": "\u0932\u0947\u0916 \u0915\u094b \u092a\u0939\u091a\u093e\u0928\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f \u0906\u092a\u0915\u093e \u0927\u094d\u200d\u0935\u0928\u093f \u0907\u0928\u092a\u0941\u091f Google \u0938\u0930\u094d\u0935\u0930 \u0915\u094b \u092d\u0947\u091c\u093e \u091c\u093e\u090f\u0917\u093e." }, "voice_turn_off": { "message": "\u0927\u094d\u0935\u0928\u093f \u0907\u0928\u0941\u092a\u091f \u091f\u0942\u0932 \u092c\u0902\u0926 \u0915\u0930\u0947\u0902"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/hr/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/hr/messages.json index cc453fd3..31e0fae 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/hr/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/hr/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u017dao nam je, ali ne mo\u017eete upotrebljavati rukopis jer mre\u017ea nije dostupna." }, "handwriting_privacy_info": { - "message": "Va\u0161 \u0107e se unos poslati Googleovom poslu\u017eitelju radi prepoznavanja teksta" + "message": "Va\u0161 \u0107e se unos poslati Googleovim poslu\u017eiteljima radi prepoznavanja teksta" }, "hide_keyboard": { "message": "sakrij tipkovnicu" @@ -2634,7 +2634,7 @@ "message": "Zanemari ispravak za" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Zanemari ispravak" }, "il_heb_settings_page": { "message": "Stranica postavki hebrejske tipkovnice" @@ -3300,7 +3300,7 @@ "message": "Glasovno" }, "voice_privacy_info": { - "message": "Snimka va\u0161eg glasa poslat \u0107e se Googleovu poslu\u017eitelju radi prepoznavanja teksta" + "message": "Va\u0161 \u0107e se glasovni unos poslati Googleovim poslu\u017eiteljima radi prepoznavanja teksta" }, "voice_turn_off": { "message": "isklju\u010di alat za glasovni unos"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/hu/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/hu/messages.json index af4f8b5..56e3662c 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/hu/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/hu/messages.json
@@ -2616,7 +2616,7 @@ "message": "Sajnos nem lehet haszn\u00e1lni a k\u00e9z\u00edr\u00e1sos bevitelt, mert nincs h\u00e1l\u00f3zati kapcsolat." }, "handwriting_privacy_info": { - "message": "A be\u00edrt sz\u00f6veget a Google megkapja, hogy megvizsg\u00e1lhassa" + "message": "A be\u00edrt sz\u00f6veget a Google megkapja a felismer\u00e9s \u00e9rdek\u00e9ben" }, "hide_keyboard": { "message": "Billenty\u0171zet elrejt\u00e9se" @@ -2634,7 +2634,7 @@ "message": "Jav\u00edt\u00e1s mell\u0151z\u00e9se enn\u00e9l a sz\u00f3n\u00e1l:" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Jav\u00edt\u00e1s mell\u0151z\u00e9se" }, "il_heb_settings_page": { "message": "H\u00e9ber billenty\u0171zet be\u00e1ll\u00edt\u00e1sainak oldala" @@ -3300,7 +3300,7 @@ "message": "Hang" }, "voice_privacy_info": { - "message": "Hangj\u00e1t tov\u00e1bb\u00edtani fogjuk egy Google-szerverre sz\u00f6vegfelismer\u00e9sre" + "message": "A hangfelv\u00e9telt a Google megkapja a felismer\u00e9s \u00e9rdek\u00e9ben" }, "voice_turn_off": { "message": "hangbeviteli eszk\u00f6z kikapcsol\u00e1sa"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/id/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/id/messages.json index a6df20e4..3d620ed 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/id/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/id/messages.json
@@ -2616,7 +2616,7 @@ "message": "Maaf, Anda tidak dapat menggunakan tulisan tangan, karena jaringan tidak tersedia." }, "handwriting_privacy_info": { - "message": "Masukan Anda akan dikirim ke server Google untuk mengenali teks" + "message": "Masukan Anda akan dikirim ke server Google untuk mengenali teks." }, "hide_keyboard": { "message": "sembunyikan keyboard" @@ -2634,7 +2634,7 @@ "message": "Abaikan koreksi untuk" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Abaikan koreksi" }, "il_heb_settings_page": { "message": "Laman Setelan Keyboard Ibrani" @@ -3300,7 +3300,7 @@ "message": "Suara" }, "voice_privacy_info": { - "message": "Suara Anda akan dikirim ke server Google untuk mengenali teks" + "message": "Masukan suara Anda akan dikirim ke server Google untuk mengenali teks." }, "voice_turn_off": { "message": "nonaktifkan alat masukan suara"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/it/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/it/messages.json index 39837d9a..9a5e2e9 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/it/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/it/messages.json
@@ -2616,7 +2616,7 @@ "message": "Spiacenti, non puoi utilizzare la scrittura a mano libera perch\u00e9 la rete non \u00e8 disponibile." }, "handwriting_privacy_info": { - "message": "Il testo inserito verr\u00e0 inviato a un server di Google per poterlo riconoscere" + "message": "Il tuo input verr\u00e0 inviato ai server di Google per il riconoscimento del testo." }, "hide_keyboard": { "message": "nascondi tastiera" @@ -2634,7 +2634,7 @@ "message": "Ignora correzione di:" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignora correzione" }, "il_heb_settings_page": { "message": "Pagina Impostazioni tastiera Ebraico" @@ -3300,7 +3300,7 @@ "message": "Voce" }, "voice_privacy_info": { - "message": "Il tuo input vocale verr\u00e0 inviato a un server di Google per il riconoscimento del testo" + "message": "Il tuo input vocale verr\u00e0 inviato ai server di Google per il riconoscimento del testo." }, "voice_turn_off": { "message": "disattiva strumento di input vocale"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/iw/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/iw/messages.json index aedadc0..ecc81bb 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/iw/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/iw/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u05de\u05e6\u05d8\u05e2\u05e8\u05d9\u05dd. \u05d0\u05d9\u05e0\u05da \u05d9\u05db\u05d5\u05dc \u05dc\u05d4\u05e9\u05ea\u05de\u05e9 \u05d1\u05db\u05ea\u05d1 \u05d9\u05d3 \u05de\u05e4\u05e0\u05d9 \u05e9\u05d4\u05e8\u05e9\u05ea \u05d0\u05d9\u05e0\u05d4 \u05d6\u05de\u05d9\u05e0\u05d4." }, "handwriting_privacy_info": { - "message": "\u200f\u05d4\u05e7\u05dc\u05d8 \u05e9\u05dc\u05da \u05d9\u05d9\u05e9\u05dc\u05d7 \u05d0\u05dc \u05e9\u05e8\u05ea \u05e9\u05dc Google \u05dc\u05d6\u05d9\u05d4\u05d5\u05d9 \u05d8\u05e7\u05e1\u05d8" + "message": "\u200f\u05d4\u05e7\u05dc\u05d8 \u05e9\u05dc\u05da \u05d9\u05d9\u05e9\u05dc\u05d7 \u05d0\u05dc \u05e9\u05e8\u05ea\u05d9 Google \u05dc\u05d6\u05d9\u05d4\u05d5\u05d9 \u05d8\u05e7\u05e1\u05d8." }, "hide_keyboard": { "message": "\u05d4\u05e1\u05ea\u05e8 \u05de\u05e7\u05dc\u05d3\u05ea" @@ -2634,7 +2634,7 @@ "message": "\u05d4\u05ea\u05e2\u05dc\u05dd \u05de\u05ea\u05d9\u05e7\u05d5\u05df \u05e9\u05dc" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u05d4\u05ea\u05e2\u05dc\u05de\u05d5\u05ea \u05de\u05ea\u05d9\u05e7\u05d5\u05df" }, "il_heb_settings_page": { "message": "\u05d3\u05e3 \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05e9\u05dc \u05de\u05e7\u05dc\u05d3\u05ea \u05e2\u05d1\u05e8\u05d9\u05ea" @@ -3300,7 +3300,7 @@ "message": "\u05e7\u05d5\u05dc" }, "voice_privacy_info": { - "message": "\u200f\u05d4\u05e7\u05dc\u05d8\u05d4 \u05e9\u05dc \u05d4\u05e7\u05d5\u05dc \u05e9\u05dc\u05da \u05ea\u05d9\u05e9\u05dc\u05d7 \u05d0\u05dc \u05e9\u05e8\u05ea Google \u05dc\u05d6\u05d9\u05d4\u05d5\u05d9 \u05d8\u05e7\u05e1\u05d8" + "message": "\u200f\u05d4\u05e7\u05dc\u05d8 \u05d4\u05e7\u05d5\u05dc\u05d9 \u05e9\u05dc\u05da \u05d9\u05d9\u05e9\u05dc\u05d7 \u05d0\u05dc \u05e9\u05e8\u05ea\u05d9 Google \u05dc\u05d6\u05d9\u05d4\u05d5\u05d9 \u05d8\u05e7\u05e1\u05d8." }, "voice_turn_off": { "message": "\u05db\u05d1\u05d4 \u05d0\u05ea \u05db\u05dc\u05d9 \u05d4\u05e7\u05dc\u05d8 \u05d4\u05e7\u05d5\u05dc\u05d9"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ja/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ja/messages.json index 9713b9f..7107b6bb 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ja/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ja/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306b\u63a5\u7d9a\u3067\u304d\u306a\u3044\u305f\u3081\u3001\u624b\u66f8\u304d\u5165\u529b\u3092\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093\u3002" }, "handwriting_privacy_info": { - "message": "\u5165\u529b\u5185\u5bb9\u306f\u3001\u30c6\u30ad\u30b9\u30c8\u3092\u8a8d\u8b58\u3059\u308b\u305f\u3081\u306b Google \u306e\u30b5\u30fc\u30d0\u30fc\u306b\u9001\u4fe1\u3055\u308c\u307e\u3059" + "message": "\u5165\u529b\u3057\u305f\u5185\u5bb9\u306f\u3001\u30c6\u30ad\u30b9\u30c8\u3092\u8a8d\u8b58\u3059\u308b\u305f\u3081\u306b Google \u306e\u30b5\u30fc\u30d0\u30fc\u306b\u9001\u4fe1\u3055\u308c\u307e\u3059\u3002" }, "hide_keyboard": { "message": "\u30ad\u30fc\u30dc\u30fc\u30c9\u3092\u975e\u8868\u793a" @@ -2634,7 +2634,7 @@ "message": "\u6b21\u306e\u8a9e\u306f\u4fee\u6b63\u3057\u306a\u3044:" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u4fee\u6b63\u3057\u306a\u3044" }, "il_heb_settings_page": { "message": "\u30d8\u30d6\u30e9\u30a4\u8a9e\u30ad\u30fc\u30dc\u30fc\u30c9\u8a2d\u5b9a\u30da\u30fc\u30b8" @@ -3300,7 +3300,7 @@ "message": "\u97f3\u58f0\u5165\u529b" }, "voice_privacy_info": { - "message": "\u5165\u529b\u3057\u305f\u97f3\u58f0\u306f\u3001\u30c6\u30ad\u30b9\u30c8\u8a8d\u8b58\u306e\u305f\u3081 Google \u306e\u30b5\u30fc\u30d0\u30fc\u306b\u9001\u4fe1\u3055\u308c\u307e\u3059" + "message": "\u5165\u529b\u3057\u305f\u97f3\u58f0\u306f\u3001\u30c6\u30ad\u30b9\u30c8\u3092\u8a8d\u8b58\u3059\u308b\u305f\u3081\u306b Google \u306e\u30b5\u30fc\u30d0\u30fc\u306b\u9001\u4fe1\u3055\u308c\u307e\u3059\u3002" }, "voice_turn_off": { "message": "\u97f3\u58f0\u5165\u529b\u30c4\u30fc\u30eb\u3092\u30aa\u30d5\u306b\u3059\u308b"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/kn/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/kn/messages.json index 7e68532b..8aebeac 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/kn/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/kn/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u0c95\u0ccd\u0cb7\u0cae\u0cbf\u0cb8\u0cbf, \u0ca8\u0cc6\u0c9f\u0ccd\u200c\u0cb5\u0cb0\u0ccd\u0c95\u0ccd \u0cb2\u0cad\u0ccd\u0caf\u0cb5\u0cbf\u0cb2\u0ccd\u0cb2\u0ca6 \u0c95\u0cbe\u0cb0\u0ca3, \u0ca8\u0cc0\u0cb5\u0cc1 \u0c95\u0cc8\u0cac\u0cb0\u0cb9 \u0cac\u0cb3\u0cb8\u0cb2\u0cc1 \u0cb8\u0cbe\u0ca7\u0ccd\u0caf\u0cb5\u0cbf\u0cb2\u0ccd\u0cb2." }, "handwriting_privacy_info": { - "message": "\u0caa\u0ca0\u0ccd\u0caf\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1 \u0c97\u0cc1\u0cb0\u0cc1\u0ca4\u0cbf\u0cb8\u0cb2\u0cc1 Google \u0cb8\u0cb0\u0ccd\u0cb5\u0cb0\u0ccd\u200c\u0c97\u0cc6 \u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0c87\u0ca8\u0ccd\u200c\u0caa\u0cc1\u0c9f\u0ccd\u200c \u0c85\u0ca8\u0ccd\u0ca8\u0cc1 \u0c95\u0cb3\u0cc1\u0cb9\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0ca6\u0cc6" + "message": "\u0caa\u0ca0\u0ccd\u0caf\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1 \u0c97\u0cc1\u0cb0\u0cc1\u0ca4\u0cbf\u0cb8\u0cb2\u0cc1 \u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0c87\u0ca8\u0ccd\u200c\u0caa\u0cc1\u0c9f\u0ccd \u0c85\u0ca8\u0ccd\u0ca8\u0cc1 Google \u0cb8\u0cb0\u0ccd\u0cb5\u0cb0\u0ccd\u200c\u0c97\u0cb3\u0cbf\u0c97\u0cc6 \u0c95\u0cb3\u0cc1\u0cb9\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0ca6\u0cc6." }, "hide_keyboard": { "message": "\u0c95\u0cc0\u0cac\u0ccb\u0cb0\u0ccd\u0ca1\u0ccd \u0cae\u0cb0\u0cc6\u0cae\u0cbe\u0ca1\u0cbf" @@ -2634,7 +2634,7 @@ "message": "\u0c87\u0ca6\u0c95\u0ccd\u0c95\u0cbe\u0c97\u0cbf \u0cb8\u0cb0\u0cbf\u0caa\u0ca1\u0cbf\u0cb8\u0cc1\u0cb5\u0cbf\u0c95\u0cc6\u0caf\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca8\u0cbf\u0cb0\u0ccd\u0cb2\u0c95\u0ccd\u0cb7\u0cbf\u0cb8\u0cbf" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u0ca4\u0cbf\u0ca6\u0ccd\u0ca6\u0cc1\u0caa\u0ca1\u0cbf \u0ca8\u0cbf\u0cb0\u0ccd\u0cb2\u0c95\u0ccd\u0cb7\u0cbf\u0cb8\u0cbf" }, "il_heb_settings_page": { "message": "\u0cb9\u0cbf\u0cac\u0ccd\u0cb0\u0cc2 \u0c95\u0cbf\u0cd5\u0cac\u0cc6\u0cc2\u0cd5\u0cb0\u0ccd\u0ca1\u0ccd \u0cb8\u0cc6\u0c9f\u0ccd\u0c9f\u0cbf\u0c82\u0c97\u0ccd\u200c\u0c97\u0cb3 \u0caa\u0cc1\u0c9f" @@ -3300,7 +3300,7 @@ "message": "\u0ca7\u0ccd\u0cb5\u0ca8\u0cbf" }, "voice_privacy_info": { - "message": "\u0caa\u0ca0\u0ccd\u0caf\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1 \u0c97\u0cc1\u0cb0\u0cc1\u0ca4\u0cbf\u0cb8\u0cb2\u0cc1 \u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0ca7\u0ccd\u0cb5\u0ca8\u0cbf\u0caf\u0ca8\u0ccd\u0ca8\u0cc1 Google \u0cb8\u0cb0\u0ccd\u0cb5\u0cb0\u0ccd\u200c\u0c97\u0cc6 \u0c95\u0cb3\u0cc1\u0cb9\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0ca6\u0cc6" + "message": "\u0caa\u0ca0\u0ccd\u0caf\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1 \u0c97\u0cc1\u0cb0\u0cc1\u0ca4\u0cbf\u0cb8\u0cb2\u0cc1 \u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0ca7\u0ccd\u0cb5\u0ca8\u0cbf \u0c87\u0ca8\u0ccd\u200c\u0caa\u0cc1\u0c9f\u0ccd \u0c85\u0ca8\u0ccd\u0ca8\u0cc1 Google \u0cb8\u0cb0\u0ccd\u0cb5\u0cb0\u0ccd\u200c\u0c97\u0cb3\u0cbf\u0c97\u0cc6 \u0c95\u0cb3\u0cc1\u0cb9\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0ca6\u0cc6." }, "voice_turn_off": { "message": "\u0ca7\u0ccd\u0cb5\u0ca8\u0cbf \u0c87\u0ca8\u0ccd\u200c\u0caa\u0cc1\u0c9f\u0ccd \u0c9f\u0cc2\u0cb2\u0ccd \u0c85\u0ca8\u0ccd\u0ca8\u0cc1 \u0c86\u0cab\u0ccd \u0cae\u0cbe\u0ca1\u0cbf"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ko/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ko/messages.json index 75dc586..00e4970 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ko/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ko/messages.json
@@ -2634,7 +2634,7 @@ "message": "\uc790\ub3d9 \uc218\uc815 \uae30\ub2a5 \ubb34\uc2dc" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\uc790\ub3d9 \uc218\uc815 \uae30\ub2a5 \ubb34\uc2dc" }, "il_heb_settings_page": { "message": "\ud788\ube0c\ub9ac\uc5b4 \ud0a4\ubcf4\ub4dc \uc124\uc815 \ud398\uc774\uc9c0" @@ -3300,7 +3300,7 @@ "message": "\uc74c\uc131" }, "voice_privacy_info": { - "message": "\uc74c\uc131\uc740 \ud14d\uc2a4\ud2b8 \uc778\uc2dd\uc744 \uc704\ud574 Google \uc11c\ubc84\ub85c \uc804\uc1a1\ub429\ub2c8\ub2e4." + "message": "\uc74c\uc131 \uc785\ub825\uc740 \ud14d\uc2a4\ud2b8 \uc778\uc2dd\uc744 \uc704\ud574 Google \uc11c\ubc84\ub85c \uc804\uc1a1\ub429\ub2c8\ub2e4." }, "voice_turn_off": { "message": "\uc74c\uc131 \uc785\ub825 \ub3c4\uad6c \uc0ac\uc6a9 \uc548\ud568"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/lt/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/lt/messages.json index a8bb5d2a..ecfe94c6 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/lt/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/lt/messages.json
@@ -2616,7 +2616,7 @@ "message": "Apgailestaujame, negalite naudoti ra\u0161ymo ranka funkcijos, nes tinklas yra nepasiekiamas." }, "handwriting_privacy_info": { - "message": "J\u016bs\u0173 \u012fvestis bus i\u0161si\u0173sta \u012f \u201eGoogle\u201c server\u012f, kad b\u016bt\u0173 atpa\u017eintas tekstas" + "message": "J\u016bs\u0173 \u012fvestis bus i\u0161si\u0173sta \u012f \u201eGoogle\u201c serverius, kad b\u016bt\u0173 atpa\u017eintas tekstas." }, "hide_keyboard": { "message": "sl\u0117pti klaviat\u016br\u0105" @@ -2634,7 +2634,7 @@ "message": "Ignoruoti pataisym\u0105" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignoruoti pataisym\u0105" }, "il_heb_settings_page": { "message": "Hebraji\u0161kos klaviat\u016bros nustatym\u0173 puslapis" @@ -3300,7 +3300,7 @@ "message": "Voice" }, "voice_privacy_info": { - "message": "J\u016bs\u0173 balso \u012fra\u0161as bus nusi\u0173stas \u012f \u201eGoogle\u201c server\u012f, kad b\u016bt\u0173 galima atpa\u017einti tekst\u0105" + "message": "J\u016bs\u0173 \u012fvestis balsu bus i\u0161si\u0173sta \u012f \u201eGoogle\u201c serverius, kad b\u016bt\u0173 atpa\u017eintas tekstas." }, "voice_turn_off": { "message": "I\u0161jungti \u012fvesties balsu \u012frank\u012f"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/lv/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/lv/messages.json index 8be3566d..686e3f0 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/lv/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/lv/messages.json
@@ -2634,7 +2634,7 @@ "message": "Ignor\u0113t labojumu v\u0101rdam" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignor\u0113t labojumu" }, "il_heb_settings_page": { "message": "Ebreju valodas tastat\u016bras iestat\u012bjumu lapa" @@ -3300,7 +3300,7 @@ "message": "Balss" }, "voice_privacy_info": { - "message": "J\u016bsu balss ieraksts tiks nos\u016bt\u012bts Google serverim, lai atpaz\u012btu tekstu." + "message": "J\u016bsu balss ievade tiks nos\u016bt\u012bta Google serveriem teksta atpaz\u012b\u0161anai." }, "voice_turn_off": { "message": "izsl\u0113gt balss ievades r\u012bku"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ml/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ml/messages.json index 25e1d44..e32e592 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ml/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ml/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u0d15\u0d4d\u0d37\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15, \u0d28\u0d46\u0d31\u0d4d\u0d31\u0d4d\u200c\u0d35\u0d7c\u0d15\u0d4d\u0d15\u0d4d \u0d32\u0d2d\u0d4d\u0d2f\u0d2e\u0d32\u0d4d\u0d32\u0d3e\u0d24\u0d4d\u0d24\u0d24\u0d3f\u0d28\u0d3e\u0d7d, \u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d7e\u0d15\u0d4d\u0d15\u0d4d \u0d15\u0d48\u0d2f\u0d4d\u0d2f\u0d46\u0d34\u0d41\u0d24\u0d4d\u0d24\u0d4d \u0d30\u0d40\u0d24\u0d3f \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d15\u0d4d\u0d15\u0d3e\u0d28\u0d3e\u0d35\u0d3f\u0d32\u0d4d\u0d32." }, "handwriting_privacy_info": { - "message": "\u0d1f\u0d46\u0d15\u0d4d\u200c\u0d38\u0d4d\u200c\u0d31\u0d4d\u0d31\u0d4d \u0d24\u0d3f\u0d30\u0d3f\u0d1a\u0d4d\u0d1a\u0d31\u0d3f\u0d2f\u0d3e\u0d7b\u00a0\u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d07\u0d7b\u0d2a\u0d41\u0d1f\u0d4d\u0d1f\u0d4d Google \u0d38\u0d46\u0d7c\u0d35\u0d31\u0d3f\u0d32\u0d47\u0d15\u0d4d\u0d15\u0d4d \u0d05\u0d2f\u0d2f\u0d4d\u200c\u0d15\u0d4d\u0d15\u0d41\u0d02" + "message": "\u0d1f\u0d46\u0d15\u0d4d\u200c\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d4d \u0d24\u0d3f\u0d30\u0d3f\u0d1a\u0d4d\u0d1a\u0d31\u0d3f\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d24\u0d3f\u0d28\u0d4d, \u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d07\u0d7b\u0d2a\u0d41\u0d1f\u0d4d\u0d1f\u0d4d Google \u0d38\u0d46\u0d7c\u0d35\u0d31\u0d41\u0d15\u0d33\u0d3f\u0d32\u0d47\u0d15\u0d4d\u0d15\u0d4d \u0d05\u0d2f\u0d2f\u0d4d\u200c\u0d15\u0d4d\u0d15\u0d41\u0d02." }, "hide_keyboard": { "message": "\u0d15\u0d40\u0d2c\u0d4b\u0d7c\u0d21\u0d4d \u0d2e\u0d31\u0d2f\u0d4d\u200c\u0d15\u0d4d\u0d15\u0d41\u0d15" @@ -2634,7 +2634,7 @@ "message": "\u0d08 \u0d35\u0d3e\u0d15\u0d4d\u0d15\u0d3f\u0d28\u0d41\u0d33\u0d4d\u0d33 \u0d24\u0d3f\u0d30\u0d41\u0d24\u0d4d\u0d24\u0d7d \u0d05\u0d35\u0d17\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u0d24\u0d3f\u0d30\u0d41\u0d24\u0d4d\u0d24\u0d7d \u0d05\u0d35\u0d17\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15" }, "il_heb_settings_page": { "message": "\u0d39\u0d40\u0d2c\u0d4d\u0d30\u0d41 \u0d15\u0d40\u0d2c\u0d4b\u0d7c\u0d21\u0d4d \u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23 \u0d2a\u0d47\u0d1c\u0d4d" @@ -3300,7 +3300,7 @@ "message": "\u0d35\u0d4b\u0d2f\u0d4d\u0d38\u0d4d" }, "voice_privacy_info": { - "message": "\u0d1f\u0d46\u0d15\u0d4d\u200c\u0d38\u0d4d\u200c\u0d31\u0d4d\u0d31\u0d4d \u0d24\u0d3f\u0d30\u0d3f\u0d1a\u0d4d\u0d1a\u0d31\u0d3f\u0d2f\u0d3e\u0d7b Google \u0d38\u0d46\u0d7c\u0d35\u0d31\u0d3f\u0d32\u0d47\u0d15\u0d4d\u0d15\u0d4d \u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d36\u0d2c\u0d4d\u200c\u0d26\u0d02 \u0d05\u0d2f\u0d2f\u0d4d\u200c\u0d15\u0d4d\u0d15\u0d41\u0d02" + "message": "\u0d1f\u0d46\u0d15\u0d4d\u200c\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d4d \u0d24\u0d3f\u0d30\u0d3f\u0d1a\u0d4d\u0d1a\u0d31\u0d3f\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d24\u0d3f\u0d28\u0d4d, \u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d35\u0d4b\u0d2f\u0d4d\u200c\u0d38\u0d4d \u0d07\u0d7b\u0d2a\u0d41\u0d1f\u0d4d\u0d1f\u0d4d Google \u0d38\u0d46\u0d7c\u0d35\u0d31\u0d41\u0d15\u0d33\u0d3f\u0d32\u0d47\u0d15\u0d4d\u0d15\u0d4d \u0d05\u0d2f\u0d2f\u0d4d\u200c\u0d15\u0d4d\u0d15\u0d41\u0d02." }, "voice_turn_off": { "message": "\u0d35\u0d4b\u0d2f\u0d4d\u200c\u0d38\u0d4d \u0d07\u0d7b\u0d2a\u0d41\u0d1f\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d15\u0d30\u0d23\u0d02 \u0d13\u0d2b\u0d3e\u0d15\u0d4d\u0d15\u0d41\u0d15"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/mr/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/mr/messages.json index 06ff85c..81aced8 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/mr/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/mr/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u0915\u094d\u0937\u092e\u0938\u094d\u0935, \u0928\u0947\u091f\u0935\u0930\u094d\u0915 \u0905\u0928\u0941\u092a\u0932\u092c\u094d\u0927 \u0905\u0938\u0932\u094d\u092f\u093e\u092e\u0941\u0933\u0947 \u0906\u092a\u0923 \u0939\u0938\u094d\u0924\u0932\u0947\u0916\u0928 \u0935\u093e\u092a\u0930\u0942 \u0936\u0915\u0924 \u0928\u093e\u0939\u0940." }, "handwriting_privacy_info": { - "message": "\u092e\u091c\u0915\u0942\u0930 \u0913\u0933\u0916\u0923\u094d\u092f\u093e\u0938\u093e\u0920\u0940 \u0906\u092a\u0932\u0947 \u0907\u0928\u092a\u0941\u091f \u090f\u0915\u093e Google \u0938\u0930\u094d\u0935\u094d\u0939\u0930\u0935\u0930 \u092a\u093e\u0920\u0935\u093f\u0932\u0947 \u091c\u093e\u0908\u0932" + "message": "\u092e\u091c\u0915\u0942\u0930 \u0913\u0933\u0916\u0923\u094d\u092f\u093e\u0938\u093e\u0920\u0940 \u0906\u092a\u0932\u0947 \u0907\u0928\u092a\u0941\u091f Google \u0938\u0930\u094d\u0935\u094d\u0939\u0930\u0935\u0930 \u092a\u093e\u0920\u0935\u093f\u0932\u0947 \u091c\u093e\u0908\u0932." }, "hide_keyboard": { "message": "\u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0932\u092a\u0935\u093e" @@ -2634,7 +2634,7 @@ "message": "\u092f\u093e\u0938\u093e\u0920\u0940 \u0938\u0941\u0927\u093e\u0930\u0923\u0947\u0915\u0921\u0947 \u0926\u0941\u0930\u094d\u0932\u0915\u094d\u0937 \u0915\u0930\u093e" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u0938\u0941\u0927\u093e\u0930\u0923\u0947\u0915\u0921\u0947 \u0926\u0941\u0930\u094d\u0932\u0915\u094d\u0937 \u0915\u0930\u093e" }, "il_heb_settings_page": { "message": "\u0939\u093f\u092c\u094d\u0930\u0942 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917\u094d\u091c \u092a\u0943\u0937\u094d\u0920" @@ -3300,7 +3300,7 @@ "message": "\u0935\u094d\u0939\u0949\u0907\u0938" }, "voice_privacy_info": { - "message": "\u092e\u091c\u0915\u0942\u0930 \u0913\u0933\u0916\u0923\u094d\u200d\u092f\u093e\u0938\u093e\u0920\u0940 \u0906\u092a\u0932\u093e \u0935\u094d\u200d\u0939\u0949\u0907\u0938 Google \u0938\u0930\u094d\u0935\u094d\u200d\u0939\u0930\u0915\u0921\u0947 \u092a\u093e\u0920\u0935\u093f\u0932\u093e \u091c\u093e\u0908\u0932" + "message": "\u092e\u091c\u0915\u0942\u0930 \u0913\u0933\u0916\u0923\u094d\u092f\u093e\u0938\u093e\u0920\u0940 \u0906\u092a\u0932\u0947 \u0935\u094d\u0939\u0949\u0907\u0938 \u0907\u0928\u092a\u0941\u091f Google \u0938\u0930\u094d\u0935\u094d\u0939\u0930\u0935\u0930 \u092a\u093e\u0920\u0935\u093f\u0932\u0947 \u091c\u093e\u0908\u0932." }, "voice_turn_off": { "message": "\u0935\u094d\u0939\u0949\u0907\u0938 \u0907\u0928\u092a\u0941\u091f \u0938\u093e\u0927\u0928 \u092c\u0902\u0926 \u0915\u0930\u093e"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ms/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ms/messages.json index cd00ee59..bcecd9bf 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ms/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ms/messages.json
@@ -2616,7 +2616,7 @@ "message": "Maaf, anda tidak boleh menggunakan tulisan tangan kerana rangkaian tidak tersedia." }, "handwriting_privacy_info": { - "message": "Input anda akan dihantar ke pelayan Google untuk mengenal pasti teks" + "message": "Input anda akan dihantar ke pelayan Google untuk mengecam teks." }, "hide_keyboard": { "message": "sembunyikan papan kekunci" @@ -2634,7 +2634,7 @@ "message": "Abaikan pembetulan untuk" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Abaikan pembetulan" }, "il_heb_settings_page": { "message": "Halaman Tetapan Papan Kekunci Ibrani" @@ -3300,7 +3300,7 @@ "message": "Suara" }, "voice_privacy_info": { - "message": "Suara anda akan dihantar ke pelayan Google untuk mengecam teks" + "message": "Input suara anda akan dihantar ke pelayan Google untuk mengecam teks." }, "voice_turn_off": { "message": "matikan alat input suara"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/nb/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/nb/messages.json index 3b67ede6..f3280f2 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/nb/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/nb/messages.json
@@ -2616,7 +2616,7 @@ "message": "Beklager, du kan ikke bruke h\u00e5ndskrift, fordi nettverket ikke er tilgjengelig." }, "handwriting_privacy_info": { - "message": "Inndataene dine blir sendt til en Google-tjener for tekstgjenkjenning" + "message": "Det du skriver, sendes til Google-tjenerne for gjenkjenning av tekst." }, "hide_keyboard": { "message": "skjul tastatur" @@ -2634,7 +2634,7 @@ "message": "Ignorer korrigering av" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignorer korrigering" }, "il_heb_settings_page": { "message": "Innstillinger-side for hebraisk tastatur" @@ -3300,7 +3300,7 @@ "message": "Tale" }, "voice_privacy_info": { - "message": "Stemmeopptaket ditt blir sendt til en Google-tjener for \u00e5 gjenkjenne tekst" + "message": "Det du sier, sendes til Google-tjenerne for gjenkjenning av tekst." }, "voice_turn_off": { "message": "sl\u00e5 av verkt\u00f8yet for taleinndata"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/nl/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/nl/messages.json index 45f09690..5fba3fc5 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/nl/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/nl/messages.json
@@ -2616,7 +2616,7 @@ "message": "Je kunt geen handschrift gebruiken omdat het netwerk niet beschikbaar is." }, "handwriting_privacy_info": { - "message": "Uw invoer wordt verzonden naar een Google-server om de tekst te herkennen" + "message": "Je invoer wordt naar servers van Google verzonden om de tekst te herkennen." }, "hide_keyboard": { "message": "toetsenbord verbergen" @@ -2634,7 +2634,7 @@ "message": "Correctie negeren voor" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Correctie negeren" }, "il_heb_settings_page": { "message": "Pagina met instellingen voor Hebreeuws toetsenbord" @@ -3300,7 +3300,7 @@ "message": "Spraak" }, "voice_privacy_info": { - "message": "Je stem wordt naar een Google-server verzonden om de tekst te herkennen" + "message": "Je gesproken invoer wordt naar servers van Google verzonden om de tekst te herkennen." }, "voice_turn_off": { "message": "tool voor spraakinvoer uitschakelen"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/pl/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/pl/messages.json index 2a751bc..5ec1bb4 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/pl/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/pl/messages.json
@@ -2616,7 +2616,7 @@ "message": "Nie mo\u017cesz pisa\u0107 odr\u0119cznie, poniewa\u017c sie\u0107 jest niedost\u0119pna." }, "handwriting_privacy_info": { - "message": "To, co napiszesz, zostanie wys\u0142ane na serwer Google w celu rozpoznania tekstu" + "message": "To, co napiszesz, zostanie wys\u0142ane na serwery Google w celu rozpoznania tekstu." }, "hide_keyboard": { "message": "ukryj klawiatur\u0119" @@ -2634,7 +2634,7 @@ "message": "Ignoruj korekt\u0119" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignoruj korekt\u0119" }, "il_heb_settings_page": { "message": "Strona ustawie\u0144 klawiatury hebrajskiej" @@ -3300,7 +3300,7 @@ "message": "G\u0142os" }, "voice_privacy_info": { - "message": "Tw\u00f3j g\u0142os zostanie wys\u0142any do serwera Google do rozpoznania tekstu" + "message": "To, co powiesz, zostanie wys\u0142ane na serwery Google w celu rozpoznania tekstu." }, "voice_turn_off": { "message": "wy\u0142\u0105cz narz\u0119dzie rozpoznawania mowy"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_BR/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_BR/messages.json index 55e5003..e98686c 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_BR/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_BR/messages.json
@@ -2616,7 +2616,7 @@ "message": "N\u00e3o \u00e9 poss\u00edvel usar a pesquisa escrita, porque a rede n\u00e3o est\u00e1 dispon\u00edvel." }, "handwriting_privacy_info": { - "message": "Seu m\u00e9todo de entrada ser\u00e1 enviado para um servidor do Google para reconhecimento do texto" + "message": "Sua entrada ser\u00e1 enviada aos servidores do Google para reconhecimento de texto." }, "hide_keyboard": { "message": "ocultar teclado" @@ -2634,7 +2634,7 @@ "message": "Ignorar corre\u00e7\u00e3o para" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignorar corre\u00e7\u00e3o" }, "il_heb_settings_page": { "message": "P\u00e1gina de configura\u00e7\u00f5es do teclado hebraico" @@ -3300,7 +3300,7 @@ "message": "Voz" }, "voice_privacy_info": { - "message": "Sua voz ser\u00e1 enviada a um servidor do Google para reconhecimento de texto" + "message": "Sua entrada de texto por voz ser\u00e1 enviada aos servidores do Google para reconhecimento de texto." }, "voice_turn_off": { "message": "desativar ferramenta de entrada de texto por voz"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_PT/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_PT/messages.json index 1a3317c5..1c46e806 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_PT/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_PT/messages.json
@@ -2616,7 +2616,7 @@ "message": "Lamentamos, mas n\u00e3o \u00e9 poss\u00edvel utilizar a escrita manual porque a rede est\u00e1 indispon\u00edvel." }, "handwriting_privacy_info": { - "message": "Os dados introduzidos s\u00e3o enviados para um servidor da Google para fazer o reconhecimento do texto" + "message": "Os dados introduzidos s\u00e3o enviados para os servidores da Google para fazer o reconhecimento do texto." }, "hide_keyboard": { "message": "ocultar teclado" @@ -2634,7 +2634,7 @@ "message": "Ignorar corre\u00e7\u00e3o para" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignorar corre\u00e7\u00e3o" }, "il_heb_settings_page": { "message": "P\u00e1gina de defini\u00e7\u00f5es do teclado hebraico" @@ -3300,7 +3300,7 @@ "message": "Voz" }, "voice_privacy_info": { - "message": "A sua voz ser\u00e1 enviada para um servidor da Google para reconhecimento de texto" + "message": "As entradas de texto por voz s\u00e3o enviadas para os servidores da Google para fazer o reconhecimento do texto." }, "voice_turn_off": { "message": "desativar a ferramenta de entrada de texto por voz"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ro/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ro/messages.json index 4b9177f..db758db 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ro/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ro/messages.json
@@ -2616,7 +2616,7 @@ "message": "Nu po\u021bi s\u0103 folose\u0219ti scrierea de m\u00e2n\u0103, deoarece re\u021beaua nu este disponibil\u0103." }, "handwriting_privacy_info": { - "message": "Datele introduse vor fi trimise la un server Google pentru recunoa\u0219terea textului" + "message": "Scrisul va fi trimis c\u0103tre serverele Google pentru recunoa\u0219terea textului." }, "hide_keyboard": { "message": "ascunde tastatura" @@ -2634,7 +2634,7 @@ "message": "Ignor\u0103 corectura pentru" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignor\u0103 corectura" }, "il_heb_settings_page": { "message": "Pagina de set\u0103ri pentru tastatura ebraic\u0103" @@ -3300,7 +3300,7 @@ "message": "Intrare vocal\u0103" }, "voice_privacy_info": { - "message": "Pentru recunoa\u0219terea textului, \u00eenregistrarea vocii va fi trimis\u0103 la un server Google" + "message": "\u00cenregistrarea vocii va fi trimis\u0103 c\u0103tre serverele Google pentru recunoa\u0219terea textului." }, "voice_turn_off": { "message": "dezactiveaz\u0103 instrumentul de intrare vocal\u0103"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ru/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ru/messages.json index 0263f1f..fc100f6 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ru/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ru/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u0420\u0443\u043a\u043e\u043f\u0438\u0441\u043d\u044b\u0439 \u0432\u0432\u043e\u0434 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0441\u0435\u0442\u044c \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430." }, "handwriting_privacy_info": { - "message": "\u0422\u0435\u043a\u0441\u0442 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 Google \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f" + "message": "\u0422\u0435\u043a\u0441\u0442 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 Google \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f." }, "hide_keyboard": { "message": "\u0441\u043a\u0440\u044b\u0442\u044c \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0443" @@ -2634,7 +2634,7 @@ "message": "\u041f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c:" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u041f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c" }, "il_heb_settings_page": { "message": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0438 \u043d\u0430 \u0438\u0432\u0440\u0438\u0442\u0435" @@ -3300,7 +3300,7 @@ "message": "\u0413\u043e\u043b\u043e\u0441\u043e\u0432\u043e\u0439 \u0432\u0432\u043e\u0434" }, "voice_privacy_info": { - "message": "\u0417\u0430\u043f\u0438\u0441\u044c \u0432\u0430\u0448\u0435\u0433\u043e \u0433\u043e\u043b\u043e\u0441\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 Google \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430" + "message": "\u0417\u0430\u043f\u0438\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 Google \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430." }, "voice_turn_off": { "message": "\u0432\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0433\u043e\u043b\u043e\u0441\u043e\u0432\u043e\u0439 \u0432\u0432\u043e\u0434"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sk/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sk/messages.json index d8d11b0..cfae0397 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sk/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sk/messages.json
@@ -2616,7 +2616,7 @@ "message": "Je n\u00e1m to \u013e\u00fato, ale p\u00edsanie rukou nie je mo\u017en\u00e9 pou\u017ei\u0165, preto\u017ee sie\u0165 nie je k dispoz\u00edcii." }, "handwriting_privacy_info": { - "message": "V\u00e1\u0161 vstup sa odo\u0161le na server Google, kde sa zadan\u00fd text rozpozn\u00e1" + "message": "V\u00e1\u0161 vstup sa odo\u0161le na servery Google, kde sa zadan\u00fd text rozpozn\u00e1" }, "hide_keyboard": { "message": "skry\u0165 kl\u00e1vesnicu" @@ -2634,7 +2634,7 @@ "message": "Ignorova\u0165 opravu pre" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignorova\u0165 opravu" }, "il_heb_settings_page": { "message": "Str\u00e1nka s nastaveniami hebrejskej kl\u00e1vesnice" @@ -3300,7 +3300,7 @@ "message": "Hlas" }, "voice_privacy_info": { - "message": "V\u00e1\u0161 hlas bude odoslan\u00fd na server Google, aby sme rozpoznali text." + "message": "V\u00e1\u0161 hlasov\u00fd vstup sa odo\u0161le na servery Google, kde sa zadan\u00fd text rozpozn\u00e1" }, "voice_turn_off": { "message": "vypn\u00fa\u0165 n\u00e1stroj na zad\u00e1vanie hlasov\u00fdch vstupov"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sl/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sl/messages.json index bba5c5e..67c89f2 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sl/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sl/messages.json
@@ -2616,7 +2616,7 @@ "message": "Uporaba rokopisa ni mogo\u010da, ker omre\u017eje ni na voljo." }, "handwriting_privacy_info": { - "message": "Va\u0161 vnos bo poslan v Googlov stre\u017enik zaradi prepoznave besedila" + "message": "Va\u0161 vnos bo poslan v Googlove stre\u017enike zaradi prepoznave besedila." }, "hide_keyboard": { "message": "skrij tipkovnico" @@ -2634,7 +2634,7 @@ "message": "Prezri popravek za" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Prezri popravek" }, "il_heb_settings_page": { "message": "Stran z nastavitvami hebrejske tipkovnice" @@ -3300,7 +3300,7 @@ "message": "Glasovne nastavitve" }, "voice_privacy_info": { - "message": "Va\u0161 glas bo poslan v Googlov stre\u017enik zaradi prepoznave besedila" + "message": "Va\u0161 glasovni vnos bo poslan v Googlove stre\u017enike zaradi prepoznave besedila." }, "voice_turn_off": { "message": "izklop orodja za glasovni vnos"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sr/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sr/messages.json index 3e4dea60..0fd1a5c 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sr/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sr/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u0416\u0430\u043e \u043d\u0430\u043c \u0458\u0435, \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u043a\u043e\u0440\u0438\u0441\u0442\u0438\u0442\u0435 \u0440\u0443\u043a\u043e\u043f\u0438\u0441 \u0458\u0435\u0440 \u0458\u0435 \u043c\u0440\u0435\u0436\u0430 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430." }, "handwriting_privacy_info": { - "message": "\u0423\u043d\u043e\u0441 \u045b\u0435 \u0431\u0438\u0442\u0438 \u043f\u043e\u0441\u043b\u0430\u0442 \u043d\u0430 Google \u0441\u0435\u0440\u0432\u0435\u0440 \u0440\u0430\u0434\u0438 \u043f\u0440\u0435\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u045a\u0430 \u0442\u0435\u043a\u0441\u0442\u0430" + "message": "\u0423\u043d\u043e\u0441 \u045b\u0435 \u0431\u0438\u0442\u0438 \u043f\u043e\u0441\u043b\u0430\u0442 \u043d\u0430 Google \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0440\u0430\u0434\u0438 \u043f\u0440\u0435\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u045a\u0430 \u0442\u0435\u043a\u0441\u0442\u0430." }, "hide_keyboard": { "message": "\u0441\u0430\u043a\u0440\u0438\u0458 \u0442\u0430\u0441\u0442\u0430\u0442\u0443\u0440\u0443" @@ -2634,7 +2634,7 @@ "message": "\u0417\u0430\u043d\u0435\u043c\u0430\u0440\u0438 \u0438\u0441\u043f\u0440\u0430\u0432\u043a\u0443 \u0437\u0430" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u0417\u0430\u043d\u0435\u043c\u0430\u0440\u0438 \u0438\u0441\u043f\u0440\u0430\u0432\u043a\u0443" }, "il_heb_settings_page": { "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441\u0430 \u043f\u043e\u0434\u0435\u0448\u0430\u0432\u0430\u045a\u0438\u043c\u0430 \u0445\u0435\u0431\u0440\u0435\u0458\u0441\u043a\u0435 \u0442\u0430\u0441\u0442\u0430\u0442\u0443\u0440\u0435" @@ -3300,7 +3300,7 @@ "message": "\u0413\u043b\u0430\u0441" }, "voice_privacy_info": { - "message": "\u0412\u0430\u0448 \u0433\u043b\u0430\u0441 \u045b\u0435 \u0431\u0438\u0442\u0438 \u043f\u043e\u0441\u043b\u0430\u0442 \u043d\u0430 Google \u0441\u0435\u0440\u0432\u0435\u0440 \u0440\u0430\u0434\u0438 \u043f\u0440\u0435\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u045a\u0430 \u0442\u0435\u043a\u0441\u0442\u0430" + "message": "\u0413\u043b\u0430\u0441\u043e\u0432\u043d\u0438 \u0443\u043d\u043e\u0441 \u045b\u0435 \u0431\u0438\u0442\u0438 \u043f\u043e\u0441\u043b\u0430\u0442 \u043d\u0430 Google \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0440\u0430\u0434\u0438 \u043f\u0440\u0435\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u045a\u0430 \u0442\u0435\u043a\u0441\u0442\u0430." }, "voice_turn_off": { "message": "\u0438\u0441\u043a\u0459\u0443\u0447\u0438 \u0430\u043b\u0430\u0442\u043a\u0443 \u0437\u0430 \u0433\u043b\u0430\u0441\u043e\u0432\u043d\u0438 \u0443\u043d\u043e\u0441"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sv/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sv/messages.json index 75b5ae2..cbb84ec0 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sv/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sv/messages.json
@@ -2616,7 +2616,7 @@ "message": "Eftersom n\u00e4tverket inte \u00e4r tillg\u00e4ngligt kan du tyv\u00e4rr inte skriva f\u00f6r hand." }, "handwriting_privacy_info": { - "message": "Inmatningen skickas till en av Googles servrar f\u00f6r textigenk\u00e4nning" + "message": "Inmatningen skickas till Googles servrar f\u00f6r textigenk\u00e4nning." }, "hide_keyboard": { "message": "d\u00f6lj tangentbord" @@ -2634,7 +2634,7 @@ "message": "Ignorera korrigeringen av" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Ignorera korrigeringen" }, "il_heb_settings_page": { "message": "Inst\u00e4llningssidan f\u00f6r hebreiskt tangentbord" @@ -3300,7 +3300,7 @@ "message": "R\u00f6st" }, "voice_privacy_info": { - "message": "R\u00f6stinmatningen skickas till en av Googles servrar f\u00f6r att identifiera text" + "message": "R\u00f6stinmatningen skickas till Googles servrar f\u00f6r textigenk\u00e4nning." }, "voice_turn_off": { "message": "inaktivera verktyg f\u00f6r r\u00f6stinmatning"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sw/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sw/messages.json index 073a1c1..f5c9474 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sw/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sw/messages.json
@@ -2616,7 +2616,7 @@ "message": "Samahani, huwezi kutumia mwandiko, kwa sababu mtandao haupatikani." }, "handwriting_privacy_info": { - "message": "Uingizaji wako utatumwa kwenye seva ya Google ili kuyatambua maandishi" + "message": "Uingizaji wako utatumwa kwenye seva za Google ili kuyatambua maandishi." }, "hide_keyboard": { "message": "ficha kibodi" @@ -2634,7 +2634,7 @@ "message": "Puuza usahihishaji wa neno" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "Puuza usahihishaji wa neno" }, "il_heb_settings_page": { "message": "Ukurasa wa Mipangilio ya Kibodi ya Kiyahudi" @@ -3300,7 +3300,7 @@ "message": "Sauti" }, "voice_privacy_info": { - "message": "Sauti yako itatumwa kwenye seva ya Google ili kutambua maandishi" + "message": "Kuweka kwako data kwa kutamka kutatumwa kwenye seva za Google ili kutambua maandishi." }, "voice_turn_off": { "message": "zima zana ya kuweka data kwa kutamka"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ta/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ta/messages.json index 848cabf6f..25a95b13 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ta/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ta/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u0bae\u0ba9\u0bcd\u0ba9\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd, \u0ba8\u0bc6\u0b9f\u0bcd\u0bb5\u0bca\u0bb0\u0bcd\u0b95\u0bcd \u0b87\u0bb2\u0bcd\u0bb2\u0bc8 \u0b8e\u0ba9\u0bcd\u0baa\u0ba4\u0bbe\u0bb2\u0bcd \u0b95\u0bc8\u0baf\u0bc6\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bc8\u0baa\u0bcd \u0baa\u0baf\u0ba9\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4 \u0bae\u0bc1\u0b9f\u0bbf\u0baf\u0bbe\u0ba4\u0bc1." }, "handwriting_privacy_info": { - "message": "\u0b89\u0bb0\u0bc8\u0baf\u0bc8 \u0b85\u0b9f\u0bc8\u0baf\u0bbe\u0bb3\u0bae\u0bcd \u0b95\u0bbe\u0ba3, \u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b89\u0bb3\u0bcd\u0bb3\u0bc0\u0b9f\u0bc1 Google \u0b9a\u0bc7\u0bb5\u0bc8\u0baf\u0b95\u0ba4\u0bcd\u0ba4\u0bc1\u0b95\u0bcd\u0b95\u0bc1 \u0b85\u0ba9\u0bc1\u0baa\u0bcd\u0baa\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0bae\u0bcd" + "message": "\u0b89\u0bb0\u0bc8\u0baf\u0bc8 \u0b85\u0b9f\u0bc8\u0baf\u0bbe\u0bb3\u0b99\u0bcd\u0b95\u0bbe\u0ba3, \u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b89\u0bb3\u0bcd\u0bb3\u0bc0\u0b9f\u0bc1 Google \u0b9a\u0bc7\u0bb5\u0bc8\u0baf\u0b95\u0b99\u0bcd\u0b95\u0bb3\u0bc1\u0b95\u0bcd\u0b95\u0bc1 \u0b85\u0ba9\u0bc1\u0baa\u0bcd\u0baa\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0bae\u0bcd." }, "hide_keyboard": { "message": "\u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0bc8\u0b95\u0bc8\u0baf\u0bc8 \u0bae\u0bb1\u0bc8\u0b95\u0bcd\u0b95\u0bc1\u0bae\u0bcd" @@ -2634,7 +2634,7 @@ "message": "\u0b87\u0ba8\u0bcd\u0ba4\u0b9a\u0bcd \u0b9a\u0bca\u0bb2\u0bcd\u0bb2\u0bbf\u0ba9\u0bcd \u0ba4\u0bbf\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0ba4\u0bcd\u0ba4\u0bc8\u0ba4\u0bcd \u0ba4\u0bb5\u0bbf\u0bb0\u0bcd" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u0ba4\u0bbf\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0ba4\u0bcd\u0ba4\u0bc8\u0ba4\u0bcd \u0ba4\u0bb5\u0bbf\u0bb0\u0bcd" }, "il_heb_settings_page": { "message": "\u0bb9\u0bc0\u0baa\u0bcd\u0bb0\u0bc1 \u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0b95\u0bc8 \u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd \u0baa\u0b95\u0bcd\u0b95\u0bae\u0bcd" @@ -3300,7 +3300,7 @@ "message": "\u0b95\u0bc1\u0bb0\u0bb2\u0bcd" }, "voice_privacy_info": { - "message": "\u0b89\u0bb0\u0bc8\u0baf\u0bc8\u0b95\u0bcd \u0b95\u0ba3\u0bcd\u0b9f\u0bb1\u0bbf\u0bb5\u0ba4\u0bb1\u0bcd\u0b95\u0bbe\u0b95 \u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b95\u0bc1\u0bb0\u0bb2\u0bcd Google \u0b9a\u0bc7\u0bb5\u0bc8\u0baf\u0b95\u0ba4\u0bcd\u0ba4\u0bbf\u0bb1\u0bcd\u0b95\u0bc1 \u0b85\u0ba9\u0bc1\u0baa\u0bcd\u0baa\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0bae\u0bcd." + "message": "\u0b89\u0bb0\u0bc8\u0baf\u0bc8 \u0b85\u0b9f\u0bc8\u0baf\u0bbe\u0bb3\u0b99\u0bcd\u0b95\u0bbe\u0ba3, \u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b95\u0bc1\u0bb0\u0bb2\u0bcd \u0b89\u0bb3\u0bcd\u0bb3\u0bc0\u0b9f\u0bc1 Google \u0b9a\u0bc7\u0bb5\u0bc8\u0baf\u0b95\u0b99\u0bcd\u0b95\u0bb3\u0bc1\u0b95\u0bcd\u0b95\u0bc1 \u0b85\u0ba9\u0bc1\u0baa\u0bcd\u0baa\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0bae\u0bcd." }, "voice_turn_off": { "message": "\u0b95\u0bc1\u0bb0\u0bb2\u0bcd \u0b89\u0bb3\u0bcd\u0bb3\u0bc0\u0b9f\u0bcd\u0b9f\u0bc1\u0b95\u0bcd \u0b95\u0bb0\u0bc1\u0bb5\u0bbf\u0baf\u0bc8 \u0bae\u0bc1\u0b9f\u0b95\u0bcd\u0b95\u0bc1"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/te/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/te/messages.json index 83ad0360..01fafd9 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/te/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/te/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u0c15\u0c4d\u0c37\u0c2e\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f, \u0c28\u0c46\u0c1f\u0c4d\u200c\u0c35\u0c30\u0c4d\u0c15\u0c4d \u0c05\u0c02\u0c26\u0c41\u0c2c\u0c3e\u0c1f\u0c41\u0c32\u0c4b \u0c32\u0c47\u0c28\u0c02\u0c26\u0c41\u0c28 \u0c2e\u0c40\u0c30\u0c41 \u0c1a\u0c47\u0c24\u0c3f\u0c35\u0c4d\u0c30\u0c3e\u0c24\u0c28\u0c41 \u0c09\u0c2a\u0c2f\u0c4b\u0c17\u0c3f\u0c02\u0c1a\u0c32\u0c47\u0c30\u0c41." }, "handwriting_privacy_info": { - "message": "\u0c35\u0c1a\u0c28\u0c3e\u0c28\u0c4d\u0c28\u0c3f \u0c17\u0c41\u0c30\u0c4d\u0c24\u0c3f\u0c02\u0c1a\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2e\u0c40 \u0c07\u0c28\u0c4d\u200c\u0c2a\u0c41\u0c1f\u0c4d Google \u0c38\u0c30\u0c4d\u0c35\u0c30\u0c4d\u200c\u0c15\u0c41 \u0c2a\u0c02\u0c2a\u0c2c\u0c21\u0c41\u0c24\u0c41\u0c02\u0c26\u0c3f" + "message": "\u0c35\u0c1a\u0c28\u0c3e\u0c28\u0c4d\u0c28\u0c3f \u0c17\u0c41\u0c30\u0c4d\u0c24\u0c3f\u0c02\u0c1a\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f Google \u0c38\u0c30\u0c4d\u0c35\u0c30\u0c4d\u200c\u0c32\u0c15\u0c41 \u0c2e\u0c40 \u0c07\u0c28\u0c4d\u200c\u0c2a\u0c41\u0c1f\u0c4d \u0c2a\u0c02\u0c2a\u0c2c\u0c21\u0c41\u0c24\u0c41\u0c02\u0c26\u0c3f." }, "hide_keyboard": { "message": "\u0c15\u0c40\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d\u200c\u0c28\u0c41 \u0c26\u0c3e\u0c1a\u0c02\u0c21\u0c3f" @@ -2634,7 +2634,7 @@ "message": "\u0c26\u0c40\u0c28\u0c3f \u0c26\u0c3f\u0c26\u0c4d\u0c26\u0c41\u0c2c\u0c3e\u0c1f\u0c41\u0c28\u0c3f \u0c35\u0c3f\u0c38\u0c4d\u0c2e\u0c30\u0c3f\u0c02\u0c1a\u0c41" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u0c26\u0c3f\u0c26\u0c4d\u0c26\u0c41\u0c2c\u0c3e\u0c1f\u0c41\u0c28\u0c3f \u0c35\u0c3f\u0c38\u0c4d\u0c2e\u0c30\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f" }, "il_heb_settings_page": { "message": "\u0c39\u0c3f\u0c2c\u0c4d\u0c30\u0c42 \u0c15\u0c40\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d \u0c38\u0c46\u0c1f\u0c4d\u0c1f\u0c3f\u0c02\u0c17\u0c4d\u200c\u0c32 \u0c2a\u0c47\u0c1c\u0c40" @@ -3300,7 +3300,7 @@ "message": "\u0c35\u0c3e\u0c2f\u0c3f\u0c38\u0c4d" }, "voice_privacy_info": { - "message": "\u0c2e\u0c40 \u0c35\u0c3e\u0c2f\u0c3f\u0c38\u0c4d \u0c35\u0c1a\u0c28 \u0c17\u0c41\u0c30\u0c4d\u0c24\u0c3f\u0c02\u0c2a\u0c41 \u0c15\u0c4b\u0c38\u0c02 Google \u0c38\u0c30\u0c4d\u0c35\u0c30\u0c4d\u200c\u0c15\u0c3f \u0c2a\u0c02\u0c2a\u0c2c\u0c21\u0c41\u0c24\u0c41\u0c02\u0c26\u0c3f" + "message": "\u0c35\u0c1a\u0c28\u0c3e\u0c28\u0c4d\u0c28\u0c3f \u0c17\u0c41\u0c30\u0c4d\u0c24\u0c3f\u0c02\u0c1a\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f Google \u0c38\u0c30\u0c4d\u0c35\u0c30\u0c4d\u200c\u0c32\u0c15\u0c41 \u0c2e\u0c40 \u0c35\u0c3e\u0c2f\u0c3f\u0c38\u0c4d \u0c07\u0c28\u0c4d\u200c\u0c2a\u0c41\u0c1f\u0c4d \u0c2a\u0c02\u0c2a\u0c2c\u0c21\u0c41\u0c24\u0c41\u0c02\u0c26\u0c3f." }, "voice_turn_off": { "message": "\u0c35\u0c3e\u0c2f\u0c3f\u0c38\u0c4d \u0c07\u0c28\u0c4d\u200c\u0c2a\u0c41\u0c1f\u0c4d \u0c38\u0c3e\u0c27\u0c28\u0c3e\u0c28\u0c4d\u0c28\u0c3f \u0c06\u0c2b\u0c4d \u0c1a\u0c47\u0c2f\u0c3f"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/th/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/th/messages.json index 956c7cf..c062713 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/th/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/th/messages.json
@@ -2634,7 +2634,7 @@ "message": "\u0e25\u0e30\u0e40\u0e27\u0e49\u0e19\u0e01\u0e32\u0e23\u0e41\u0e01\u0e49\u0e44\u0e02\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u0e25\u0e30\u0e40\u0e27\u0e49\u0e19\u0e01\u0e32\u0e23\u0e41\u0e01\u0e49\u0e44\u0e02" }, "il_heb_settings_page": { "message": "\u0e2b\u0e19\u0e49\u0e32\u0e01\u0e32\u0e23\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32\u0e41\u0e1b\u0e49\u0e19\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e20\u0e32\u0e29\u0e32\u0e2e\u0e35\u0e1a\u0e23\u0e39" @@ -3300,7 +3300,7 @@ "message": "\u0e40\u0e2a\u0e35\u0e22\u0e07" }, "voice_privacy_info": { - "message": "\u0e23\u0e30\u0e1a\u0e1a\u0e08\u0e30\u0e2a\u0e48\u0e07\u0e40\u0e2a\u0e35\u0e22\u0e07\u0e02\u0e2d\u0e07\u0e04\u0e38\u0e13\u0e44\u0e1b\u0e22\u0e31\u0e07\u0e40\u0e0b\u0e34\u0e23\u0e4c\u0e1f\u0e40\u0e27\u0e2d\u0e23\u0e4c Google \u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e08\u0e14\u0e08\u0e33\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21" + "message": "\u0e23\u0e30\u0e1a\u0e1a\u0e08\u0e30\u0e2a\u0e48\u0e07\u0e40\u0e2a\u0e35\u0e22\u0e07\u0e17\u0e35\u0e48\u0e04\u0e38\u0e13\u0e1b\u0e49\u0e2d\u0e19\u0e44\u0e1b\u0e22\u0e31\u0e07\u0e40\u0e0b\u0e34\u0e23\u0e4c\u0e1f\u0e40\u0e27\u0e2d\u0e23\u0e4c\u0e02\u0e2d\u0e07 Google \u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e08\u0e14\u0e08\u0e33\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21" }, "voice_turn_off": { "message": "\u0e1b\u0e34\u0e14\u0e40\u0e04\u0e23\u0e37\u0e48\u0e2d\u0e07\u0e21\u0e37\u0e2d\u0e1b\u0e49\u0e2d\u0e19\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e14\u0e49\u0e27\u0e22\u0e40\u0e2a\u0e35\u0e22\u0e07"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/tr/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/tr/messages.json index 4620db2..f1f38f2 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/tr/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/tr/messages.json
@@ -2616,7 +2616,7 @@ "message": "A\u011f ba\u011flant\u0131s\u0131 olmad\u0131\u011f\u0131ndan maalesef el yaz\u0131s\u0131n\u0131 kullanamazs\u0131n\u0131z." }, "handwriting_privacy_info": { - "message": "Giri\u015finiz, metnin tan\u0131nmas\u0131 i\u00e7in bir Google sunucusuna g\u00f6nderilecek" + "message": "Giri\u015finiz, metnin tan\u0131nmas\u0131 i\u00e7in Google sunucular\u0131na g\u00f6nderilecektir." }, "hide_keyboard": { "message": "klavyeyi gizle" @@ -2634,7 +2634,7 @@ "message": "\u015eu kelime i\u00e7in d\u00fczeltmeyi yoksay" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "D\u00fczeltmeyi yoksay" }, "il_heb_settings_page": { "message": "\u0130branice Klavye Ayarlar\u0131 Sayfas\u0131" @@ -3300,7 +3300,7 @@ "message": "Ses" }, "voice_privacy_info": { - "message": "Metni tan\u0131mak i\u00e7in sesiniz bir Google sunucusuna g\u00f6nderilecektir" + "message": "Ses giri\u015finiz, metnin tan\u0131nmas\u0131 i\u00e7in Google sunucular\u0131na g\u00f6nderilecektir." }, "voice_turn_off": { "message": "ses giri\u015fi arac\u0131n\u0131 kapat"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/uk/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/uk/messages.json index 3dbd1f2..0ce164e0 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/uk/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/uk/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u041d\u0430 \u0436\u0430\u043b\u044c, \u043d\u0435 \u0432\u0434\u0430\u0454\u0442\u044c\u0441\u044f \u0441\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u0442\u0438\u0441\u044f \u0440\u0443\u043a\u043e\u043f\u0438\u0441\u043d\u0438\u043c \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044f\u043c, \u043e\u0441\u043a\u0456\u043b\u044c\u043a\u0438 \u043c\u0435\u0440\u0435\u0436\u0430 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430." }, "handwriting_privacy_info": { - "message": "\u0412\u0432\u0435\u0434\u0435\u043d\u0456 \u0434\u0430\u043d\u0456 \u0431\u0443\u0434\u0435 \u043d\u0430\u0434\u0456\u0441\u043b\u0430\u043d\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 Google \u0434\u043b\u044f \u0440\u043e\u0437\u043f\u0456\u0437\u043d\u0430\u0432\u0430\u043d\u043d\u044f \u0442\u0435\u043a\u0441\u0442\u0443" + "message": "\u0412\u0432\u0435\u0434\u0435\u043d\u0456 \u0434\u0430\u043d\u0456 \u0431\u0443\u0434\u0435 \u043d\u0430\u0434\u0456\u0441\u043b\u0430\u043d\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0438 Google \u0434\u043b\u044f \u0440\u043e\u0437\u043f\u0456\u0437\u043d\u0430\u0432\u0430\u043d\u043d\u044f \u0442\u0435\u043a\u0441\u0442\u0443." }, "hide_keyboard": { "message": "\u0441\u0445\u043e\u0432\u0430\u0442\u0438 \u043a\u043b\u0430\u0432\u0456\u0430\u0442\u0443\u0440\u0443" @@ -2634,7 +2634,7 @@ "message": "\u0406\u0433\u043d\u043e\u0440\u0443\u0432\u0430\u0442\u0438 \u0432\u0438\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044f \u0441\u043b\u043e\u0432\u0430" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u0406\u0433\u043d\u043e\u0440\u0443\u0432\u0430\u0442\u0438 \u0432\u0438\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044f" }, "il_heb_settings_page": { "message": "\u0421\u0442\u043e\u0440\u0456\u043d\u043a\u0430 \u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u044c \u043a\u043b\u0430\u0432\u0456\u0430\u0442\u0443\u0440\u0438 \u0434\u043b\u044f \u0456\u0432\u0440\u0438\u0442\u0443" @@ -3300,7 +3300,7 @@ "message": "\u0413\u043e\u043b\u043e\u0441\u043e\u0432\u0435 \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044f" }, "voice_privacy_info": { - "message": "\u0417\u0430\u043f\u0438\u0441 \u0432\u0430\u0448\u043e\u0433\u043e \u0433\u043e\u043b\u043e\u0441\u0443 \u0431\u0443\u0434\u0435 \u043d\u0430\u0434\u0456\u0441\u043b\u0430\u043d\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 Google \u0434\u043b\u044f \u0440\u043e\u0437\u043f\u0456\u0437\u043d\u0430\u0432\u0430\u043d\u043d\u044f \u0442\u0435\u043a\u0441\u0442\u0443" + "message": "\u0412\u0432\u0435\u0434\u0435\u043d\u0456 \u0433\u043e\u043b\u043e\u0441\u043e\u043c \u0434\u0430\u043d\u0456 \u0431\u0443\u0434\u0435 \u043d\u0430\u0434\u0456\u0441\u043b\u0430\u043d\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0438 Google \u0434\u043b\u044f \u0440\u043e\u0437\u043f\u0456\u0437\u043d\u0430\u0432\u0430\u043d\u043d\u044f \u0442\u0435\u043a\u0441\u0442\u0443." }, "voice_turn_off": { "message": "\u0432\u0438\u043c\u043a\u043d\u0443\u0442\u0438 \u0456\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0433\u043e\u043b\u043e\u0441\u043e\u0432\u043e\u0433\u043e \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044f"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/vi/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/vi/messages.json index 337df5f..fd53055 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/vi/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/vi/messages.json
@@ -2616,7 +2616,7 @@ "message": "R\u1ea5t ti\u1ebfc, b\u1ea1n kh\u00f4ng th\u1ec3 s\u1eed d\u1ee5ng ch\u1eef vi\u1ebft tay v\u00ec kh\u00f4ng c\u00f3 m\u1ea1ng." }, "handwriting_privacy_info": { - "message": "D\u1eef li\u1ec7u b\u1ea1n nh\u1eadp s\u1ebd \u0111\u01b0\u1ee3c g\u1eedi t\u1edbi m\u00e1y ch\u1ee7 c\u1ee7a Google \u0111\u1ec3 nh\u1eadn d\u1ea1ng v\u0103n b\u1ea3n" + "message": "D\u1eef li\u1ec7u b\u1ea1n nh\u1eadp s\u1ebd \u0111\u01b0\u1ee3c g\u1eedi t\u1edbi m\u00e1y ch\u1ee7 c\u1ee7a Google \u0111\u1ec3 nh\u1eadn d\u1ea1ng v\u0103n b\u1ea3n." }, "hide_keyboard": { "message": "\u1ea9n b\u00e0n ph\u00edm" @@ -2634,7 +2634,7 @@ "message": "B\u1ecf qua t\u00ednh n\u0103ng s\u1eeda cho" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "B\u1ecf qua t\u00ednh n\u0103ng s\u1eeda" }, "il_heb_settings_page": { "message": "Trang c\u00e0i \u0111\u1eb7t b\u00e0n ph\u00edm ti\u1ebfng Do Th\u00e1i" @@ -3300,7 +3300,7 @@ "message": "Gi\u1ecdng n\u00f3i" }, "voice_privacy_info": { - "message": "Gi\u1ecdng n\u00f3i c\u1ee7a b\u1ea1n s\u1ebd \u0111\u01b0\u1ee3c g\u1eedi t\u1edbi m\u00e1y ch\u1ee7 Google \u0111\u1ec3 nh\u1eadn d\u1ea1ng v\u0103n b\u1ea3n" + "message": "Nh\u1eadp b\u1eb1ng gi\u1ecdng n\u00f3i s\u1ebd \u0111\u01b0\u1ee3c g\u1eedi t\u1edbi m\u00e1y ch\u1ee7 c\u1ee7a Google \u0111\u1ec3 nh\u1eadn d\u1ea1ng v\u0103n b\u1ea3n." }, "voice_turn_off": { "message": "t\u1eaft c\u00f4ng c\u1ee5 nh\u1eadp b\u1eb1ng gi\u1ecdng n\u00f3i"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_CN/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_CN/messages.json index b099646..dbea84d 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_CN/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_CN/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u62b1\u6b49\uff0c\u7531\u4e8e\u7f51\u7edc\u4e2d\u65ad\uff0c\u60a8\u65e0\u6cd5\u4f7f\u7528\u624b\u5199\u5de5\u5177\u3002" }, "handwriting_privacy_info": { - "message": "\u60a8\u8f93\u5165\u7684\u5185\u5bb9\u5c06\u53d1\u9001\u81f3 Google \u670d\u52a1\u5668\u8fdb\u884c\u6587\u5b57\u8bc6\u522b" + "message": "\u60a8\u8f93\u5165\u7684\u5185\u5bb9\u5c06\u53d1\u9001\u81f3 Google \u670d\u52a1\u5668\u8fdb\u884c\u6587\u5b57\u8bc6\u522b\u3002" }, "hide_keyboard": { "message": "\u9690\u85cf\u952e\u76d8" @@ -2634,7 +2634,7 @@ "message": "\u4e0d\u81ea\u52a8\u66f4\u6b63\u4ee5\u4e0b\u5b57\u8bcd\uff1a" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u4e0d\u81ea\u52a8\u66f4\u6b63" }, "il_heb_settings_page": { "message": "\u5e0c\u4f2f\u6765\u8bed\u952e\u76d8\u8bbe\u7f6e\u9875\u9762" @@ -3300,7 +3300,7 @@ "message": "\u8bed\u97f3" }, "voice_privacy_info": { - "message": "\u60a8\u6240\u8bf4\u7684\u5185\u5bb9\u5c06\u53d1\u9001\u81f3 Google \u670d\u52a1\u5668\u8fdb\u884c\u6587\u5b57\u8bc6\u522b" + "message": "\u60a8\u4f7f\u7528\u8bed\u97f3\u8f93\u5165\u7684\u5185\u5bb9\u5c06\u53d1\u9001\u81f3 Google \u670d\u52a1\u5668\u8fdb\u884c\u6587\u5b57\u8bc6\u522b\u3002" }, "voice_turn_off": { "message": "\u5173\u95ed\u8bed\u97f3\u8f93\u5165\u5de5\u5177"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_TW/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_TW/messages.json index 5df93fc..e3d96f3 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_TW/messages.json +++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_TW/messages.json
@@ -2616,7 +2616,7 @@ "message": "\u5f88\u62b1\u6b49\uff0c\u76ee\u524d\u672a\u9023\u7dda\u81f3\u7db2\u8def\uff0c\u56e0\u6b64\u7121\u6cd5\u8b93\u60a8\u4f7f\u7528\u624b\u5beb\u8f38\u5165\u3002" }, "handwriting_privacy_info": { - "message": "\u60a8\u7684\u8f38\u5165\u5167\u5bb9\u5c07\u50b3\u9001\u81f3 Google \u4f3a\u670d\u5668\uff0c\u7528\u65bc\u8fa8\u8b58\u6587\u5b57" + "message": "\u60a8\u8f38\u5165\u7684\u5167\u5bb9\u5c07\u50b3\u9001\u5230 Google \u4f3a\u670d\u5668\u9032\u884c\u6587\u5b57\u8fa8\u8b58\u3002" }, "hide_keyboard": { "message": "\u96b1\u85cf\u9375\u76e4" @@ -2634,7 +2634,7 @@ "message": "\u4e0d\u66f4\u6b63\u4ee5\u4e0b\u5b57\u8a5e\uff1a" }, "ignore_correction_short": { - "message": "Ignore correction" + "message": "\u4e0d\u9032\u884c\u66f4\u6b63" }, "il_heb_settings_page": { "message": "\u5e0c\u4f2f\u4f86\u6587\u9375\u76e4\u8a2d\u5b9a\u9801\u9762" @@ -3300,7 +3300,7 @@ "message": "\u8a9e\u97f3" }, "voice_privacy_info": { - "message": "Chrome \u6703\u5c07\u60a8\u7684\u8a9e\u97f3\u50b3\u9001\u5230 Google \u4f3a\u670d\u5668\uff0c\u7528\u65bc\u8fa8\u8b58\u6587\u5b57" + "message": "\u60a8\u8f38\u5165\u7684\u8a9e\u97f3\u5167\u5bb9\u5c07\u50b3\u9001\u5230 Google \u4f3a\u670d\u5668\u9032\u884c\u6587\u5b57\u8fa8\u8b58\u3002" }, "voice_turn_off": { "message": "\u95dc\u9589\u8a9e\u97f3\u8f38\u5165\u5de5\u5177"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/adapter.js b/third_party/google_input_tools/src/chrome/os/inputview/adapter.js index bee4f683e..b6664780 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/adapter.js +++ b/third_party/google_input_tools/src/chrome/os/inputview/adapter.js
@@ -117,10 +117,6 @@ /** @type {boolean} */ -Adapter.prototype.isExperimental = false; - - -/** @type {boolean} */ Adapter.prototype.isVoiceInputEnabled = true; @@ -386,6 +382,7 @@ return this.features.isEnabled(FeatureName.GESTURE_TYPING); }; + /** * Callback when blurs in the context. * @@ -495,7 +492,6 @@ if (window.inputview) { inputview.getKeyboardConfig((function(config) { this.isA11yMode = !!config['a11ymode']; - this.isExperimental = !!config['experimental']; this.features.initialize(config); this.readyState_.markStateReady(StateType.KEYBOARD_CONFIG_READY); this.maybeDispatchSettingsReadyEvent_(); @@ -606,7 +602,6 @@ chrome.runtime.sendMessage(goog.object.create( Name.TYPE, Type.VISIBILITY_CHANGE, Name.VISIBILITY, !document.webkitHidden, - Name.IS_EXPERIMENTAL, this.isExperimental, Name.WORKSPACE_HEIGHT, screen.height - window.innerHeight)); };
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/common.css b/third_party/google_input_tools/src/chrome/os/inputview/common.css index fc84723..5521c88 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/common.css +++ b/third_party/google_input_tools/src/chrome/os/inputview/common.css
@@ -286,14 +286,18 @@ color: #111111; } .inputview-candidate-view { - overflow: hidden; display: table-cell; - height: 32px; + overflow: hidden; + position: relative; } -.inputview-toolbar-button, -.inputview-candidate-button { +.inputview-toolbar-button { float: right; } +.inputview-candidate-button { + position: absolute; + right: 0; + top: 0; +} .inputview-toolbar-button.float-left { float: left; }
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/config/compact_letter_characters.js b/third_party/google_input_tools/src/chrome/os/inputview/config/compact_letter_characters.js index ad099b93..b81b135 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/config/compact_letter_characters.js +++ b/third_party/google_input_tools/src/chrome/os/inputview/config/compact_letter_characters.js
@@ -89,8 +89,10 @@ { 'email' : { 'text' : '@' }}}, /* 36 */ NonLetterKeys.SPACE, /* 37 */ { 'text': ',', 'isGrey': true, 'onContext': - { 'email' : {'text' : '.com', 'textCssClass' : Css.FONT_SMALL }, - 'url' : {'text' : '.com', 'textCssClass' : Css.FONT_SMALL }}}, + { 'email' : {'text' : '.com', 'textCssClass' : Css.FONT_SMALL, + 'moreKeys': {'characters': ['.net', '.org']}}, + 'url' : {'text' : '.com', 'textCssClass' : Css.FONT_SMALL, + 'moreKeys': {'characters': ['.net', '.org']}}}}, /* 38 */ { 'text': '.', 'isGrey': true, 'moreKeys': { 'characters': [',', '\'', '#', ')', '(', '/', ';', '@', ':',
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/controller.js b/third_party/google_input_tools/src/chrome/os/inputview/controller.js index 52b65d7..6d4bc10 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/controller.js +++ b/third_party/google_input_tools/src/chrome/os/inputview/controller.js
@@ -601,7 +601,8 @@ newKeyset = /** @type {string} */ (this.model_.settings. getPreference(util.getConfigName(keysetMap[ContextType.DEFAULT]))); } - if (!this.adapter_.isExperimental && keysetMap[ContextType.DEFAULT] == + if (!this.adapter_.features.isEnabled(FeatureName.EXPERIMENTAL) && + keysetMap[ContextType.DEFAULT] == 'zhuyin.compact.qwerty') { newKeyset = 'zhuyin'; } @@ -739,7 +740,7 @@ */ Controller.prototype.onDragEvent_ = function(e) { if (this.adapter_.isGestureTypingEnabled() && e.type == EventType.DRAG) { - this.container_.gestureCanvasView.addPointAndDraw(e); + this.container_.gestureCanvasView.addPoint(e); return; } }; @@ -846,8 +847,8 @@ */ Controller.prototype.handlePointerAction_ = function(view, e) { if (this.adapter_.isGestureTypingEnabled() && - e.type == EventType.POINTER_UP) { - this.container_.gestureCanvasView.clear(); + e.type == EventType.POINTER_DOWN) { + this.container_.gestureCanvasView.startStroke(e); } // Listen for DOUBLE_CLICK as well to capture secondary taps on the spacebar. @@ -1257,7 +1258,8 @@ var defaultFullKeyset = this.initialKeyset_.split(/\./)[0]; var enableCompact = !this.adapter_.isA11yMode && goog.array.contains( util.KEYSETS_HAVE_COMPACT, defaultFullKeyset); - if (defaultFullKeyset == 'zhuyin' && !this.adapter_.isExperimental || + if (defaultFullKeyset == 'zhuyin' && + !this.adapter_.features.isEnabled(FeatureName.EXPERIMENTAL) || this.languageCode_ == 'ko') { // Hides 'switch to compact' for zhuyin when not in experimental env. enableCompact = false;
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/css.js b/third_party/google_input_tools/src/chrome/os/inputview/css.js index 23ba9e5..87f657f 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/css.js +++ b/third_party/google_input_tools/src/chrome/os/inputview/css.js
@@ -21,6 +21,10 @@ */ i18n.input.chrome.inputview.Css = { A11Y: goog.getCssName('inputview-a11y'), + ACCENT_CONTAINER: goog.getCssName('inputview-accent-container'), + ACCENT_ROW: goog.getCssName('inputview-accent-row'), + ACCENT_EMPTY_KEY: goog.getCssName('inputview-accent-empty-key'), + ACCENT_KEY: goog.getCssName('inputview-accent-key'), ALTDATA_COVER: goog.getCssName('inputview-altdata-cover'), ALTDATA_KEY: goog.getCssName('inputview-altdata-key'), ALTDATA_SEPARATOR: goog.getCssName('inputview-altdata-separator'),
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/candidateview.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/candidateview.js index 4bbe45a..d3e1658 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/candidateview.js +++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/candidateview.js
@@ -232,6 +232,7 @@ var dom = this.getDomHelper(); var elem = this.getElement(); + goog.dom.classlist.add(elem, Css.CANDIDATE_VIEW); for (var i = 0; i < this.toolbarButtons_.length; i++) { var button = this.toolbarButtons_[i]; @@ -450,7 +451,6 @@ */ CandidateView.prototype.switchToIcon = function(type, visible) { for (var i = 0; i < this.iconButtons_.length; i++) { - // Don't enable voice when focus in password box. this.iconButtons_[i].setVisible(false); } @@ -459,6 +459,7 @@ this.iconButtons_[type].setVisible(true); } else if (this.adapter_.isVoiceInputEnabled && this.adapter_.contextType != 'password') { + // Don't enable voice when focus in password box. this.iconButtons_[type].setVisible(true); } } else if (this.adapter_.isVoiceInputEnabled &&
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/compactkey.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/compactkey.js index e027211..212e698e 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/compactkey.js +++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/compactkey.js
@@ -191,6 +191,8 @@ * Get the active character. It may be upper case |text| when shift is pressed * or flickerred character when swipe. Note this should replace Compactkey.text * for compact keys. + * + * @return {string} */ CompactKey.prototype.getActiveCharacter = function() { if (this.flickerredCharacter) { @@ -233,30 +235,39 @@ * @return {!Array.<string>} The characters. */ CompactKey.prototype.getMoreCharacters = function() { - var moreCharacters = goog.array.clone(this.compactKeyModel_.moreKeys); - switch (this.compactKeyModel_.moreKeysShiftOperation) { - case MoreKeysShiftOperation.TO_UPPER_CASE: - if (this.getActiveCharacter().toLowerCase() != - this.getActiveCharacter()) { - for (var i = 0; i < this.compactKeyModel_.moreKeys.length; i++) { - moreCharacters[i] = this.compactKeyModel_.moreKeys[i].toUpperCase(); + var context = this.stateManager_.contextType; + var contextMap = context && this.compactKeyModel_.textOnContext[context]; + if (contextMap && + contextMap[SpecNodeName.MORE_KEYS] && + contextMap[SpecNodeName.MORE_KEYS][SpecNodeName.CHARACTERS]) { + return goog.array.clone( + contextMap[SpecNodeName.MORE_KEYS][SpecNodeName.CHARACTERS]); + } else { + var moreCharacters = goog.array.clone(this.compactKeyModel_.moreKeys); + switch (this.compactKeyModel_.moreKeysShiftOperation) { + case MoreKeysShiftOperation.TO_UPPER_CASE: + if (this.getActiveCharacter().toLowerCase() != + this.getActiveCharacter()) { + for (var i = 0; i < this.compactKeyModel_.moreKeys.length; i++) { + moreCharacters[i] = this.compactKeyModel_.moreKeys[i].toUpperCase(); + } + goog.array.removeDuplicates(moreCharacters); } - goog.array.removeDuplicates(moreCharacters); - } - return moreCharacters; - case MoreKeysShiftOperation.TO_LOWER_CASE: - if (this.hasShift_ && this.stateManager_.hasState( - i18n.input.chrome.inputview.StateType.SHIFT)) { - for (var i = 0; i < this.compactKeyModel_.moreKeys.length; i++) { - moreCharacters[i] = this.compactKeyModel_.moreKeys[i].toLowerCase(); + return moreCharacters; + case MoreKeysShiftOperation.TO_LOWER_CASE: + if (this.hasShift_ && this.stateManager_.hasState( + i18n.input.chrome.inputview.StateType.SHIFT)) { + for (var i = 0; i < this.compactKeyModel_.moreKeys.length; i++) { + moreCharacters[i] = this.compactKeyModel_.moreKeys[i].toLowerCase(); + } + goog.array.removeDuplicates(moreCharacters); } - goog.array.removeDuplicates(moreCharacters); - } - return moreCharacters; - case MoreKeysShiftOperation.STABLE: - break; + return moreCharacters; + case MoreKeysShiftOperation.STABLE: + break; + } + return moreCharacters; } - return moreCharacters; };
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturecanvasview.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturecanvasview.js index 9f081a1..4661e2c 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturecanvasview.js +++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturecanvasview.js
@@ -12,6 +12,7 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // goog.provide('i18n.input.chrome.inputview.elements.content.GestureCanvasView'); +goog.provide('i18n.input.chrome.inputview.elements.content.GestureCanvasView.Point'); goog.require('goog.async.Delay'); goog.require('goog.dom.TagName'); @@ -57,11 +58,11 @@ this.drawingContext_; /** - * Drag events whose points should be drawn on the canvas. + * A list of list of gesture points to be rendered on the canvas as strokes. * - * @private {!Array} + * @private {!Array.<Array>} */ - this.dragEventList_ = []; + this.strokeList_ = []; /** @private {!goog.async.Delay} */ this.animator_ = new goog.async.Delay(this.animateGestureTrail_, 0, this); @@ -72,6 +73,14 @@ /** + * Rate at which the ttl should degrade for the fading stroke effect. + * + * @const {number} + */ +GestureCanvasView.DEGRADATION_RATE = 5; + + +/** * Draw the gesture trail. * * @private @@ -81,27 +90,30 @@ this.drawingContext_.clearRect( 0, 0, this.drawingCanvas_.width, this.drawingCanvas_.height); - // Event positions come in relative to the top of the entire content area, so - // grab the canvas offset in order to calculate the correct position to draw - // the strokes. - var offset = goog.style.getPageOffset(this.drawingCanvas_); + for (var i = 0; i < this.strokeList_.length; i++) { + var pointList = this.strokeList_[i]; - // Iterate through all the points and draw them. - for (var i = 1; i < this.dragEventList_.length; i++) { - // TODO(stevet): The following is a basic implementation of the trail - // rendering. This should be later be updated to be more efficient and - // support effects like fading. - var first = this.dragEventList_[i - 1]; - var second = this.dragEventList_[i]; - this.drawingContext_.beginPath(); - this.drawingContext_.strokeStyle = '#00B4CC'; - this.drawingContext_.fillStyle = 'none'; - this.drawingContext_.lineWidth = 8; - this.drawingContext_.lineCap = 'round'; - this.drawingContext_.lineJoin = 'round'; - this.drawingContext_.moveTo(first.x - offset.x, first.y - offset.y); - this.drawingContext_.lineTo(second.x - offset.x, second.y - offset.y); - this.drawingContext_.stroke(); + for (var j = 1; j < pointList.length; j++) { + var first = pointList[j - 1]; + var second = pointList[j]; + // All rendering calculations are based on the second point in the segment + // because there must be at least two points for something to be rendered. + var ttl = second.ttl; + if (ttl <= 0) { + continue; + } + + this.drawingContext_.beginPath(); + this.drawingContext_.moveTo(first.x, first.y); + this.drawingContext_.lineTo(second.x, second.y); + // TODO(stevet): Use alpha and #00B4CC. + this.drawingContext_.strokeStyle = this.calculateColor_(ttl); + this.drawingContext_.fillStyle = 'none'; + this.drawingContext_.lineWidth = this.calculateLineWidth_(ttl); + this.drawingContext_.lineCap = 'round'; + this.drawingContext_.lineJoin = 'round'; + this.drawingContext_.stroke(); + } } }; @@ -117,6 +129,8 @@ this.drawingCanvas_ = dom.createDom(TagName.CANVAS, Css.DRAWING_CANVAS); this.drawingContext_ = this.drawingCanvas_.getContext('2d'); dom.appendChild(elem, this.drawingCanvas_); + + this.animator_.start(); }; @@ -132,16 +146,18 @@ /** - * Add a new point to the collection of points, and refresh the view. + * Converts a drag event to a gesture Point and adds it to the collection of + * points. * * @param {!i18n.input.chrome.inputview.events.DragEvent} e Drag event to draw. */ -GestureCanvasView.prototype.addPointAndDraw = function(e) { - // Add to the collection. - this.dragEventList_.push(e); +GestureCanvasView.prototype.addPoint = function(e) { + if (this.strokeList_.length == 0) { + this.strokeList_.push([]); + } - // Refresh the view. - this.draw_(); + this.strokeList_[this.strokeList_.length - 1].push( + this.createGesturePoint_(e)); }; @@ -149,17 +165,151 @@ * Clear the view. */ GestureCanvasView.prototype.clear = function() { - this.dragEventList_ = []; + this.strokeList_ = []; this.draw_(); }; /** + * Begins a new gesture. + * + * @param {!i18n.input.chrome.inputview.events.PointerEvent} e Drag event to + * draw. + */ +GestureCanvasView.prototype.startStroke = function(e) { + // Always start a new array to separate previous strokes from this new one. + this.strokeList_.push([]); + + this.strokeList_[this.strokeList_.length - 1].push( + this.createGesturePoint_(e)); +}; + + +/** * The gesture trail animation function. * * @private */ GestureCanvasView.prototype.animateGestureTrail_ = function() { - // TODO(stevet): Implement the gesture trail animation here. + // TODO(stevet): This approximates drawing at 60fps. Refactor this and the + // voice input code to use a common call to requestRenderFrame. + var timeStep = 16; + + this.draw_(); + this.degradeStrokes_(); + this.animator_.start(timeStep); }; + + +/** + * Calculates the line width of the point based on the ttl. + * + * @param {number} ttl The time to live of the point. + * @return {number} The line width to use for the point. + * @private + */ +GestureCanvasView.prototype.calculateLineWidth_ = function(ttl) { + var ratio = ttl / 255.0; + if (ratio < 0) { + ratio = 0; + } + return 9 * ratio; +}; + + +/** + * Calculates the color of the point based on the ttl. + * + * @param {number} ttl The time to live of the point. + * @return {string} The color to use for the point. + * @private + */ +GestureCanvasView.prototype.calculateColor_ = function(ttl) { + var shade = 225 - ttl; + if (shade < 0) { + shade = 0; + } + return 'rgb(' + shade + ', ' + shade + ', ' + shade + ')'; +}; + + +/** + * Returns a gesture point for a given event, with the correct coordinates. + * + * @param {!i18n.input.chrome.inputview.events.DragEvent| + * i18n.input.chrome.inputview.events.PointerEvent} e The event to + * convert. + * @return {i18n.input.chrome.inputview.elements.content. + * GestureCanvasView.Point} The converted gesture point. + * @private + */ +GestureCanvasView.prototype.createGesturePoint_ = function(e) { + var offset = goog.style.getPageOffset(this.drawingCanvas_); + return new + i18n.input.chrome.inputview.elements.content.GestureCanvasView.Point( + e.x - offset.x, e.y - offset.y); +}; + + +/** + * Degrades the ttl of the points in all gesture strokes. + * + * @private + */ +GestureCanvasView.prototype.degradeStrokes_ = function() { + for (var i = 0; i < this.strokeList_.length; i++) { + var all_empty = true; + var pointList = this.strokeList_[i]; + for (var j = 0; j < pointList.length; j++) { + if (pointList[j].ttl > 0) { + pointList[j].ttl -= GestureCanvasView.DEGRADATION_RATE; + all_empty = false; + } + } + + // In the case where all points in the list are empty, dispose of the first. + if (all_empty) { + this.strokeList_.splice(i, 1); + i--; + } + } +}; + + +/** + * One point in the gesture stroke. + * + * This class is used for both rendering the gesture stroke, and also for + * transmitting the stroke coordinates to the recognizer for decoding. + * + * @param {number} x The x coordinate. + * @param {number} y The y coordinate. + * @constructor + */ +i18n.input.chrome.inputview.elements.content.GestureCanvasView.Point = + function(x, y) { + /** + * The left offset relative to the canvas. + * + * @type {number} + */ + this.x = x; + + /** + * The top offset relative to the canvas. + * + * @type {number} + */ + this.y = y; + + /** + * The time-to-live value of the point, used to render the trail fading + * effect. + * + * @type {number} + */ + this.ttl = 225; +}; + + }); // goog.scope
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/imewindows/accents.js b/third_party/google_input_tools/src/chrome/os/inputview/imewindows/accents.js index 1cdfce4f..8a89e889 100644 --- a/third_party/google_input_tools/src/chrome/os/inputview/imewindows/accents.js +++ b/third_party/google_input_tools/src/chrome/os/inputview/imewindows/accents.js
@@ -14,13 +14,17 @@ goog.provide('i18n.input.chrome.inputview.Accents'); goog.require('goog.dom'); +goog.require('goog.dom.TagName'); +goog.require('goog.dom.classlist'); goog.require('goog.math.Coordinate'); goog.require('goog.style'); +goog.require('i18n.input.chrome.inputview.Css'); goog.require('i18n.input.chrome.inputview.util'); goog.scope(function() { var Accents = i18n.input.chrome.inputview.Accents; +var Css = i18n.input.chrome.inputview.Css; /** @@ -56,12 +60,14 @@ var highlightedItem = Accents.getHighlightedItem_(x, y, offset); if (Accents.highlightedItem_ != highlightedItem) { if (Accents.highlightedItem_) { - Accents.highlightedItem_.classList.remove('highlight'); + goog.dom.classlist.remove(Accents.highlightedItem_, + i18n.input.chrome.inputview.Css.ELEMENT_HIGHLIGHT); } Accents.highlightedItem_ = highlightedItem; if (Accents.highlightedItem_ && Accents.highlightedItem_.textContent.trim()) { - Accents.highlightedItem_.classList.add('highlight'); + goog.dom.classlist.add(Accents.highlightedItem_, + i18n.input.chrome.inputview.Css.ELEMENT_HIGHLIGHT); } } }; @@ -77,7 +83,7 @@ Accents.getHighlightedItem_ = function(x, y, offset) { var dom = goog.dom.getDomHelper(); var row = null; - var rows = dom.getElementsByClass('accent-row'); + var rows = dom.getElementsByClass(i18n.input.chrome.inputview.Css.ACCENT_ROW); for (var i = 0; i < rows.length; i++) { var coordinate = goog.style.getClientPosition(rows[i]); var size = goog.style.getSize(rows[i]); @@ -121,39 +127,45 @@ */ Accents.setAccents_ = function(accents, numOfColumns, numOfRows, width, height, startKeyIndex) { - var container = document.createElement('div'); + var TagName = goog.dom.TagName; + var dom = goog.dom.getDomHelper(); + var container = dom.createDom(TagName.DIV, Css.ACCENT_CONTAINER); + goog.dom.setProperties(container, { + 'id' : 'container' + }); container.id = 'container'; - container.classList.add('accent-container'); var orderedAccents = Accents.reorderAccents_(accents, numOfColumns, numOfRows, startKeyIndex); var row = null; for (var i = 0; i < orderedAccents.length; i++) { - var keyElem = document.createElement('div'); + var keyElem = dom.createDom(TagName.DIV, Css.ACCENT_KEY); // Even if this is an empty key, we still need to add textDiv. Otherwise, // the keys have layout issues. - var textDiv = document.createElement('div'); - textDiv.textContent = - i18n.input.chrome.inputview.util.getVisibleCharacter( - orderedAccents[i]); - textDiv.style.lineHeight = height + 'px'; - keyElem.appendChild(textDiv); + var textDiv = dom.createElement(TagName.DIV); + var text = i18n.input.chrome.inputview.util.getVisibleCharacter( + orderedAccents[i]); + textDiv.textContent = text; + // If accent is a word use a smaller font size. + goog.dom.classlist.add(textDiv, text.length > 1 ? Css.FONT_SMALL : + Css.FONT); + + goog.style.setStyle(textDiv, 'lineHeight', height + 'px'); + dom.appendChild(keyElem, textDiv); if (!orderedAccents[i]) { - keyElem.classList.add('empty-key'); + goog.dom.classlist.add(keyElem, Css.ACCENT_EMPTY_KEY); } - keyElem.style.width = width + 'px'; - keyElem.style.height = height + 'px'; + goog.style.setSize(keyElem, width, height); if (i % numOfColumns == 0) { if (row) { container.appendChild(row); } - row = document.createElement('div'); - row.classList.add('accent-row'); + row = dom.createDom(TagName.DIV, Css.ACCENT_ROW); } - row.appendChild(keyElem); + dom.appendChild(row, keyElem); } - container.appendChild(row); - document.body.appendChild(container); + dom.appendChild(container, row); + dom.appendChild(document.body, container); };
diff --git a/third_party/google_input_tools/src/chrome/os/message/name.js b/third_party/google_input_tools/src/chrome/os/message/name.js index 42817612..481a7b35 100644 --- a/third_party/google_input_tools/src/chrome/os/message/name.js +++ b/third_party/google_input_tools/src/chrome/os/message/name.js
@@ -37,7 +37,6 @@ ID: 'id', IS_AUTOCORRECT: 'isAutoCorrect', IS_EMOJI: 'isEmoji', - IS_EXPERIMENTAL: 'IS_EXPERIMENTAL', KEY: 'key', KEYCODE: 'keyCode', KEYSET: 'keyset',
diff --git a/third_party/google_input_tools/src/chrome/os/statistics.js b/third_party/google_input_tools/src/chrome/os/statistics.js index af1d9f89..d08a004 100644 --- a/third_party/google_input_tools/src/chrome/os/statistics.js +++ b/third_party/google_input_tools/src/chrome/os/statistics.js
@@ -95,6 +95,22 @@ /** + * The length of the last text commit. + * + * @private {number} + */ +Statistics.prototype.lastCommitLength_ = 0; + + +/** + * The number of characters typed in this session. + * + * @private {number} + */ +Statistics.prototype.charactersCommitted_ = 0; + + +/** * Sets whether recording for physical keyboard. * * @param {boolean} isPhysicalKeyboard . @@ -152,6 +168,22 @@ /** + * Records that the controller session ended. + */ +Statistics.prototype.recordSessionEnd = function() { + // Do not record cases where we gain and immediately lose focus. This also + // excudes the focus loss-gain on the new tab page from being counted. + if (this.charactersCommitted_ > 0) { + this.recordValue('InputMethod.VirtualKeyboard.CharactersCommitted', + this.charactersCommitted_, 16384, 50); + // TODO: Add WPM metrics. + } + this.charactersCommitted_ = 0; + this.lastCommitLength_ = 0; +}; + + +/** * Records the metrics for each commit. * * @param {string} source . @@ -166,6 +198,16 @@ if (!this.inputMethodId_) { return; } + var length = target.length; + // Increment to include space. + if (triggerType == 0) { + length++; + } else if (triggerType == 5) { + length -= this.lastCommitLength_; + } + this.lastCommitLength_ = length; + this.charactersCommitted_ += length; + var CommitTypes = Statistics.CommitTypes; var commitType = -1; if (targetIndex == 0 && source == target) {
diff --git a/third_party/harfbuzz-ng/src/hb-buffer.cc b/third_party/harfbuzz-ng/src/hb-buffer.cc index 0500aa2..942177c 100644 --- a/third_party/harfbuzz-ng/src/hb-buffer.cc +++ b/third_party/harfbuzz-ng/src/hb-buffer.cc
@@ -454,7 +454,7 @@ info[j] = t; } - if (pos) { + if (have_positions) { for (i = start, j = end - 1; i < j; i++, j--) { hb_glyph_position_t t;
diff --git a/third_party/libjingle/BUILD.gn b/third_party/libjingle/BUILD.gn index e6c1636e..9553d10 100644 --- a/third_party/libjingle/BUILD.gn +++ b/third_party/libjingle/BUILD.gn
@@ -354,6 +354,10 @@ "source/talk/app/webrtc/audiotrackrenderer.h", "source/talk/app/webrtc/datachannel.cc", "source/talk/app/webrtc/datachannel.h", + "source/talk/app/webrtc/dtlsidentityservice.cc", + "source/talk/app/webrtc/dtlsidentityservice.h", + "source/talk/app/webrtc/dtlsidentitystore.cc", + "source/talk/app/webrtc/dtlsidentitystore.h", "source/talk/app/webrtc/dtmfsender.cc", "source/talk/app/webrtc/dtmfsender.h", "source/talk/app/webrtc/jsep.h", @@ -541,42 +545,5 @@ "//third_party/webrtc/voice_engine", ] } - - if (is_android) { - import("//build/config/android/rules.gni") - source_set("libjingle_peerconnection_so") { - sources = [ - "source/talk/app/webrtc/java/jni/peerconnection_jni.cc", - ] - deps = [ - ":libjingle_webrtc", - ":libpeerconnection", - ] - } - - android_library("libjingle_peerconnection_java") { - java_files = [ - "source/talk/app/webrtc/java/src/org/webrtc/AudioSource.java", - "source/talk/app/webrtc/java/src/org/webrtc/AudioTrack.java", - "source/talk/app/webrtc/java/src/org/webrtc/DataChannel.java", - "source/talk/app/webrtc/java/src/org/webrtc/IceCandidate.java", - "source/talk/app/webrtc/java/src/org/webrtc/Logging.java", - "source/talk/app/webrtc/java/src/org/webrtc/MediaConstraints.java", - "source/talk/app/webrtc/java/src/org/webrtc/MediaSource.java", - "source/talk/app/webrtc/java/src/org/webrtc/MediaStream.java", - "source/talk/app/webrtc/java/src/org/webrtc/MediaStreamTrack.java", - "source/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java", - "source/talk/app/webrtc/java/src/org/webrtc/PeerConnection.java", - "source/talk/app/webrtc/java/src/org/webrtc/SdpObserver.java", - "source/talk/app/webrtc/java/src/org/webrtc/StatsObserver.java", - "source/talk/app/webrtc/java/src/org/webrtc/StatsReport.java", - "source/talk/app/webrtc/java/src/org/webrtc/SessionDescription.java", - "source/talk/app/webrtc/java/src/org/webrtc/VideoCapturer.java", - "source/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java", - "source/talk/app/webrtc/java/src/org/webrtc/VideoSource.java", - "source/talk/app/webrtc/java/src/org/webrtc/VideoTrack.java", - ] - } - } } # enable_webrtc # TODO(GYP): Port libjingle.gyp's enable_webrtc condition block.
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium index 84b983f..bb42149 100644 --- a/third_party/libjingle/README.chromium +++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@ Name: libjingle URL: http://code.google.com/p/webrtc/ Version: unknown -Revision: 8542 +Revision: 8600 License: BSD License File: source/talk/COPYING Security Critical: yes
diff --git a/third_party/libjingle/libjingle.gyp b/third_party/libjingle/libjingle.gyp index 8aafdc9..9415b7d 100644 --- a/third_party/libjingle/libjingle.gyp +++ b/third_party/libjingle/libjingle.gyp
@@ -645,34 +645,5 @@ }, # target libpeerconnection ], }], - ['enable_webrtc==1 and OS=="android" and "<(libpeer_target_type)"=="static_library"', { - 'targets': [ - { - # GN version: //third_party/libjingle:libjingle_peerconnection_so - 'target_name': 'libjingle_peerconnection_so', - 'type': 'shared_library', - 'dependencies': [ - '<(DEPTH)/third_party/icu/icu.gyp:icuuc', - 'libjingle_webrtc', - 'libpeerconnection', - ], - 'sources': [ - '<(libjingle_source)/talk/app/webrtc/java/jni/peerconnection_jni.cc', - ], - }, - { - # GN version: //third_party/libjingle:libjingle_peerconnection_java - 'target_name': 'libjingle_peerconnection_javalib', - 'type': 'none', - 'variables': { - 'java_in_dir': '<(libjingle_source)/talk/app/webrtc/java', - }, - 'dependencies': [ - 'libjingle_peerconnection_so', - ], - 'includes': [ '../../build/java.gypi' ], - }, - ], - }], ], }
diff --git a/third_party/mesa/mesa.gyp b/third_party/mesa/mesa.gyp index bf2afcd2..82027b35e 100644 --- a/third_party/mesa/mesa.gyp +++ b/third_party/mesa/mesa.gyp
@@ -80,6 +80,7 @@ # which is used by gallium/auxiliary/Makefile. '-fsanitize=null', '-fsanitize=vptr', + '-fsanitize-coverage=<(sanitizer_coverage)', ], }], ],
diff --git a/third_party/mojo/mojo_edk.gyp b/third_party/mojo/mojo_edk.gyp index 01edb62f..20aa38a 100644 --- a/third_party/mojo/mojo_edk.gyp +++ b/third_party/mojo/mojo_edk.gyp
@@ -24,6 +24,7 @@ 'dependencies': [ '../../base/base.gyp:base', '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', + '../../crypto/crypto.gyp:crypto', ], 'includes': [ 'mojo_edk_system_impl.gypi', @@ -86,6 +87,8 @@ 'sources': [ 'src/mojo/edk/test/multiprocess_test_helper.cc', 'src/mojo/edk/test/multiprocess_test_helper.h', + 'src/mojo/edk/test/scoped_ipc_support.cc', + 'src/mojo/edk/test/scoped_ipc_support.h', 'src/mojo/edk/test/test_utils.h', 'src/mojo/edk/test/test_utils_posix.cc', 'src/mojo/edk/test/test_utils_win.cc', @@ -138,6 +141,7 @@ 'dependencies': [ '../../base/base.gyp:base_win64', '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64', + '../../crypto/crypto.gyp:crypto_nacl_win64', ], 'includes': [ 'mojo_edk_system_impl.gypi',
diff --git a/third_party/mojo/mojo_edk_system_impl.gypi b/third_party/mojo/mojo_edk_system_impl.gypi index 50991bf4..60fd1a9 100644 --- a/third_party/mojo/mojo_edk_system_impl.gypi +++ b/third_party/mojo/mojo_edk_system_impl.gypi
@@ -14,8 +14,6 @@ 'sources': [ 'src/mojo/edk/embedder/configuration.h', 'src/mojo/edk/embedder/channel_info_forward.h', - 'src/mojo/edk/embedder/channel_init.cc', - 'src/mojo/edk/embedder/channel_init.h', 'src/mojo/edk/embedder/embedder.cc', 'src/mojo/edk/embedder/embedder.h', 'src/mojo/edk/embedder/embedder_internal.h', @@ -64,6 +62,8 @@ 'src/mojo/edk/system/core.h', 'src/mojo/edk/system/data_pipe.cc', 'src/mojo/edk/system/data_pipe.h', + 'src/mojo/edk/system/data_pipe_impl.cc', + 'src/mojo/edk/system/data_pipe_impl.h', 'src/mojo/edk/system/data_pipe_consumer_dispatcher.cc', 'src/mojo/edk/system/data_pipe_consumer_dispatcher.h', 'src/mojo/edk/system/data_pipe_producer_dispatcher.cc', @@ -77,12 +77,14 @@ 'src/mojo/edk/system/handle_table.h', 'src/mojo/edk/system/incoming_endpoint.cc', 'src/mojo/edk/system/incoming_endpoint.h', - 'src/mojo/edk/system/local_data_pipe.cc', - 'src/mojo/edk/system/local_data_pipe.h', + 'src/mojo/edk/system/local_data_pipe_impl.cc', + 'src/mojo/edk/system/local_data_pipe_impl.h', 'src/mojo/edk/system/local_message_pipe_endpoint.cc', 'src/mojo/edk/system/local_message_pipe_endpoint.h', 'src/mojo/edk/system/mapping_table.cc', 'src/mojo/edk/system/mapping_table.h', + 'src/mojo/edk/system/master_connection_manager.cc', + 'src/mojo/edk/system/master_connection_manager.h', 'src/mojo/edk/system/memory.cc', 'src/mojo/edk/system/memory.h', 'src/mojo/edk/system/message_in_transit.cc', @@ -100,6 +102,11 @@ 'src/mojo/edk/system/platform_handle_dispatcher.h', 'src/mojo/edk/system/proxy_message_pipe_endpoint.cc', 'src/mojo/edk/system/proxy_message_pipe_endpoint.h', + 'src/mojo/edk/system/remote_consumer_data_pipe_impl.cc', + 'src/mojo/edk/system/remote_consumer_data_pipe_impl.h', + 'src/mojo/edk/system/remote_data_pipe_ack.h', + 'src/mojo/edk/system/remote_producer_data_pipe_impl.cc', + 'src/mojo/edk/system/remote_producer_data_pipe_impl.h', 'src/mojo/edk/system/raw_channel.cc', 'src/mojo/edk/system/raw_channel.h', 'src/mojo/edk/system/raw_channel_posix.cc', @@ -108,8 +115,12 @@ 'src/mojo/edk/system/shared_buffer_dispatcher.h', 'src/mojo/edk/system/simple_dispatcher.cc', 'src/mojo/edk/system/simple_dispatcher.h', + 'src/mojo/edk/system/slave_connection_manager.cc', + 'src/mojo/edk/system/slave_connection_manager.h', 'src/mojo/edk/system/transport_data.cc', 'src/mojo/edk/system/transport_data.h', + 'src/mojo/edk/system/unique_identifier.cc', + 'src/mojo/edk/system/unique_identifier.h', 'src/mojo/edk/system/waiter.cc', 'src/mojo/edk/system/waiter.h', # Test-only code:
diff --git a/third_party/mojo/mojo_edk_tests.gyp b/third_party/mojo/mojo_edk_tests.gyp index 91a777f..94269729 100644 --- a/third_party/mojo/mojo_edk_tests.gyp +++ b/third_party/mojo/mojo_edk_tests.gyp
@@ -175,9 +175,10 @@ 'src/mojo/edk/system/core_unittest.cc', 'src/mojo/edk/system/core_test_base.cc', 'src/mojo/edk/system/core_test_base.h', + 'src/mojo/edk/system/data_pipe_impl_unittest.cc', 'src/mojo/edk/system/data_pipe_unittest.cc', 'src/mojo/edk/system/dispatcher_unittest.cc', - 'src/mojo/edk/system/local_data_pipe_unittest.cc', + 'src/mojo/edk/system/local_data_pipe_impl_unittest.cc', 'src/mojo/edk/system/memory_unittest.cc', 'src/mojo/edk/system/message_pipe_dispatcher_unittest.cc', 'src/mojo/edk/system/message_pipe_test_utils.h', @@ -187,12 +188,14 @@ 'src/mojo/edk/system/options_validation_unittest.cc', 'src/mojo/edk/system/platform_handle_dispatcher_unittest.cc', 'src/mojo/edk/system/raw_channel_unittest.cc', + 'src/mojo/edk/system/remote_data_pipe_impl_unittest.cc', 'src/mojo/edk/system/remote_message_pipe_unittest.cc', 'src/mojo/edk/system/run_all_unittests.cc', 'src/mojo/edk/system/shared_buffer_dispatcher_unittest.cc', 'src/mojo/edk/system/simple_dispatcher_unittest.cc', 'src/mojo/edk/system/test_utils.cc', 'src/mojo/edk/system/test_utils.h', + 'src/mojo/edk/system/unique_identifier_unittest.cc', 'src/mojo/edk/system/waiter_test_utils.cc', 'src/mojo/edk/system/waiter_test_utils.h', 'src/mojo/edk/system/waiter_unittest.cc',
diff --git a/third_party/mojo/mojo_public.gyp b/third_party/mojo/mojo_public.gyp index 0ab9e87..683791d 100644 --- a/third_party/mojo/mojo_public.gyp +++ b/third_party/mojo/mojo_public.gyp
@@ -333,7 +333,6 @@ 'src/mojo/public/interfaces/bindings/tests/no_module.mojom', 'src/mojo/public/interfaces/bindings/tests/rect.mojom', 'src/mojo/public/interfaces/bindings/tests/regression_tests.mojom', - 'src/mojo/public/interfaces/bindings/tests/regression_tests_import.mojom', 'src/mojo/public/interfaces/bindings/tests/sample_factory.mojom', 'src/mojo/public/interfaces/bindings/tests/sample_import.mojom', 'src/mojo/public/interfaces/bindings/tests/sample_import2.mojom',
diff --git a/third_party/mojo/mojom_bindings_generator_variables.gypi b/third_party/mojo/mojom_bindings_generator_variables.gypi index 727eef0..d09c13c 100644 --- a/third_party/mojo/mojom_bindings_generator_variables.gypi +++ b/third_party/mojo/mojom_bindings_generator_variables.gypi
@@ -19,7 +19,6 @@ '<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl', '<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl', '<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl', - '<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl', '<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl', '<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl', '<(DEPTH)/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl',
diff --git a/third_party/mojo/src/mojo/edk/embedder/BUILD.gn b/third_party/mojo/src/mojo/edk/embedder/BUILD.gn index 5eb77d7..9650209 100644 --- a/third_party/mojo/src/mojo/edk/embedder/BUILD.gn +++ b/third_party/mojo/src/mojo/edk/embedder/BUILD.gn
@@ -11,8 +11,6 @@ sources = [ "channel_info_forward.h", - "channel_init.cc", - "channel_init.h", "configuration.h", "embedder.cc", "embedder.h", @@ -84,6 +82,7 @@ deps = [ "//base", + "//crypto", ] if (is_android) { @@ -100,6 +99,8 @@ sources = [ "master_process_delegate.h", + "process_delegate.h", + "process_type.h", "slave_process_delegate.h", ]
diff --git a/third_party/mojo/src/mojo/edk/embedder/channel_init.cc b/third_party/mojo/src/mojo/edk/embedder/channel_init.cc deleted file mode 100644 index 0b6d76c..0000000 --- a/third_party/mojo/src/mojo/edk/embedder/channel_init.cc +++ /dev/null
@@ -1,56 +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 "mojo/edk/embedder/channel_init.h" - -#include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "mojo/edk/embedder/embedder.h" - -namespace mojo { -namespace embedder { - -ChannelInit::ChannelInit() : channel_info_(nullptr), weak_factory_(this) { -} - -ChannelInit::~ChannelInit() { - // TODO(vtl): This is likely leaky in common scenarios (we're on the main - // thread, which outlives the I/O thread, and we're destroyed after the I/O - // thread is destroyed. - if (channel_info_) - DestroyChannel(channel_info_); -} - -ScopedMessagePipeHandle ChannelInit::Init( - base::PlatformFile file, - scoped_refptr<base::TaskRunner> io_thread_task_runner) { - ScopedMessagePipeHandle message_pipe = - CreateChannel(ScopedPlatformHandle(PlatformHandle(file)), - io_thread_task_runner, - base::Bind(&ChannelInit::OnCreatedChannel, - weak_factory_.GetWeakPtr()), - base::MessageLoop::current()->task_runner()).Pass(); - return message_pipe.Pass(); -} - -void ChannelInit::WillDestroySoon() { - if (channel_info_) - WillDestroyChannelSoon(channel_info_); -} - -// static -void ChannelInit::OnCreatedChannel(base::WeakPtr<ChannelInit> self, - ChannelInfo* channel) { - // If |self| was already destroyed, shut the channel down. - if (!self) { - DestroyChannel(channel); - return; - } - - DCHECK(!self->channel_info_); - self->channel_info_ = channel; -} - -} // namespace embedder -} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/embedder/channel_init.h b/third_party/mojo/src/mojo/edk/embedder/channel_init.h deleted file mode 100644 index 478da41b..0000000 --- a/third_party/mojo/src/mojo/edk/embedder/channel_init.h +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_EDK_EMBEDDER_CHANNEL_INIT_H_ -#define MOJO_EDK_EMBEDDER_CHANNEL_INIT_H_ - -#include "base/files/file.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "mojo/edk/embedder/channel_info_forward.h" -#include "mojo/edk/system/system_impl_export.h" -#include "mojo/public/cpp/system/message_pipe.h" - -namespace base { -class MessageLoopProxy; -class TaskRunner; -} - -namespace mojo { -namespace embedder { - -// |ChannelInit| handles creation (and destruction) of the Mojo channel. It is -// not thread-safe, but may be used on any single thread (with a |MessageLoop|). -class MOJO_SYSTEM_IMPL_EXPORT ChannelInit { - public: - ChannelInit(); - ~ChannelInit(); - - // Initializes the channel. This takes ownership of |file|. Returns the - // primordial |MessagePipe| for the channel. - mojo::ScopedMessagePipeHandle Init( - base::PlatformFile file, - scoped_refptr<base::TaskRunner> io_thread_task_runner); - - // Notifies the channel that we (hence it) will soon be destroyed. - void WillDestroySoon(); - - private: - // Invoked on the thread on which this object lives once the channel has been - // established. (This is a static method that takes a weak pointer to self, - // since we want to destroy the channel even if we're destroyed.) - static void OnCreatedChannel(base::WeakPtr<ChannelInit> self, - ChannelInfo* channel); - - // If non-null the channel has been established. - ChannelInfo* channel_info_; - - base::WeakPtrFactory<ChannelInit> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(ChannelInit); -}; - -} // namespace embedder -} // namespace mojo - -#endif // MOJO_EDK_EMBEDDER_CHANNEL_INIT_H_
diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder.cc b/third_party/mojo/src/mojo/edk/embedder/embedder.cc index d0a5135..a4997e7d 100644 --- a/third_party/mojo/src/mojo/edk/embedder/embedder.cc +++ b/third_party/mojo/src/mojo/edk/embedder/embedder.cc
@@ -6,25 +6,60 @@ #include "base/atomicops.h" #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/location.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/task_runner.h" #include "mojo/edk/embedder/embedder_internal.h" +#include "mojo/edk/embedder/master_process_delegate.h" #include "mojo/edk/embedder/platform_support.h" +#include "mojo/edk/embedder/process_delegate.h" +#include "mojo/edk/embedder/slave_process_delegate.h" #include "mojo/edk/system/channel.h" #include "mojo/edk/system/channel_manager.h" #include "mojo/edk/system/configuration.h" +#include "mojo/edk/system/connection_manager.h" #include "mojo/edk/system/core.h" +#include "mojo/edk/system/master_connection_manager.h" #include "mojo/edk/system/message_pipe_dispatcher.h" #include "mojo/edk/system/platform_handle_dispatcher.h" #include "mojo/edk/system/raw_channel.h" +#include "mojo/edk/system/slave_connection_manager.h" namespace mojo { namespace embedder { +namespace internal { + +// Declared in embedder_internal.h. +PlatformSupport* g_platform_support = nullptr; +system::Core* g_core = nullptr; +ProcessType g_process_type = ProcessType::UNINITIALIZED; + +} // namespace internal + namespace { +// The following global variables are set in |InitIPCSupport()| and reset by +// |ShutdownIPCSupport()|/|ShutdownIPCSupportOnIOThread()|. + +// Note: This needs to be |AddRef()|ed/|Release()|d. +base::TaskRunner* g_delegate_thread_task_runner = nullptr; + +ProcessDelegate* g_process_delegate = nullptr; + +// Note: This needs to be |AddRef()|ed/|Release()|d. +base::TaskRunner* g_io_thread_task_runner = nullptr; + +// Instance of |ConnectionManager| used by the channel manager (below). +system::ConnectionManager* g_connection_manager = nullptr; + +// Instance of |ChannelManager| used by the channel management functions +// (|CreateChannel()|, etc.). +system::ChannelManager* g_channel_manager = nullptr; + // TODO(vtl): For now, we need this to be thread-safe (since theoretically we // currently support multiple channel creation threads -- possibly one per // channel). Eventually, we won't need it to be thread-safe (we'll require a @@ -46,19 +81,23 @@ return static_cast<system::ChannelId>(-new_counter_value); } +// Note: Called on the I/O thread. +void ShutdownIPCSupportHelper() { + // Save these before nuking them using |ShutdownChannelOnIOThread()|. + scoped_refptr<base::TaskRunner> delegate_thread_task_runner( + g_delegate_thread_task_runner); + ProcessDelegate* process_delegate = g_process_delegate; + + ShutdownIPCSupportOnIOThread(); + + bool ok = delegate_thread_task_runner->PostTask( + FROM_HERE, base::Bind(&ProcessDelegate::OnShutdownComplete, + base::Unretained(process_delegate))); + DCHECK(ok); +} + } // namespace -namespace internal { - -// Declared in embedder_internal.h. -PlatformSupport* g_platform_support = nullptr; -system::Core* g_core = nullptr; -system::ChannelManager* g_channel_manager = nullptr; -MasterProcessDelegate* g_master_process_delegate = nullptr; -SlaveProcessDelegate* g_slave_process_delegate = nullptr; - -} // namespace internal - Configuration* GetConfiguration() { return system::GetMutableConfiguration(); } @@ -71,95 +110,12 @@ DCHECK(!internal::g_core); internal::g_core = new system::Core(internal::g_platform_support); - - DCHECK(!internal::g_channel_manager); - internal::g_channel_manager = - new system::ChannelManager(internal::g_platform_support); } -void InitMaster(scoped_refptr<base::TaskRunner> delegate_thread_task_runner, - MasterProcessDelegate* master_process_delegate, - scoped_refptr<base::TaskRunner> io_thread_task_runner) { - // |Init()| must have already been called. - DCHECK(internal::g_core); - - // TODO(vtl): This is temporary. We really want to construct a - // |MasterConnectionManager| here, which will in turn hold on to the delegate. - internal::g_master_process_delegate = master_process_delegate; -} - -void InitSlave(scoped_refptr<base::TaskRunner> delegate_thread_task_runner, - SlaveProcessDelegate* slave_process_delegate, - scoped_refptr<base::TaskRunner> io_thread_task_runner, - ScopedPlatformHandle platform_handle) { - // |Init()| must have already been called. - DCHECK(internal::g_core); - - // TODO(vtl): This is temporary. We really want to construct a - // |SlaveConnectionManager| here, which will in turn hold on to the delegate. - internal::g_slave_process_delegate = slave_process_delegate; -} - -// TODO(vtl): Write tests for this. -ScopedMessagePipeHandle CreateChannelOnIOThread( - ScopedPlatformHandle platform_handle, - ChannelInfo** channel_info) { - DCHECK(platform_handle.is_valid()); - DCHECK(channel_info); - - *channel_info = new ChannelInfo(MakeChannelId()); - scoped_refptr<system::MessagePipeDispatcher> dispatcher = - internal::g_channel_manager->CreateChannelOnIOThread( - (*channel_info)->channel_id, platform_handle.Pass()); - - ScopedMessagePipeHandle rv( - MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); - CHECK(rv.is_valid()); - // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it - // once that's fixed. - return rv.Pass(); -} - -ScopedMessagePipeHandle CreateChannel( - ScopedPlatformHandle platform_handle, - scoped_refptr<base::TaskRunner> io_thread_task_runner, - DidCreateChannelCallback callback, - scoped_refptr<base::TaskRunner> callback_thread_task_runner) { - DCHECK(platform_handle.is_valid()); - DCHECK(io_thread_task_runner); - DCHECK(!callback.is_null()); - - system::ChannelId channel_id = MakeChannelId(); - scoped_ptr<ChannelInfo> channel_info(new ChannelInfo(channel_id)); - scoped_refptr<system::MessagePipeDispatcher> dispatcher = - internal::g_channel_manager->CreateChannel( - channel_id, platform_handle.Pass(), io_thread_task_runner, - base::Bind(callback, base::Unretained(channel_info.release())), - callback_thread_task_runner); - - ScopedMessagePipeHandle rv( - MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); - CHECK(rv.is_valid()); - // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it - // once that's fixed. - return rv.Pass(); -} - -// TODO(vtl): Write tests for this. -void DestroyChannel(ChannelInfo* channel_info) { - DCHECK(channel_info); - DCHECK(channel_info->channel_id); - DCHECK(internal::g_channel_manager); - // This will destroy the channel synchronously if called from the channel - // thread. - internal::g_channel_manager->ShutdownChannel(channel_info->channel_id); - delete channel_info; -} - -void WillDestroyChannelSoon(ChannelInfo* channel_info) { - DCHECK(channel_info); - DCHECK(internal::g_channel_manager); - internal::g_channel_manager->WillShutdownChannel(channel_info->channel_id); +MojoResult AsyncWait(MojoHandle handle, + MojoHandleSignals signals, + const base::Callback<void(MojoResult)>& callback) { + return internal::g_core->AsyncWait(handle, signals, callback); } MojoResult CreatePlatformHandleWrapper( @@ -202,10 +158,176 @@ return MOJO_RESULT_OK; } -MojoResult AsyncWait(MojoHandle handle, - MojoHandleSignals signals, - base::Callback<void(MojoResult)> callback) { - return internal::g_core->AsyncWait(handle, signals, callback); +void InitIPCSupport(ProcessType process_type, + scoped_refptr<base::TaskRunner> delegate_thread_task_runner, + ProcessDelegate* process_delegate, + scoped_refptr<base::TaskRunner> io_thread_task_runner, + ScopedPlatformHandle platform_handle) { + // |Init()| must have already been called. + DCHECK(internal::g_core); + // And not |InitIPCSupport()| (without |ShutdownIPCSupport()|). + DCHECK(internal::g_process_type == ProcessType::UNINITIALIZED); + + internal::g_process_type = process_type; + + DCHECK(delegate_thread_task_runner); + DCHECK(!g_delegate_thread_task_runner); + g_delegate_thread_task_runner = delegate_thread_task_runner.get(); + g_delegate_thread_task_runner->AddRef(); + + DCHECK(process_delegate->GetType() == process_type); + DCHECK(!g_process_delegate); + g_process_delegate = process_delegate; + + DCHECK(io_thread_task_runner); + DCHECK(!g_io_thread_task_runner); + g_io_thread_task_runner = io_thread_task_runner.get(); + g_io_thread_task_runner->AddRef(); + + DCHECK(!g_connection_manager); + switch (process_type) { + case ProcessType::UNINITIALIZED: + CHECK(false); + break; + case ProcessType::NONE: + DCHECK(!platform_handle.is_valid()); // We wouldn't do anything with it. + // Nothing to do. + break; + case ProcessType::MASTER: + DCHECK(!platform_handle.is_valid()); // We wouldn't do anything with it. + g_connection_manager = new system::MasterConnectionManager(); + static_cast<system::MasterConnectionManager*>(g_connection_manager) + ->Init(g_delegate_thread_task_runner, + static_cast<MasterProcessDelegate*>(g_process_delegate)); + break; + case ProcessType::SLAVE: + DCHECK(platform_handle.is_valid()); + g_connection_manager = new system::SlaveConnectionManager(); + static_cast<system::SlaveConnectionManager*>(g_connection_manager) + ->Init(g_delegate_thread_task_runner, + static_cast<SlaveProcessDelegate*>(g_process_delegate), + platform_handle.Pass()); + break; + } + + DCHECK(!g_channel_manager); + g_channel_manager = + new system::ChannelManager(internal::g_platform_support, + io_thread_task_runner, g_connection_manager); +} + +void ShutdownIPCSupportOnIOThread() { + DCHECK(internal::g_process_type != ProcessType::UNINITIALIZED); + + g_channel_manager->ShutdownOnIOThread(); + delete g_channel_manager; + g_channel_manager = nullptr; + + if (g_connection_manager) { + g_connection_manager->Shutdown(); + delete g_connection_manager; + g_connection_manager = nullptr; + } + + g_io_thread_task_runner->Release(); + g_io_thread_task_runner = nullptr; + + g_delegate_thread_task_runner->Release(); + g_delegate_thread_task_runner = nullptr; + + g_process_delegate = nullptr; + + internal::g_process_type = ProcessType::UNINITIALIZED; +} + +void ShutdownIPCSupport() { + DCHECK(internal::g_process_type != ProcessType::UNINITIALIZED); + + bool ok = g_io_thread_task_runner->PostTask( + FROM_HERE, base::Bind(&ShutdownIPCSupportHelper)); + DCHECK(ok); +} + +void ConnectToSlave(SlaveInfo slave_info, + ScopedPlatformHandle platform_handle) { + DCHECK(platform_handle.is_valid()); + DCHECK(internal::g_process_type == ProcessType::MASTER); + static_cast<system::MasterConnectionManager*>(g_connection_manager) + ->AddSlave(slave_info, platform_handle.Pass()); +} + +// TODO(vtl): Write tests for this. +ScopedMessagePipeHandle CreateChannelOnIOThread( + ScopedPlatformHandle platform_handle, + ChannelInfo** channel_info) { + DCHECK(platform_handle.is_valid()); + DCHECK(channel_info); + + *channel_info = new ChannelInfo(MakeChannelId()); + scoped_refptr<system::MessagePipeDispatcher> dispatcher = + g_channel_manager->CreateChannelOnIOThread((*channel_info)->channel_id, + platform_handle.Pass()); + + ScopedMessagePipeHandle rv( + MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); + CHECK(rv.is_valid()); + // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it + // once that's fixed. + return rv.Pass(); +} + +ScopedMessagePipeHandle CreateChannel( + ScopedPlatformHandle platform_handle, + scoped_refptr<base::TaskRunner> io_thread_task_runner, + const DidCreateChannelCallback& callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner) { + DCHECK(platform_handle.is_valid()); + DCHECK(io_thread_task_runner); + DCHECK(!callback.is_null()); + + system::ChannelId channel_id = MakeChannelId(); + scoped_ptr<ChannelInfo> channel_info(new ChannelInfo(channel_id)); + scoped_refptr<system::MessagePipeDispatcher> dispatcher = + g_channel_manager->CreateChannel( + channel_id, platform_handle.Pass(), io_thread_task_runner, + base::Bind(callback, base::Unretained(channel_info.release())), + callback_thread_task_runner); + + ScopedMessagePipeHandle rv( + MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); + CHECK(rv.is_valid()); + // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it + // once that's fixed. + return rv.Pass(); +} + +// TODO(vtl): Write tests for this. +void DestroyChannelOnIOThread(ChannelInfo* channel_info) { + DCHECK(channel_info); + DCHECK(channel_info->channel_id); + DCHECK(g_channel_manager); + g_channel_manager->ShutdownChannelOnIOThread(channel_info->channel_id); + delete channel_info; +} + +// TODO(vtl): Write tests for this. +void DestroyChannel( + ChannelInfo* channel_info, + const DidDestroyChannelCallback& callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner) { + DCHECK(channel_info); + DCHECK(channel_info->channel_id); + DCHECK(!callback.is_null()); + DCHECK(g_channel_manager); + g_channel_manager->ShutdownChannel(channel_info->channel_id, callback, + callback_thread_task_runner); + delete channel_info; +} + +void WillDestroyChannelSoon(ChannelInfo* channel_info) { + DCHECK(channel_info); + DCHECK(g_channel_manager); + g_channel_manager->WillShutdownChannel(channel_info->channel_id); } } // namespace embedder
diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder.h b/third_party/mojo/src/mojo/edk/embedder/embedder.h index 4898ae1..142c86fa 100644 --- a/third_party/mojo/src/mojo/edk/embedder/embedder.h +++ b/third_party/mojo/src/mojo/edk/embedder/embedder.h
@@ -10,6 +10,7 @@ #include "base/memory/scoped_ptr.h" #include "base/task_runner.h" #include "mojo/edk/embedder/channel_info_forward.h" +#include "mojo/edk/embedder/process_type.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/system_impl_export.h" #include "mojo/public/cpp/system/message_pipe.h" @@ -18,9 +19,15 @@ namespace embedder { struct Configuration; -class MasterProcessDelegate; class PlatformSupport; -class SlaveProcessDelegate; +class ProcessDelegate; +typedef void* SlaveInfo; + +// Basic configuration/initialization ------------------------------------------ + +// |Init()| sets up the basic Mojo system environment, making the |Mojo...()| +// functions available and functional. This is never shut down (except in tests +// -- see test_embedder.h). // Returns the global configuration. In general, you should not need to change // the configuration, but if you do you must do it before calling |Init()|. @@ -30,31 +37,88 @@ // initialize the (global, singleton) system. MOJO_SYSTEM_IMPL_EXPORT void Init(scoped_ptr<PlatformSupport> platform_support); -// Initializes a master process. To be called after |Init()|. -// |master_process_delegate| should live forever (or until after -// |mojo::embedder::test::Shutdown()|); its methods will be called using -// |delegate_thread_task_runner|, which must be the task runner for the thread -// calling |InitMaster()|. |io_thread_task_runner| should be the task runner for -// some I/O thread; this should be the same as that provided to -// |CreateChannel()| (or on which |CreateChannelOnIOThread()| is called). -// TODO(vtl): Remove the |io_thread_task_runner| argument from -// |CreateChannel()| (and eventually |CreateChannel()| altogether) and require -// that either this or |InitSlave()| be called. Currently, |CreateChannel()| can -// be used with different I/O threads, but this capability will be removed. -MOJO_SYSTEM_IMPL_EXPORT void InitMaster( - scoped_refptr<base::TaskRunner> delegate_thread_task_runner, - MasterProcessDelegate* master_process_delegate, - scoped_refptr<base::TaskRunner> io_thread_task_runner); +// Basic functions ------------------------------------------------------------- -// Initializes a slave process. Similar to |InitMaster()| (see above). -// |platform_handle| should be connected to the handle passed to |AddSlave()|. -// TODO(vtl): |AddSlave()| doesn't exist yet. -MOJO_SYSTEM_IMPL_EXPORT void InitSlave( +// The functions in this section are available once |Init()| has been called. + +// Start waiting on the handle asynchronously. On success, |callback| will be +// called exactly once, when |handle| satisfies a signal in |signals| or it +// becomes known that it will never do so. |callback| will be executed on an +// arbitrary thread, so it must not call any Mojo system or embedder functions. +MOJO_SYSTEM_IMPL_EXPORT MojoResult +AsyncWait(MojoHandle handle, + MojoHandleSignals signals, + const base::Callback<void(MojoResult)>& callback); + +// Creates a |MojoHandle| that wraps the given |PlatformHandle| (taking +// ownership of it). This |MojoHandle| can then, e.g., be passed through message +// pipes. Note: This takes ownership (and thus closes) |platform_handle| even on +// failure, which is different from what you'd expect from a Mojo API, but it +// makes for a more convenient embedder API. +MOJO_SYSTEM_IMPL_EXPORT MojoResult +CreatePlatformHandleWrapper(ScopedPlatformHandle platform_handle, + MojoHandle* platform_handle_wrapper_handle); + +// Retrieves the |PlatformHandle| that was wrapped into a |MojoHandle| (using +// |CreatePlatformHandleWrapper()| above). Note that the |MojoHandle| must still +// be closed separately. +MOJO_SYSTEM_IMPL_EXPORT MojoResult +PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle, + ScopedPlatformHandle* platform_handle); + +// Initialialization/shutdown for interprocess communication (IPC) ------------- + +// |InitIPCSupport()| sets up the subsystem for interprocess communication, +// making the IPC functions (in the following section) available and functional. +// (This may only be done after |Init()|.) +// +// This subsystem may be shut down, using |ShutdownIPCSupportOnIOThread()| or +// |ShutdownIPCSupport()|. None of the IPC functions may be called while or +// after either of these is called. + +// Initializes a process of the given type; to be called after |Init()|. +// - |process_delegate| must be a process delegate of the appropriate type +// corresponding to |process_type|; its methods will be called on +// |delegate_thread_task_runner|. +// - |delegate_thread_task_runner|, |process_delegate|, and +// |io_thread_task_runner| should live at least until +// |ShutdownIPCSupport()|'s callback has been run or +// |ShutdownIPCSupportOnIOThread()| has completed. +// - For slave processes (i.e., |process_type| is |ProcessType::SLAVE|), +// |platform_handle| should be connected to the handle passed to +// |ConnectToSlave()| (in the master process). For other processes, +// |platform_handle| is ignored (and should not be valid). +MOJO_SYSTEM_IMPL_EXPORT void InitIPCSupport( + ProcessType process_type, scoped_refptr<base::TaskRunner> delegate_thread_task_runner, - SlaveProcessDelegate* slave_process_delegate, + ProcessDelegate* process_delegate, scoped_refptr<base::TaskRunner> io_thread_task_runner, ScopedPlatformHandle platform_handle); +// Shuts down the subsystem initialized by |InitIPCSupport()|. This must be +// called on the I/O thread (given to |InitIPCSupport()|). This completes +// synchronously and does not result in a call to the process delegate's +// |OnShutdownComplete()|. +MOJO_SYSTEM_IMPL_EXPORT void ShutdownIPCSupportOnIOThread(); + +// Like |ShutdownIPCSupportOnIOThread()|, but may be called from any thread, +// signalling shutdown completion via the process delegate's +// |OnShutdownComplete()|. +MOJO_SYSTEM_IMPL_EXPORT void ShutdownIPCSupport(); + +// Interprocess communication (IPC) functions ---------------------------------- + +// Connects to a slave process to the IPC system. This should only be called in +// a process initialized (using |InitIPCSupport()|) with process type +// |ProcessType::MASTER|. |slave_info| is caller-dependent slave information, +// which should remain alive until the master process delegate's +// |OnSlaveDisconnect()| is called. |platform_handle| should be a handle to one +// end of an OS "pipe"; the slave process should |InitIPCSupport()| with +// |ProcessType::SLAVE| and the handle to the other end of this OS "pipe". +MOJO_SYSTEM_IMPL_EXPORT void ConnectToSlave( + SlaveInfo slave_info, + ScopedPlatformHandle platform_handle); + // A "channel" is a connection on top of an OS "pipe", on top of which Mojo // message pipes (etc.) can be multiplexed. It must "live" on some I/O thread. // @@ -111,48 +175,33 @@ MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle CreateChannel(ScopedPlatformHandle platform_handle, scoped_refptr<base::TaskRunner> io_thread_task_runner, - DidCreateChannelCallback callback, + const DidCreateChannelCallback& callback, scoped_refptr<base::TaskRunner> callback_thread_task_runner); // Destroys a channel that was created using |CreateChannel()| (or -// |CreateChannelOnIOThread()|); may be called from any thread. |channel_info| -// should be the value provided to the callback to |CreateChannel()| (or -// returned by |CreateChannelOnIOThread()|). If called from the I/O thread, this -// will complete synchronously (in particular, it will post no tasks). -// TODO(vtl): If called from some other thread, it'll post tasks to the I/O -// thread. This is obviously potentially problematic if you want to shut the I/O -// thread down. -MOJO_SYSTEM_IMPL_EXPORT void DestroyChannel(ChannelInfo* channel_info); +// |CreateChannelOnIOThread()|); must be called from the channel's I'O thread. +// |channel_info| should be the value provided to the callback to +// |CreateChannel()| (or returned by |CreateChannelOnIOThread()|). Completes +// synchronously (and posts no tasks). +MOJO_SYSTEM_IMPL_EXPORT void DestroyChannelOnIOThread( + ChannelInfo* channel_info); + +typedef base::Closure DidDestroyChannelCallback; +// Like |DestroyChannelOnIOThread()|, but asynchronous and may be called from +// any thread. The callback will be called using |callback_thread_task_runner| +// if that is non-null, or otherwise it will be called on the "channel thread". +// The "channel thread" must remain alive and continue to process tasks until +// the callback has been executed. +MOJO_SYSTEM_IMPL_EXPORT void DestroyChannel( + ChannelInfo* channel_info, + const DidDestroyChannelCallback& callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner); // Inform the channel that it will soon be destroyed (doing so is optional). // This may be called from any thread, but the caller must ensure that this is // called before |DestroyChannel()|. MOJO_SYSTEM_IMPL_EXPORT void WillDestroyChannelSoon(ChannelInfo* channel_info); -// Creates a |MojoHandle| that wraps the given |PlatformHandle| (taking -// ownership of it). This |MojoHandle| can then, e.g., be passed through message -// pipes. Note: This takes ownership (and thus closes) |platform_handle| even on -// failure, which is different from what you'd expect from a Mojo API, but it -// makes for a more convenient embedder API. -MOJO_SYSTEM_IMPL_EXPORT MojoResult -CreatePlatformHandleWrapper(ScopedPlatformHandle platform_handle, - MojoHandle* platform_handle_wrapper_handle); -// Retrieves the |PlatformHandle| that was wrapped into a |MojoHandle| (using -// |CreatePlatformHandleWrapper()| above). Note that the |MojoHandle| must still -// be closed separately. -MOJO_SYSTEM_IMPL_EXPORT MojoResult -PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle, - ScopedPlatformHandle* platform_handle); - -// Start waiting the handle asynchronously. On success, |callback| will be -// called exactly once, when |handle| satisfies a signal in |signals| or it -// becomes known that it will never do so. |callback| will be executed on an -// arbitrary thread. It must not call any Mojo system or embedder functions. -MOJO_SYSTEM_IMPL_EXPORT MojoResult -AsyncWait(MojoHandle handle, - MojoHandleSignals signals, - base::Callback<void(MojoResult)> callback); - } // namespace embedder } // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder_internal.h b/third_party/mojo/src/mojo/edk/embedder/embedder_internal.h index 7d90148..833e66b 100644 --- a/third_party/mojo/src/mojo/edk/embedder/embedder_internal.h +++ b/third_party/mojo/src/mojo/edk/embedder/embedder_internal.h
@@ -11,6 +11,12 @@ #include <stdint.h> +#include "mojo/edk/embedder/process_type.h" + +namespace base { +class TaskRunner; +} + namespace mojo { namespace system { @@ -26,9 +32,7 @@ namespace embedder { class PlatformSupport; -// TODO(vtl): Remove these (see below). -class MasterProcessDelegate; -class SlaveProcessDelegate; +class ProcessDelegate; // This is a type that's opaque to users of the embedder API (which only // gives/takes |ChannelInfo*|s). We make it a struct to make it @@ -48,15 +52,11 @@ // Instance of |Core| used by the system functions (|Mojo...()|). extern system::Core* g_core; -// Instance of |ChannelManager| used by the channel management functions -// (|mojo::embedder::CreateChannel()|, etc.). -extern system::ChannelManager* g_channel_manager; - -// TODO(vtl): Remove these: We'll eventually really want to hold on to a -// |MasterConnectionManager*| or a |SlaveConnectionManager*|. For now, keep -// these around as globals to avoid triggering leak detectors. -extern MasterProcessDelegate* g_master_process_delegate; -extern SlaveProcessDelegate* g_slave_process_delegate; +// Type of process initialized in |InitIPCSupport()| (set to |UNINITIALIZED| if +// "outside" |InitIPCSupport()|/|ShutdownIPCSupport()|). This is declared here +// so that |mojo::embedder::test::Shutdown()| can check that it's only called +// after |ShutdownIPCSupport()|. +extern ProcessType g_process_type; } // namespace internal
diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder_unittest.cc b/third_party/mojo/src/mojo/edk/embedder/embedder_unittest.cc index aa0b08b8..48a59c1 100644 --- a/third_party/mojo/src/mojo/edk/embedder/embedder_unittest.cc +++ b/third_party/mojo/src/mojo/edk/embedder/embedder_unittest.cc
@@ -18,6 +18,7 @@ #include "mojo/edk/embedder/test_embedder.h" #include "mojo/edk/system/test_utils.h" #include "mojo/edk/test/multiprocess_test_helper.h" +#include "mojo/edk/test/scoped_ipc_support.h" #include "mojo/public/c/system/core.h" #include "testing/gtest/include/gtest/gtest.h" @@ -44,7 +45,7 @@ ScopedPlatformHandle platform_handle) : io_thread_task_runner_(io_thread_task_runner), bootstrap_message_pipe_(MOJO_HANDLE_INVALID), - did_create_channel_event_(true, false), // Manual reset. + event_(true, false), // Manual reset. channel_info_(nullptr) { bootstrap_message_pipe_ = CreateChannel(platform_handle.Pass(), io_thread_task_runner_, @@ -60,12 +61,17 @@ // the I/O thread must be alive and pumping messages.) ~ScopedTestChannel() { // |WaitForChannelCreationCompletion()| must be called before destruction. - CHECK(did_create_channel_event_.IsSignaled()); - DestroyChannel(channel_info_); + CHECK(event_.IsSignaled()); + event_.Reset(); + DestroyChannel(channel_info_, + base::Bind(&ScopedTestChannel::DidDestroyChannel, + base::Unretained(this)), + nullptr); + event_.Wait(); } // Waits for channel creation to be completed. - void WaitForChannelCreationCompletion() { did_create_channel_event_.Wait(); } + void WaitForChannelCreationCompletion() { event_.Wait(); } MojoHandle bootstrap_message_pipe() const { return bootstrap_message_pipe_; } @@ -78,9 +84,11 @@ CHECK(channel_info); CHECK(!channel_info_); channel_info_ = channel_info; - did_create_channel_event_.Signal(); + event_.Signal(); } + void DidDestroyChannel() { event_.Signal(); } + scoped_refptr<base::TaskRunner> io_thread_task_runner_; // Valid from creation until whenever it gets closed (by the "owner" of this @@ -90,8 +98,9 @@ MojoHandle bootstrap_message_pipe_; // Set after channel creation has been completed (i.e., the callback to - // |CreateChannel()| has been called). - base::WaitableEvent did_create_channel_event_; + // |CreateChannel()| has been called). Also used in the destructor to wait for + // |DestroyChannel()| completion. + base::WaitableEvent event_; // Valid after channel creation completion until destruction. ChannelInfo* channel_info_; @@ -120,6 +129,8 @@ }; TEST_F(EmbedderTest, ChannelsBasic) { + mojo::test::ScopedIPCSupport ipc_support(test_io_task_runner()); + PlatformChannelPair channel_pair; ScopedTestChannel server_channel(test_io_task_runner(), channel_pair.PassServerHandle()); @@ -247,6 +258,8 @@ } TEST_F(EmbedderTest, ChannelsHandlePassing) { + mojo::test::ScopedIPCSupport ipc_support(test_io_task_runner()); + PlatformChannelPair channel_pair; ScopedTestChannel server_channel(test_io_task_runner(), channel_pair.PassServerHandle()); @@ -389,6 +402,10 @@ #define MAYBE_MultiprocessChannels MultiprocessChannels #endif // defined(OS_ANDROID) TEST_F(EmbedderTest, MAYBE_MultiprocessChannels) { + // TODO(vtl): This should eventually initialize a master process instead, + // probably. + mojo::test::ScopedIPCSupport ipc_support(test_io_task_runner()); + mojo::test::MultiprocessTestHelper multiprocess_test_helper; multiprocess_test_helper.StartChild("MultiprocessChannelsClient"); @@ -512,6 +529,10 @@ test::InitWithSimplePlatformSupport(); { + // TODO(vtl): This should eventually initialize a slave process instead, + // probably. + mojo::test::ScopedIPCSupport ipc_support(test_io_thread.task_runner()); + ScopedTestChannel client_channel(test_io_thread.task_runner(), client_platform_handle.Pass()); MojoHandle client_mp = client_channel.bootstrap_message_pipe();
diff --git a/third_party/mojo/src/mojo/edk/embedder/master_process_delegate.h b/third_party/mojo/src/mojo/edk/embedder/master_process_delegate.h index 13791f45..bc3c909 100644 --- a/third_party/mojo/src/mojo/edk/embedder/master_process_delegate.h +++ b/third_party/mojo/src/mojo/edk/embedder/master_process_delegate.h
@@ -7,40 +7,38 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "mojo/edk/embedder/process_delegate.h" #include "mojo/edk/system/system_impl_export.h" namespace mojo { namespace embedder { -// An interface for containers of slave process information, to be used by -// |MasterProcessDelegate| (below). -class MOJO_SYSTEM_IMPL_EXPORT SlaveInfo { - public: - SlaveInfo() {} - virtual ~SlaveInfo() {} - - private: - DISALLOW_COPY_AND_ASSIGN(SlaveInfo); -}; +typedef void* SlaveInfo; // An interface for the master process delegate (which lives in the master // process). -class MOJO_SYSTEM_IMPL_EXPORT MasterProcessDelegate { +class MOJO_SYSTEM_IMPL_EXPORT MasterProcessDelegate : public ProcessDelegate { public: + ProcessType GetType() const override; + // Called when contact with the slave process specified by |slave_info| has // been lost. // TODO(vtl): Obviously, there needs to be a suitable embedder API for // connecting to a process. What will it be? Mention that here once it exists. - virtual void OnSlaveDisconnect(scoped_ptr<SlaveInfo> slave_info) = 0; + virtual void OnSlaveDisconnect(SlaveInfo slave_info) = 0; protected: MasterProcessDelegate() {} - virtual ~MasterProcessDelegate() {} + ~MasterProcessDelegate() override {} private: DISALLOW_COPY_AND_ASSIGN(MasterProcessDelegate); }; +inline ProcessType MasterProcessDelegate::GetType() const { + return ProcessType::MASTER; +} + } // namespace embedder } // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/embedder/platform_support.h b/third_party/mojo/src/mojo/edk/embedder/platform_support.h index 4556ee3..80ee81b8 100644 --- a/third_party/mojo/src/mojo/edk/embedder/platform_support.h +++ b/third_party/mojo/src/mojo/edk/embedder/platform_support.h
@@ -18,10 +18,13 @@ // This class is provided by the embedder to implement (typically // platform-dependent) things needed by the Mojo system implementation. +// Implementations must be thread-safe. class MOJO_SYSTEM_IMPL_EXPORT PlatformSupport { public: virtual ~PlatformSupport() {} + virtual void GetCryptoRandomBytes(void* bytes, size_t num_bytes) = 0; + virtual PlatformSharedBuffer* CreateSharedBuffer(size_t num_bytes) = 0; virtual PlatformSharedBuffer* CreateSharedBufferFromHandle( size_t num_bytes,
diff --git a/third_party/mojo/src/mojo/edk/embedder/process_delegate.h b/third_party/mojo/src/mojo/edk/embedder/process_delegate.h new file mode 100644 index 0000000..325c5320 --- /dev/null +++ b/third_party/mojo/src/mojo/edk/embedder/process_delegate.h
@@ -0,0 +1,39 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_EDK_EMBEDDER_PROCESS_DELEGATE_H_ +#define MOJO_EDK_EMBEDDER_PROCESS_DELEGATE_H_ + +#include "base/macros.h" +#include "mojo/edk/embedder/process_type.h" +#include "mojo/edk/system/system_impl_export.h" + +namespace mojo { +namespace embedder { + +// An interface for process delegates. +class MOJO_SYSTEM_IMPL_EXPORT ProcessDelegate { + public: + virtual ProcessType GetType() const; + + // Called when |ShutdownIPCSupport()| has "completed". Note that this is NOT + // called if |ShutdownIPCSupportOnIOThread()| is used instead. + virtual void OnShutdownComplete() = 0; + + protected: + ProcessDelegate() {} + virtual ~ProcessDelegate() {} + + private: + DISALLOW_COPY_AND_ASSIGN(ProcessDelegate); +}; + +inline ProcessType ProcessDelegate::GetType() const { + return ProcessType::NONE; +} + +} // namespace embedder +} // namespace mojo + +#endif // MOJO_EDK_EMBEDDER_PROCESS_DELEGATE_H_
diff --git a/third_party/mojo/src/mojo/edk/embedder/process_type.h b/third_party/mojo/src/mojo/edk/embedder/process_type.h new file mode 100644 index 0000000..87292df9 --- /dev/null +++ b/third_party/mojo/src/mojo/edk/embedder/process_type.h
@@ -0,0 +1,26 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_EDK_EMBEDDER_PROCESS_TYPE_H_ +#define MOJO_EDK_EMBEDDER_PROCESS_TYPE_H_ + +namespace mojo { +namespace embedder { + +enum class ProcessType { + // |InitIPCSupport()| has not been called (or |ShutdownIPCSupport()| has been + // called). + UNINITIALIZED, + // Process without connection management. + NONE, + // Master process. + MASTER, + // Slave process. + SLAVE, +}; + +} // namespace embedder +} // namespace mojo + +#endif // MOJO_EDK_EMBEDDER_PROCESS_TYPE_H_
diff --git a/third_party/mojo/src/mojo/edk/embedder/simple_platform_support.cc b/third_party/mojo/src/mojo/edk/embedder/simple_platform_support.cc index c59cfb3..50240870 100644 --- a/third_party/mojo/src/mojo/edk/embedder/simple_platform_support.cc +++ b/third_party/mojo/src/mojo/edk/embedder/simple_platform_support.cc
@@ -4,11 +4,17 @@ #include "mojo/edk/embedder/simple_platform_support.h" +#include "crypto/random.h" #include "mojo/edk/embedder/simple_platform_shared_buffer.h" namespace mojo { namespace embedder { +void SimplePlatformSupport::GetCryptoRandomBytes(void* bytes, + size_t num_bytes) { + crypto::RandBytes(bytes, num_bytes); +} + PlatformSharedBuffer* SimplePlatformSupport::CreateSharedBuffer( size_t num_bytes) { return SimplePlatformSharedBuffer::Create(num_bytes);
diff --git a/third_party/mojo/src/mojo/edk/embedder/simple_platform_support.h b/third_party/mojo/src/mojo/edk/embedder/simple_platform_support.h index 2013f8d..9be7dc0 100644 --- a/third_party/mojo/src/mojo/edk/embedder/simple_platform_support.h +++ b/third_party/mojo/src/mojo/edk/embedder/simple_platform_support.h
@@ -22,6 +22,7 @@ SimplePlatformSupport() {} ~SimplePlatformSupport() override {} + void GetCryptoRandomBytes(void* bytes, size_t num_bytes) override; PlatformSharedBuffer* CreateSharedBuffer(size_t num_bytes) override; PlatformSharedBuffer* CreateSharedBufferFromHandle( size_t num_bytes,
diff --git a/third_party/mojo/src/mojo/edk/embedder/slave_process_delegate.h b/third_party/mojo/src/mojo/edk/embedder/slave_process_delegate.h index 1c55a7a..d9592154 100644 --- a/third_party/mojo/src/mojo/edk/embedder/slave_process_delegate.h +++ b/third_party/mojo/src/mojo/edk/embedder/slave_process_delegate.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "mojo/edk/embedder/process_delegate.h" #include "mojo/edk/system/system_impl_export.h" namespace mojo { @@ -14,8 +15,10 @@ // An interface for the slave process delegate (which lives in each slave // process). -class MOJO_SYSTEM_IMPL_EXPORT SlaveProcessDelegate { +class MOJO_SYSTEM_IMPL_EXPORT SlaveProcessDelegate : public ProcessDelegate { public: + ProcessType GetType() const override; + // Called when contact with the master process has been lost. // TODO(vtl): Obviously, there needs to be a suitable embedder API for // connecting to the master process. What will it be? Mention that here once @@ -24,12 +27,16 @@ protected: SlaveProcessDelegate() {} - virtual ~SlaveProcessDelegate() {} + ~SlaveProcessDelegate() override {} private: DISALLOW_COPY_AND_ASSIGN(SlaveProcessDelegate); }; +inline ProcessType SlaveProcessDelegate::GetType() const { + return ProcessType::SLAVE; +} + } // namespace embedder } // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/embedder/test_embedder.cc b/third_party/mojo/src/mojo/edk/embedder/test_embedder.cc index 3412626..791a888 100644 --- a/third_party/mojo/src/mojo/edk/embedder/test_embedder.cc +++ b/third_party/mojo/src/mojo/edk/embedder/test_embedder.cc
@@ -46,9 +46,9 @@ } bool Shutdown() { - CHECK(internal::g_channel_manager); - delete internal::g_channel_manager; - internal::g_channel_manager = nullptr; + // If |InitIPCSupport()| was called, then |ShutdownIPCSupport()| must have + // been called first. + CHECK(internal::g_process_type == ProcessType::UNINITIALIZED); CHECK(internal::g_core); bool rv = system::internal::ShutdownCheckNoLeaks(internal::g_core);
diff --git a/third_party/mojo/src/mojo/edk/js/core.cc b/third_party/mojo/src/mojo/edk/js/core.cc index c06977d6..cfa58a59 100644 --- a/third_party/mojo/src/mojo/edk/js/core.cc +++ b/third_party/mojo/src/mojo/edk/js/core.cc
@@ -356,8 +356,6 @@ .SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_NONE", MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE) - .SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD", - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD) .SetValue("WRITE_DATA_FLAG_NONE", MOJO_WRITE_DATA_FLAG_NONE) .SetValue("WRITE_DATA_FLAG_ALL_OR_NONE",
diff --git a/third_party/mojo/src/mojo/edk/js/tests/BUILD.gn b/third_party/mojo/src/mojo/edk/js/tests/BUILD.gn index 72e1c8f5..c9711c76 100644 --- a/third_party/mojo/src/mojo/edk/js/tests/BUILD.gn +++ b/third_party/mojo/src/mojo/edk/js/tests/BUILD.gn
@@ -17,7 +17,7 @@ "mojo/edk/js", "mojo/edk/test:test_support", ] - + mojo_sdk_deps = [ "mojo/public/cpp/bindings", "mojo/public/cpp/system",
diff --git a/third_party/mojo/src/mojo/edk/js/tests/connection_tests.js b/third_party/mojo/src/mojo/edk/js/tests/connection_tests.js index 17009d9a..ff59aeb 100644 --- a/third_party/mojo/src/mojo/edk/js/tests/connection_tests.js +++ b/third_party/mojo/src/mojo/edk/js/tests/connection_tests.js
@@ -83,14 +83,15 @@ function createPeerConnection(handle, stubClass, proxyClass) { var c = new connection.Connection(handle, stubClass, proxyClass); - c.local.peer = c.remote; - c.remote.peer = c.local; + if (c.local) + c.local.peer = c.remote; + if (c.remote) + c.remote.peer = c.local; return c; } function testClientServer() { var receivedFrobinate = false; - var receivedDidFrobinate = false; // ServiceImpl ------------------------------------------------------------ @@ -107,21 +108,7 @@ expect(baz).toBeTruthy(); expect(core.close(port)).toBe(core.RESULT_OK); - this.peer.didFrobinate(42); - }; - - // ServiceClientImpl ------------------------------------------------------ - - function ServiceClientImpl() { - } - - ServiceClientImpl.prototype = - Object.create(sample_service.ServiceClient.stubClass.prototype); - - ServiceClientImpl.prototype.didFrobinate = function(result) { - receivedDidFrobinate = true; - - expect(result).toBe(42); + return Promise.resolve(42); }; var pipe = core.createMessagePipe(); @@ -129,10 +116,10 @@ var sourcePipe = core.createMessagePipe(); var connection0 = createPeerConnection( - pipe.handle0, ServiceImpl, sample_service.ServiceClient.proxyClass); + pipe.handle0, ServiceImpl); var connection1 = createPeerConnection( - pipe.handle1, ServiceClientImpl, sample_service.Service.proxyClass); + pipe.handle1, undefined, sample_service.Service.proxyClass); var foo = new sample_service.Foo(); foo.bar = new sample_service.Bar(); @@ -143,7 +130,6 @@ mockSupport.pumpOnce(core.RESULT_OK); expect(receivedFrobinate).toBeTruthy(); - expect(receivedDidFrobinate).toBeTruthy(); connection0.close(); connection1.close(); @@ -179,8 +165,7 @@ var foo = new sample_service.Foo(); foo.bar = new sample_service.Bar(); - // TODO(darin): crbug.com/357043: pass null in place of |foo| here. - connection1.remote.frobinate(foo, true, null); + connection1.remote.frobinate(null, true, null); // Write failures are not reported. expect(connection1.encounteredError()).toBeFalsy(); @@ -213,24 +198,15 @@ return Promise.resolve({a: a, b: b}); }; - // ProviderClientImpl ------------------------------------------------------ - - function ProviderClientImpl() { - } - - ProviderClientImpl.prototype = - Object.create(sample_interfaces.ProviderClient.stubClass.prototype); - var pipe = core.createMessagePipe(); var connection0 = createPeerConnection( pipe.handle0, - ProviderImpl, - sample_interfaces.ProviderClient.proxyClass); + ProviderImpl); var connection1 = createPeerConnection( pipe.handle1, - ProviderClientImpl, + undefined, sample_interfaces.Provider.proxyClass); var origReadMessage = core.readMessage;
diff --git a/third_party/mojo/src/mojo/edk/js/tests/sample_service_tests.js b/third_party/mojo/src/mojo/edk/js/tests/sample_service_tests.js index 2afdf3e..ac8ce2e 100644 --- a/third_party/mojo/src/mojo/edk/js/tests/sample_service_tests.js +++ b/third_party/mojo/src/mojo/edk/js/tests/sample_service_tests.js
@@ -146,14 +146,14 @@ function SimpleMessageReceiver() { } - SimpleMessageReceiver.prototype.accept = function(message) { + SimpleMessageReceiver.prototype.acceptAndExpectResponse = function(message) { if (dumpMessageAsHex) { var uint8Array = new Uint8Array(message.buffer.arrayBuffer); console.log(hexdump.dumpArray(uint8Array)); } // Imagine some IPC happened here. var serviceImpl = new ServiceImpl(); - serviceImpl.accept(message); + return serviceImpl.acceptWithResponder(message, { accept: function() {} }); }; var serviceProxy = new sample.Service.proxyClass;
diff --git a/third_party/mojo/src/mojo/edk/system/BUILD.gn b/third_party/mojo/src/mojo/edk/system/BUILD.gn index a386ff91..9b093a0 100644 --- a/third_party/mojo/src/mojo/edk/system/BUILD.gn +++ b/third_party/mojo/src/mojo/edk/system/BUILD.gn
@@ -44,6 +44,8 @@ "core.h", "data_pipe.cc", "data_pipe.h", + "data_pipe_impl.cc", + "data_pipe_impl.h", "data_pipe_consumer_dispatcher.cc", "data_pipe_consumer_dispatcher.h", "data_pipe_producer_dispatcher.cc", @@ -57,8 +59,8 @@ "handle_table.h", "incoming_endpoint.cc", "incoming_endpoint.h", - "local_data_pipe.cc", - "local_data_pipe.h", + "local_data_pipe_impl.cc", + "local_data_pipe_impl.h", "local_message_pipe_endpoint.cc", "local_message_pipe_endpoint.h", "mapping_table.cc", @@ -86,6 +88,11 @@ "raw_channel.h", "raw_channel_posix.cc", "raw_channel_win.cc", + "remote_consumer_data_pipe_impl.cc", + "remote_consumer_data_pipe_impl.h", + "remote_data_pipe_ack.h", + "remote_producer_data_pipe_impl.cc", + "remote_producer_data_pipe_impl.h", "shared_buffer_dispatcher.cc", "shared_buffer_dispatcher.h", "simple_dispatcher.cc", @@ -117,7 +124,6 @@ deps = [ "//base", "//base/third_party/dynamic_annotations", - "//crypto", ] allow_circular_includes_from = [ "../embedder" ] @@ -142,6 +148,7 @@ deps = [ "//base", "//base/test:test_support", + "../../public/c/system", ] } @@ -156,9 +163,10 @@ "core_test_base.cc", "core_test_base.h", "core_unittest.cc", + "data_pipe_impl_unittest.cc", "data_pipe_unittest.cc", "dispatcher_unittest.cc", - "local_data_pipe_unittest.cc", + "local_data_pipe_impl_unittest.cc", "memory_unittest.cc", "message_pipe_dispatcher_unittest.cc", "message_pipe_test_utils.cc", @@ -168,6 +176,7 @@ "options_validation_unittest.cc", "platform_handle_dispatcher_unittest.cc", "raw_channel_unittest.cc", + "remote_data_pipe_impl_unittest.cc", "remote_message_pipe_unittest.cc", "run_all_unittests.cc", "shared_buffer_dispatcher_unittest.cc", @@ -194,8 +203,8 @@ test("mojo_message_pipe_perftests") { sources = [ "message_pipe_perftest.cc", - "message_pipe_test_utils.cc", "message_pipe_test_utils.h", + "message_pipe_test_utils.cc", ] deps = [
diff --git a/third_party/mojo/src/mojo/edk/system/async_waiter.cc b/third_party/mojo/src/mojo/edk/system/async_waiter.cc index 071eb01..4f539b9c 100644 --- a/third_party/mojo/src/mojo/edk/system/async_waiter.cc +++ b/third_party/mojo/src/mojo/edk/system/async_waiter.cc
@@ -7,7 +7,7 @@ namespace mojo { namespace system { -AsyncWaiter::AsyncWaiter(AwakeCallback callback) : callback_(callback) { +AsyncWaiter::AsyncWaiter(const AwakeCallback& callback) : callback_(callback) { } AsyncWaiter::~AsyncWaiter() {
diff --git a/third_party/mojo/src/mojo/edk/system/async_waiter.h b/third_party/mojo/src/mojo/edk/system/async_waiter.h index da412c0..df3b4820 100644 --- a/third_party/mojo/src/mojo/edk/system/async_waiter.h +++ b/third_party/mojo/src/mojo/edk/system/async_waiter.h
@@ -20,7 +20,7 @@ typedef base::Callback<void(MojoResult)> AwakeCallback; // |callback| must satisfy the same contract as |Awakable::Awake()|. - explicit AsyncWaiter(AwakeCallback callback); + explicit AsyncWaiter(const AwakeCallback& callback); virtual ~AsyncWaiter(); private:
diff --git a/third_party/mojo/src/mojo/edk/system/channel_manager.cc b/third_party/mojo/src/mojo/edk/system/channel_manager.cc index 634accc8..a5301b39 100644 --- a/third_party/mojo/src/mojo/edk/system/channel_manager.cc +++ b/third_party/mojo/src/mojo/edk/system/channel_manager.cc
@@ -18,27 +18,68 @@ namespace { -void ShutdownChannelHelper(const ChannelInfo& channel_info) { - if (base::MessageLoopProxy::current() == - channel_info.channel_thread_task_runner) { - channel_info.channel->Shutdown(); +void ShutdownChannelHelper( + const ChannelInfo& channel_info, + const base::Closure& callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner) { + DCHECK(base::MessageLoopProxy::current() == + channel_info.channel_thread_task_runner); + channel_info.channel->Shutdown(); + if (callback_thread_task_runner) { + bool ok = callback_thread_task_runner->PostTask(FROM_HERE, callback); + DCHECK(ok); } else { - channel_info.channel->WillShutdownSoon(); - channel_info.channel_thread_task_runner->PostTask( - FROM_HERE, base::Bind(&Channel::Shutdown, channel_info.channel)); + callback.Run(); } } } // namespace -ChannelManager::ChannelManager(embedder::PlatformSupport* platform_support) - : platform_support_(platform_support) { +ChannelManager::ChannelManager( + embedder::PlatformSupport* platform_support, + scoped_refptr<base::TaskRunner> io_thread_task_runner, + ConnectionManager* connection_manager) + : platform_support_(platform_support), + io_thread_task_runner_(io_thread_task_runner), + connection_manager_(connection_manager) { + DCHECK(platform_support_); + DCHECK(io_thread_task_runner_); + // (|connection_manager_| may be null.) } ChannelManager::~ChannelManager() { - // No need to take the lock. - for (const auto& map_elem : channel_infos_) - ShutdownChannelHelper(map_elem.second); + // |Shutdown()| must be called before destruction and have been completed. + // TODO(vtl): This doesn't verify the above condition very strictly at all + // (e.g., we may never have had any channels, or we may have manually shut all + // the channels down). + DCHECK(channel_infos_.empty()); +} + +void ChannelManager::ShutdownOnIOThread() { + // Taking this lock really shouldn't be necessary, but we do it for + // consistency. + base::hash_map<ChannelId, ChannelInfo> channel_infos; + { + base::AutoLock locker(lock_); + channel_infos.swap(channel_infos_); + } + + for (const auto& map_elem : channel_infos) { + const ChannelInfo& channel_info = map_elem.second; + DCHECK(base::MessageLoopProxy::current() == + channel_info.channel_thread_task_runner); + channel_info.channel->Shutdown(); + } +} + +void ChannelManager::Shutdown( + const base::Closure& callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner) { + bool ok = io_thread_task_runner_->PostTask( + FROM_HERE, + base::Bind(&ChannelManager::ShutdownHelper, base::Unretained(this), + callback, callback_thread_task_runner)); + DCHECK(ok); } scoped_refptr<MessagePipeDispatcher> ChannelManager::CreateChannelOnIOThread( @@ -57,9 +98,10 @@ ChannelId channel_id, embedder::ScopedPlatformHandle platform_handle, scoped_refptr<base::TaskRunner> io_thread_task_runner, - base::Closure callback, + const base::Closure& callback, scoped_refptr<base::TaskRunner> callback_thread_task_runner) { - DCHECK(io_thread_task_runner); + // TODO(vtl): Remove |io_thread_task_runner| argument. + DCHECK_EQ(io_thread_task_runner, io_thread_task_runner_); DCHECK(!callback.is_null()); // (|callback_thread_task_runner| may be null.) @@ -67,12 +109,13 @@ scoped_refptr<system::MessagePipeDispatcher> dispatcher = system::MessagePipeDispatcher::CreateRemoteMessagePipe( &bootstrap_channel_endpoint); - io_thread_task_runner->PostTask( + bool ok = io_thread_task_runner_->PostTask( FROM_HERE, base::Bind(&ChannelManager::CreateChannelHelper, base::Unretained(this), channel_id, base::Passed(&platform_handle), bootstrap_channel_endpoint, callback, callback_thread_task_runner)); + DCHECK(ok); return dispatcher; } @@ -87,7 +130,7 @@ GetChannel(channel_id)->WillShutdownSoon(); } -void ChannelManager::ShutdownChannel(ChannelId channel_id) { +void ChannelManager::ShutdownChannelOnIOThread(ChannelId channel_id) { ChannelInfo channel_info; { base::AutoLock locker(lock_); @@ -96,7 +139,40 @@ channel_info.Swap(&it->second); channel_infos_.erase(it); } - ShutdownChannelHelper(channel_info); + DCHECK(base::MessageLoopProxy::current() == + channel_info.channel_thread_task_runner); + channel_info.channel->Shutdown(); +} + +void ChannelManager::ShutdownChannel( + ChannelId channel_id, + const base::Closure& callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner) { + ChannelInfo channel_info; + { + base::AutoLock locker(lock_); + auto it = channel_infos_.find(channel_id); + DCHECK(it != channel_infos_.end()); + channel_info.Swap(&it->second); + channel_infos_.erase(it); + } + channel_info.channel->WillShutdownSoon(); + bool ok = channel_info.channel_thread_task_runner->PostTask( + FROM_HERE, base::Bind(&ShutdownChannelHelper, channel_info, callback, + callback_thread_task_runner)); + DCHECK(ok); +} + +void ChannelManager::ShutdownHelper( + const base::Closure& callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner) { + ShutdownOnIOThread(); + if (callback_thread_task_runner) { + bool ok = callback_thread_task_runner->PostTask(FROM_HERE, callback); + DCHECK(ok); + } else { + callback.Run(); + } } void ChannelManager::CreateChannelOnIOThreadHelper( @@ -126,14 +202,16 @@ ChannelId channel_id, embedder::ScopedPlatformHandle platform_handle, scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint, - base::Closure callback, + const base::Closure& callback, scoped_refptr<base::TaskRunner> callback_thread_task_runner) { CreateChannelOnIOThreadHelper(channel_id, platform_handle.Pass(), bootstrap_channel_endpoint); - if (callback_thread_task_runner) - callback_thread_task_runner->PostTask(FROM_HERE, callback); - else + if (callback_thread_task_runner) { + bool ok = callback_thread_task_runner->PostTask(FROM_HERE, callback); + DCHECK(ok); + } else { callback.Run(); + } } } // namespace system
diff --git a/third_party/mojo/src/mojo/edk/system/channel_manager.h b/third_party/mojo/src/mojo/edk/system/channel_manager.h index da3e030..77ff953 100644 --- a/third_party/mojo/src/mojo/edk/system/channel_manager.h +++ b/third_party/mojo/src/mojo/edk/system/channel_manager.h
@@ -29,6 +29,7 @@ class Channel; class ChannelEndpoint; +class ConnectionManager; class MessagePipeDispatcher; // IDs for |Channel|s managed by a |ChannelManager|. (IDs should be thought of @@ -42,17 +43,37 @@ // specifically noted. class MOJO_SYSTEM_IMPL_EXPORT ChannelManager { public: - // |*platform_support| must remain alive longer than this object. - explicit ChannelManager(embedder::PlatformSupport* platform_support); + // |io_thread_task_runner| should be the |TaskRunner| for the I/O thread, on + // which this channel manager will create all channels. Connection manager is + // optional and may be null. All arguments (if non-null) must remain alive at + // least until after shutdown completion. + ChannelManager(embedder::PlatformSupport* platform_support, + scoped_refptr<base::TaskRunner> io_thread_task_runner, + ConnectionManager* connection_manager); ~ChannelManager(); + // Shuts down the channel manager, including shutting down all channels (as if + // |ShutdownChannelOnIOThread()| were called for each channel). This must be + // called from the I/O thread (given to the constructor) and completes + // synchronously. This, or |Shutdown()|, must be called before destroying this + // object. + void ShutdownOnIOThread(); + + // Like |ShutdownOnIOThread()|, but may be called from any thread. On + // completion, will call |callback| ("on" |io_thread_task_runner| if + // |callback_thread_task_runner| is null else by posted using + // |callback_thread_task_runner|). Note: This will always post a task to the + // I/O thread, even it is the current thread. + // TODO(vtl): Consider if this is really necessary, since it only has one use + // (in tests). + void Shutdown(const base::Closure& callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner); + // Creates a |Channel| and adds it to the set of channels managed by this - // |ChannelManager|. |channel_id| should be a valid |ChannelId| (i.e., - // nonzero) not "assigned" to any other |Channel| being managed by this + // |ChannelManager|. This must be called from the I/O thread (given to the + // constructor). |channel_id| should be a valid |ChannelId| (i.e., nonzero) + // not "assigned" to any other |Channel| being managed by this // |ChannelManager|. - // TODO(vtl): Currently, this should be called on any I/O thread (which will - // become the new channel's "channel thread"). Eventually, the channel manager - // will have an assigned I/O thread, on which this must be called. scoped_refptr<MessagePipeDispatcher> CreateChannelOnIOThread( ChannelId channel_id, embedder::ScopedPlatformHandle platform_handle); @@ -69,7 +90,7 @@ ChannelId channel_id, embedder::ScopedPlatformHandle platform_handle, scoped_refptr<base::TaskRunner> io_thread_task_runner, - base::Closure callback, + const base::Closure& callback, scoped_refptr<base::TaskRunner> callback_thread_task_runner); // Gets the |Channel| with the given ID (which must exist). @@ -82,14 +103,31 @@ // the channel). void WillShutdownChannel(ChannelId channel_id); - // Shuts down the channel specified by the given ID. It is up to the caller to - // guarantee that this is only called once per channel (that was added using - // |CreateChannelOnIOThread()|). If called from the channel's creation thread - // (i.e., |base::MessageLoopProxy::current()| is the channel thread's - // |TaskRunner|), this will complete synchronously. - void ShutdownChannel(ChannelId channel_id); + // Shuts down the channel specified by the given ID. This, or + // |ShutdownChannel()|, should be called once per channel (created using + // |CreateChannelOnIOThread()| or |CreateChannel()|). This must be called from + // the channel's "channel thread", and completes synchronously. + // TODO(vtl): "channel thread" will become "this object's I/O thread". + void ShutdownChannelOnIOThread(ChannelId channel_id); + + // Like |ShutdownChannelOnIOThread()|, but may be called from any thread. It + // will always post a task to the channel's "channel thread", and post + // |callback| to |callback_thread_task_runner| (or execute it directly on the + // "channel thread" if |callback_thread_task_runner| is null) on completion. + // TODO(vtl): "channel thread" will become "this object's I/O thread". + void ShutdownChannel( + ChannelId channel_id, + const base::Closure& callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner); + + ConnectionManager* connection_manager() const { return connection_manager_; } private: + // Used by |Shutdown()|. Called on the I/O thread. + void ShutdownHelper( + const base::Closure& callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner); + // Used by |CreateChannelOnIOThread()| and |CreateChannelHelper()|. Called on // the I/O thread. void CreateChannelOnIOThreadHelper( @@ -102,10 +140,13 @@ ChannelId channel_id, embedder::ScopedPlatformHandle platform_handle, scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint, - base::Closure callback, + const base::Closure& callback, scoped_refptr<base::TaskRunner> callback_thread_task_runner); + // Note: These must not be used after shutdown. embedder::PlatformSupport* const platform_support_; + const scoped_refptr<base::TaskRunner> io_thread_task_runner_; + ConnectionManager* const connection_manager_; // Note: |Channel| methods should not be called under |lock_|. mutable base::Lock lock_; // Protects the members below.
diff --git a/third_party/mojo/src/mojo/edk/system/channel_manager_unittest.cc b/third_party/mojo/src/mojo/edk/system/channel_manager_unittest.cc index 86ab4a0..1a3176eec 100644 --- a/third_party/mojo/src/mojo/edk/system/channel_manager_unittest.cc +++ b/third_party/mojo/src/mojo/edk/system/channel_manager_unittest.cc
@@ -10,10 +10,7 @@ #include "base/message_loop/message_loop_proxy.h" #include "base/run_loop.h" #include "base/task_runner.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" #include "base/threading/simple_thread.h" -#include "base/time/time.h" #include "mojo/edk/embedder/platform_channel_pair.h" #include "mojo/edk/embedder/simple_platform_support.h" #include "mojo/edk/system/channel.h" @@ -27,42 +24,44 @@ class ChannelManagerTest : public testing::Test { public: - ChannelManagerTest() : message_loop_(base::MessageLoop::TYPE_IO) {} + ChannelManagerTest() + : message_loop_(base::MessageLoop::TYPE_IO), + channel_manager_(&platform_support_, + message_loop_.task_runner(), + nullptr) {} ~ChannelManagerTest() override {} protected: - embedder::SimplePlatformSupport* platform_support() { - return &platform_support_; - } - base::MessageLoop* message_loop() { return &message_loop_; } + ChannelManager& channel_manager() { return channel_manager_; } private: embedder::SimplePlatformSupport platform_support_; base::MessageLoop message_loop_; + // Note: This should be *after* the above, since they must be initialized + // before it (and should outlive it). + ChannelManager channel_manager_; DISALLOW_COPY_AND_ASSIGN(ChannelManagerTest); }; TEST_F(ChannelManagerTest, Basic) { - ChannelManager cm(platform_support()); - embedder::PlatformChannelPair channel_pair; const ChannelId id = 1; scoped_refptr<MessagePipeDispatcher> d = - cm.CreateChannelOnIOThread(id, channel_pair.PassServerHandle()); + channel_manager().CreateChannelOnIOThread( + id, channel_pair.PassServerHandle()); - scoped_refptr<Channel> ch = cm.GetChannel(id); + scoped_refptr<Channel> ch = channel_manager().GetChannel(id); EXPECT_TRUE(ch); // |ChannelManager| should have a ref. EXPECT_FALSE(ch->HasOneRef()); - cm.WillShutdownChannel(id); + channel_manager().WillShutdownChannel(id); // |ChannelManager| should still have a ref. EXPECT_FALSE(ch->HasOneRef()); - cm.ShutdownChannel(id); - // On the "I/O" thread, so shutdown should happen synchronously. + channel_manager().ShutdownChannelOnIOThread(id); // |ChannelManager| should have given up its ref. EXPECT_TRUE(ch->HasOneRef()); @@ -70,33 +69,33 @@ } TEST_F(ChannelManagerTest, TwoChannels) { - ChannelManager cm(platform_support()); - embedder::PlatformChannelPair channel_pair; const ChannelId id1 = 1; scoped_refptr<MessagePipeDispatcher> d1 = - cm.CreateChannelOnIOThread(id1, channel_pair.PassServerHandle()); + channel_manager().CreateChannelOnIOThread( + id1, channel_pair.PassServerHandle()); const ChannelId id2 = 2; scoped_refptr<MessagePipeDispatcher> d2 = - cm.CreateChannelOnIOThread(id2, channel_pair.PassClientHandle()); + channel_manager().CreateChannelOnIOThread( + id2, channel_pair.PassClientHandle()); - scoped_refptr<Channel> ch1 = cm.GetChannel(id1); + scoped_refptr<Channel> ch1 = channel_manager().GetChannel(id1); EXPECT_TRUE(ch1); - scoped_refptr<Channel> ch2 = cm.GetChannel(id2); + scoped_refptr<Channel> ch2 = channel_manager().GetChannel(id2); EXPECT_TRUE(ch2); // Calling |WillShutdownChannel()| multiple times (on |id1|) is okay. - cm.WillShutdownChannel(id1); - cm.WillShutdownChannel(id1); + channel_manager().WillShutdownChannel(id1); + channel_manager().WillShutdownChannel(id1); EXPECT_FALSE(ch1->HasOneRef()); // Not calling |WillShutdownChannel()| (on |id2|) is okay too. - cm.ShutdownChannel(id1); + channel_manager().ShutdownChannelOnIOThread(id1); EXPECT_TRUE(ch1->HasOneRef()); - cm.ShutdownChannel(id2); + channel_manager().ShutdownChannelOnIOThread(id2); EXPECT_TRUE(ch2->HasOneRef()); EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); @@ -110,7 +109,7 @@ OtherThread(scoped_refptr<base::TaskRunner> task_runner, ChannelManager* channel_manager, ChannelId channel_id, - base::Closure quit_closure) + const base::Closure& quit_closure) : base::SimpleThread("other_thread"), task_runner_(task_runner), channel_manager_(channel_manager), @@ -132,20 +131,12 @@ // |ChannelManager| should still have a ref. EXPECT_FALSE(ch->HasOneRef()); - channel_manager_->ShutdownChannel(channel_id_); - // This doesn't happen synchronously, so we "wait" until it does. - // TODO(vtl): Probably |Channel| should provide some notification of being - // shut down. - base::TimeTicks start_time(base::TimeTicks::Now()); - for (;;) { - if (ch->HasOneRef()) - break; - - // Check, instead of assert, since if things go wrong, dying is more - // reliable than tearing down. - CHECK_LT(base::TimeTicks::Now() - start_time, - TestTimeouts::action_timeout()); - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); + { + base::MessageLoop message_loop; + base::RunLoop run_loop; + channel_manager_->ShutdownChannel(channel_id_, run_loop.QuitClosure(), + message_loop.task_runner()); + run_loop.Run(); } CHECK(task_runner_->PostTask(FROM_HERE, quit_closure_)); @@ -160,16 +151,15 @@ }; TEST_F(ChannelManagerTest, CallsFromOtherThread) { - ChannelManager cm(platform_support()); - embedder::PlatformChannelPair channel_pair; const ChannelId id = 1; scoped_refptr<MessagePipeDispatcher> d = - cm.CreateChannelOnIOThread(id, channel_pair.PassServerHandle()); + channel_manager().CreateChannelOnIOThread( + id, channel_pair.PassServerHandle()); base::RunLoop run_loop; - OtherThread thread(base::MessageLoopProxy::current(), &cm, id, + OtherThread thread(base::MessageLoopProxy::current(), &channel_manager(), id, run_loop.QuitClosure()); thread.Start(); run_loop.Run();
diff --git a/third_party/mojo/src/mojo/edk/system/connection_manager.h b/third_party/mojo/src/mojo/edk/system/connection_manager.h index fede7a54..921d19c55 100644 --- a/third_party/mojo/src/mojo/edk/system/connection_manager.h +++ b/third_party/mojo/src/mojo/edk/system/connection_manager.h
@@ -6,6 +6,7 @@ #define MOJO_EDK_SYSTEM_CONNECTION_MANAGER_H_ #include "base/macros.h" +#include "mojo/edk/system/system_impl_export.h" #include "mojo/edk/system/unique_identifier.h" namespace mojo { @@ -62,15 +63,21 @@ // connected to the master by a special dedicated |RawChannel|, on which it does // synchronous IPC (note, however, that the master should never block on any // slave). -class ConnectionManager { +class MOJO_SYSTEM_IMPL_EXPORT ConnectionManager { public: - // All of these methods return true on success or false on failure. Failure is - // obviously fatal for the establishment of a particular connection, but - // should not be treated as fatal to the process. Failure may, e.g., be caused - // by a misbehaving (malicious) untrusted peer process. + virtual ~ConnectionManager() {} + + // Shuts down this connection manager. No other methods may be called after + // this is (or while it is being) called. + virtual void Shutdown() = 0; // TODO(vtl): Add a "get my own process identifier" method? + // All of the methods below return true on success or false on failure. + // Failure is obviously fatal for the establishment of a particular + // connection, but should not be treated as fatal to the process. Failure may, + // e.g., be caused by a misbehaving (malicious) untrusted peer process. + // Allows a process who makes the identical call (with equal |connection_id|) // to connect to the calling process. (On success, there will be a "pending // connection" for the given |connection_id| for the calling process.) @@ -93,7 +100,6 @@ protected: ConnectionManager() {} - virtual ~ConnectionManager() {} private: DISALLOW_COPY_AND_ASSIGN(ConnectionManager);
diff --git a/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc b/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc index f1939a0..fea0920 100644 --- a/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc +++ b/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc
@@ -17,6 +17,7 @@ #include "base/threading/thread_checker.h" #include "mojo/edk/embedder/master_process_delegate.h" #include "mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/edk/embedder/simple_platform_support.h" #include "mojo/edk/embedder/slave_process_delegate.h" #include "mojo/edk/system/master_connection_manager.h" #include "mojo/edk/system/slave_connection_manager.h" @@ -63,10 +64,10 @@ process_identifier != kMasterProcessIdentifier; } -class TestSlaveInfo : public embedder::SlaveInfo { +class TestSlaveInfo { public: explicit TestSlaveInfo(const std::string& name) : name_(name) {} - ~TestSlaveInfo() override { CHECK(thread_checker_.CalledOnValidThread()); } + ~TestSlaveInfo() { CHECK(thread_checker_.CalledOnValidThread()); } const std::string& name() const { return name_; } @@ -85,7 +86,7 @@ SlaveConnectionManager* slave, const std::string& slave_name) { embedder::PlatformChannelPair platform_channel_pair; - master->AddSlave(make_scoped_ptr(new TestSlaveInfo(slave_name)), + master->AddSlave(new TestSlaveInfo(slave_name), platform_channel_pair.PassServerHandle()); slave->Init(base::MessageLoop::current()->task_runner(), slave_process_delegate, platform_channel_pair.PassClientHandle()); @@ -113,14 +114,16 @@ } // |embedder::MasterProcessDelegate| implementation: - void OnSlaveDisconnect(scoped_ptr<embedder::SlaveInfo> slave_info) override { + void OnShutdownComplete() override { NOTREACHED(); } + + void OnSlaveDisconnect(embedder::SlaveInfo slave_info) override { CHECK(thread_checker_.CalledOnValidThread()); on_slave_disconnect_calls_++; last_slave_disconnect_name_ = - static_cast<TestSlaveInfo*>(slave_info.get())->name(); + static_cast<TestSlaveInfo*>(slave_info)->name(); DVLOG(1) << "Disconnected from slave process " << last_slave_disconnect_name_; - slave_info.reset(); + delete static_cast<TestSlaveInfo*>(slave_info); if (current_run_loop_) current_run_loop_->Quit(); @@ -155,6 +158,8 @@ } // |embedder::SlaveProcessDelegate| implementation: + void OnShutdownComplete() override { NOTREACHED(); } + void OnMasterDisconnect() override { CHECK(thread_checker_.CalledOnValidThread()); on_master_disconnect_calls_++; @@ -178,12 +183,15 @@ ConnectionManagerTest() {} ~ConnectionManagerTest() override {} + embedder::PlatformSupport* platform_support() { return &platform_support_; } + base::MessageLoop& message_loop() { return message_loop_; } MockMasterProcessDelegate& master_process_delegate() { return master_process_delegate_; } private: + embedder::SimplePlatformSupport platform_support_; base::MessageLoop message_loop_; MockMasterProcessDelegate master_process_delegate_; @@ -203,7 +211,8 @@ SlaveConnectionManager slave2; ConnectSlave(&master, &slave2_process_delegate, &slave2, "slave2"); - ConnectionIdentifier connection_id = ConnectionIdentifier::Generate(); + ConnectionIdentifier connection_id = + ConnectionIdentifier::Generate(platform_support()); EXPECT_TRUE(slave1.AllowConnect(connection_id)); EXPECT_TRUE(slave2.AllowConnect(connection_id)); @@ -291,7 +300,8 @@ SlaveConnectionManager slave2; ConnectSlave(&master, &slave2_process_delegate, &slave2, "slave2"); - ConnectionIdentifier connection_id = ConnectionIdentifier::Generate(); + ConnectionIdentifier connection_id = + ConnectionIdentifier::Generate(platform_support()); EXPECT_TRUE(slave1.AllowConnect(connection_id)); EXPECT_TRUE(slave2.AllowConnect(connection_id)); @@ -321,7 +331,8 @@ SlaveConnectionManager slave2; ConnectSlave(&master, &slave2_process_delegate, &slave2, "slave2"); - ConnectionIdentifier connection_id = ConnectionIdentifier::Generate(); + ConnectionIdentifier connection_id = + ConnectionIdentifier::Generate(platform_support()); EXPECT_TRUE(slave1.AllowConnect(connection_id)); EXPECT_TRUE(slave2.AllowConnect(connection_id)); @@ -352,7 +363,8 @@ SlaveConnectionManager slave; ConnectSlave(&master, &slave_process_delegate, &slave, "slave"); - ConnectionIdentifier connection_id = ConnectionIdentifier::Generate(); + ConnectionIdentifier connection_id = + ConnectionIdentifier::Generate(platform_support()); EXPECT_TRUE(slave.AllowConnect(connection_id)); EXPECT_TRUE(slave.AllowConnect(connection_id)); @@ -388,7 +400,8 @@ SlaveConnectionManager slave2; ConnectSlave(&master, &slave2_process_delegate, &slave2, "slave2"); - ConnectionIdentifier connection_id = ConnectionIdentifier::Generate(); + ConnectionIdentifier connection_id = + ConnectionIdentifier::Generate(platform_support()); EXPECT_TRUE(slave1.AllowConnect(connection_id)); EXPECT_TRUE(slave2.AllowConnect(connection_id)); @@ -407,7 +420,7 @@ // tracking and is prone to races -- especially if we want slaves to be able // to tear down no-longer-needed connections.) But the slaves should be able // to do the tracking themselves (using the peer process identifiers). - connection_id = ConnectionIdentifier::Generate(); + connection_id = ConnectionIdentifier::Generate(platform_support()); EXPECT_TRUE(slave1.AllowConnect(connection_id)); EXPECT_TRUE(slave2.AllowConnect(connection_id)); @@ -436,7 +449,8 @@ SlaveConnectionManager slave; ConnectSlave(&master, &slave_process_delegate, &slave, "slave"); - ConnectionIdentifier connection_id = ConnectionIdentifier::Generate(); + ConnectionIdentifier connection_id = + ConnectionIdentifier::Generate(platform_support()); EXPECT_TRUE(master.AllowConnect(connection_id)); EXPECT_TRUE(slave.AllowConnect(connection_id)); @@ -463,7 +477,8 @@ master.Init(base::MessageLoop::current()->task_runner(), &master_process_delegate()); - ConnectionIdentifier connection_id = ConnectionIdentifier::Generate(); + ConnectionIdentifier connection_id = + ConnectionIdentifier::Generate(platform_support()); EXPECT_TRUE(master.AllowConnect(connection_id)); EXPECT_TRUE(master.AllowConnect(connection_id)); @@ -494,7 +509,8 @@ SlaveConnectionManager slave; ConnectSlave(&master, &slave_process_delegate, &slave, "slave"); - ConnectionIdentifier connection_id = ConnectionIdentifier::Generate(); + ConnectionIdentifier connection_id = + ConnectionIdentifier::Generate(platform_support()); EXPECT_TRUE(master.AllowConnect(connection_id)); EXPECT_TRUE(slave.AllowConnect(connection_id)); @@ -517,7 +533,7 @@ MockSlaveProcessDelegate slave_process_delegate; SlaveConnectionManager slave; embedder::PlatformChannelPair platform_channel_pair; - master.AddSlave(make_scoped_ptr(new TestSlaveInfo("slave")), + master.AddSlave(new TestSlaveInfo("slave"), platform_channel_pair.PassServerHandle()); master.Shutdown(); // Since we never initialized |slave|, we don't have to shut it down.
diff --git a/third_party/mojo/src/mojo/edk/system/core.cc b/third_party/mojo/src/mojo/edk/system/core.cc index 4460088d..80c3d36 100644 --- a/third_party/mojo/src/mojo/edk/system/core.cc +++ b/third_party/mojo/src/mojo/edk/system/core.cc
@@ -17,7 +17,6 @@ #include "mojo/edk/system/data_pipe_producer_dispatcher.h" #include "mojo/edk/system/dispatcher.h" #include "mojo/edk/system/handle_signals_state.h" -#include "mojo/edk/system/local_data_pipe.h" #include "mojo/edk/system/memory.h" #include "mojo/edk/system/message_pipe.h" #include "mojo/edk/system/message_pipe_dispatcher.h" @@ -100,7 +99,7 @@ MojoResult Core::AsyncWait(MojoHandle handle, MojoHandleSignals signals, - base::Callback<void(MojoResult)> callback) { + const base::Callback<void(MojoResult)>& callback) { scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle); DCHECK(dispatcher); @@ -381,7 +380,7 @@ } DCHECK_NE(handle_pair.second, MOJO_HANDLE_INVALID); - scoped_refptr<DataPipe> data_pipe(new LocalDataPipe(validated_options)); + scoped_refptr<DataPipe> data_pipe(DataPipe::CreateLocal(validated_options)); producer_dispatcher->Init(data_pipe); consumer_dispatcher->Init(data_pipe);
diff --git a/third_party/mojo/src/mojo/edk/system/core.h b/third_party/mojo/src/mojo/edk/system/core.h index 7833193c..aadfb66 100644 --- a/third_party/mojo/src/mojo/edk/system/core.h +++ b/third_party/mojo/src/mojo/edk/system/core.h
@@ -58,7 +58,7 @@ // awakable.h. In particular, it must not call any Mojo system functions. MojoResult AsyncWait(MojoHandle handle, MojoHandleSignals signals, - base::Callback<void(MojoResult)> callback); + const base::Callback<void(MojoResult)>& callback); embedder::PlatformSupport* platform_support() const { return platform_support_;
diff --git a/third_party/mojo/src/mojo/edk/system/data_pipe.cc b/third_party/mojo/src/mojo/edk/system/data_pipe.cc index 2f433bd..c46de2cc 100644 --- a/third_party/mojo/src/mojo/edk/system/data_pipe.cc +++ b/third_party/mojo/src/mojo/edk/system/data_pipe.cc
@@ -10,10 +10,17 @@ #include <limits> #include "base/logging.h" +#include "base/memory/aligned_memory.h" #include "mojo/edk/system/awakable_list.h" +#include "mojo/edk/system/channel.h" #include "mojo/edk/system/configuration.h" +#include "mojo/edk/system/data_pipe_impl.h" +#include "mojo/edk/system/incoming_endpoint.h" +#include "mojo/edk/system/local_data_pipe_impl.h" #include "mojo/edk/system/memory.h" #include "mojo/edk/system/options_validation.h" +#include "mojo/edk/system/remote_consumer_data_pipe_impl.h" +#include "mojo/edk/system/remote_producer_data_pipe_impl.h" namespace mojo { namespace system { @@ -34,7 +41,7 @@ UserPointer<const MojoCreateDataPipeOptions> in_options, MojoCreateDataPipeOptions* out_options) { const MojoCreateDataPipeOptionsFlags kKnownFlags = - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD; + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; *out_options = GetDefaultCreateOptions(); if (in_options.IsNull()) @@ -83,6 +90,177 @@ return MOJO_RESULT_OK; } +// static +DataPipe* DataPipe::CreateLocal( + const MojoCreateDataPipeOptions& validated_options) { + return new DataPipe(true, true, validated_options, + make_scoped_ptr(new LocalDataPipeImpl())); +} + +// static +DataPipe* DataPipe::CreateRemoteProducerFromExisting( + const MojoCreateDataPipeOptions& validated_options, + MessageInTransitQueue* message_queue, + ChannelEndpoint* channel_endpoint) { + scoped_ptr<char, base::AlignedFreeDeleter> buffer; + size_t buffer_num_bytes = 0; + if (!RemoteProducerDataPipeImpl::ProcessMessagesFromIncomingEndpoint( + validated_options, message_queue, &buffer, &buffer_num_bytes)) + return nullptr; + + // Important: This is called under |IncomingEndpoint|'s (which is a + // |ChannelEndpointClient|) lock, in particular from + // |IncomingEndpoint::ConvertToDataPipeConsumer()|. Before releasing that + // lock, it will reset its |endpoint_| member, which makes any later or + // ongoing call to |IncomingEndpoint::OnReadMessage()| return false. This will + // make |ChannelEndpoint::OnReadMessage()| retry, until its |ReplaceClient()| + // is called. + DataPipe* data_pipe = + new DataPipe(false, true, validated_options, + make_scoped_ptr(new RemoteProducerDataPipeImpl( + channel_endpoint, buffer.Pass(), 0, buffer_num_bytes))); + if (channel_endpoint) { + if (!channel_endpoint->ReplaceClient(data_pipe, 0)) + data_pipe->OnDetachFromChannel(0); + } else { + data_pipe->SetProducerClosed(); + } + return data_pipe; +} + +// static +DataPipe* DataPipe::CreateRemoteConsumerFromExisting( + const MojoCreateDataPipeOptions& validated_options, + size_t consumer_num_bytes, + MessageInTransitQueue* message_queue, + ChannelEndpoint* channel_endpoint) { + if (!RemoteConsumerDataPipeImpl::ProcessMessagesFromIncomingEndpoint( + validated_options, &consumer_num_bytes, message_queue)) + return nullptr; + + // Important: This is called under |IncomingEndpoint|'s (which is a + // |ChannelEndpointClient|) lock, in particular from + // |IncomingEndpoint::ConvertToDataPipeProducer()|. Before releasing that + // lock, it will reset its |endpoint_| member, which makes any later or + // ongoing call to |IncomingEndpoint::OnReadMessage()| return false. This will + // make |ChannelEndpoint::OnReadMessage()| retry, until its |ReplaceClient()| + // is called. + DataPipe* data_pipe = + new DataPipe(true, false, validated_options, + make_scoped_ptr(new RemoteConsumerDataPipeImpl( + channel_endpoint, consumer_num_bytes))); + if (channel_endpoint) { + if (!channel_endpoint->ReplaceClient(data_pipe, 0)) + data_pipe->OnDetachFromChannel(0); + } else { + data_pipe->SetConsumerClosed(); + } + return data_pipe; +} + +// static +bool DataPipe::ProducerDeserialize(Channel* channel, + const void* source, + size_t size, + scoped_refptr<DataPipe>* data_pipe) { + DCHECK(!*data_pipe); // Not technically wrong, but unlikely. + + bool consumer_open = false; + if (size == sizeof(SerializedDataPipeProducerDispatcher)) { + consumer_open = false; + } else if (size == + sizeof(SerializedDataPipeProducerDispatcher) + + channel->GetSerializedEndpointSize()) { + consumer_open = true; + } else { + LOG(ERROR) << "Invalid serialized data pipe producer"; + return false; + } + + const SerializedDataPipeProducerDispatcher* s = + static_cast<const SerializedDataPipeProducerDispatcher*>(source); + MojoCreateDataPipeOptions revalidated_options = {}; + if (ValidateCreateOptions(MakeUserPointer(&s->validated_options), + &revalidated_options) != MOJO_RESULT_OK) { + LOG(ERROR) << "Invalid serialized data pipe producer (bad options)"; + return false; + } + + if (!consumer_open) { + if (s->consumer_num_bytes != static_cast<size_t>(-1)) { + LOG(ERROR) + << "Invalid serialized data pipe producer (bad consumer_num_bytes)"; + return false; + } + + *data_pipe = new DataPipe( + true, false, revalidated_options, + make_scoped_ptr(new RemoteConsumerDataPipeImpl(nullptr, 0))); + (*data_pipe)->SetConsumerClosed(); + + return true; + } + + if (s->consumer_num_bytes > revalidated_options.capacity_num_bytes || + s->consumer_num_bytes % revalidated_options.element_num_bytes != 0) { + LOG(ERROR) + << "Invalid serialized data pipe producer (bad consumer_num_bytes)"; + return false; + } + + const void* endpoint_source = static_cast<const char*>(source) + + sizeof(SerializedDataPipeProducerDispatcher); + scoped_refptr<IncomingEndpoint> incoming_endpoint = + channel->DeserializeEndpoint(endpoint_source); + if (!incoming_endpoint) + return false; + + *data_pipe = incoming_endpoint->ConvertToDataPipeProducer( + revalidated_options, s->consumer_num_bytes); + if (!*data_pipe) + return false; + + return true; +} + +// static +bool DataPipe::ConsumerDeserialize(Channel* channel, + const void* source, + size_t size, + scoped_refptr<DataPipe>* data_pipe) { + DCHECK(!*data_pipe); // Not technically wrong, but unlikely. + + if (size != + sizeof(SerializedDataPipeConsumerDispatcher) + + channel->GetSerializedEndpointSize()) { + LOG(ERROR) << "Invalid serialized data pipe consumer"; + return false; + } + + const SerializedDataPipeConsumerDispatcher* s = + static_cast<const SerializedDataPipeConsumerDispatcher*>(source); + MojoCreateDataPipeOptions revalidated_options = {}; + if (ValidateCreateOptions(MakeUserPointer(&s->validated_options), + &revalidated_options) != MOJO_RESULT_OK) { + LOG(ERROR) << "Invalid serialized data pipe consumer (bad options)"; + return false; + } + + const void* endpoint_source = static_cast<const char*>(source) + + sizeof(SerializedDataPipeConsumerDispatcher); + scoped_refptr<IncomingEndpoint> incoming_endpoint = + channel->DeserializeEndpoint(endpoint_source); + if (!incoming_endpoint) + return false; + + *data_pipe = + incoming_endpoint->ConvertToDataPipeConsumer(revalidated_options); + if (!*data_pipe) + return false; + + return true; +} + void DataPipe::ProducerCancelAllAwakables() { base::AutoLock locker(lock_); DCHECK(has_local_producer_no_lock()); @@ -91,17 +269,7 @@ void DataPipe::ProducerClose() { base::AutoLock locker(lock_); - DCHECK(producer_open_); - producer_open_ = false; - DCHECK(has_local_producer_no_lock()); - producer_awakable_list_.reset(); - // Not a bug, except possibly in "user" code. - DVLOG_IF(2, producer_in_two_phase_write_no_lock()) - << "Producer closed with active two-phase write"; - producer_two_phase_max_num_bytes_written_ = 0; - ProducerCloseImplNoLock(); - AwakeConsumerAwakablesForStateChangeNoLock( - ConsumerGetHandleSignalsStateImplNoLock()); + ProducerCloseNoLock(); } MojoResult DataPipe::ProducerWriteData(UserPointer<const void> elements, @@ -117,7 +285,7 @@ // Returning "busy" takes priority over "invalid argument". uint32_t max_num_bytes_to_write = num_bytes.Get(); - if (max_num_bytes_to_write % element_num_bytes_ != 0) + if (max_num_bytes_to_write % element_num_bytes() != 0) return MOJO_RESULT_INVALID_ARGUMENT; if (max_num_bytes_to_write == 0) @@ -126,11 +294,11 @@ uint32_t min_num_bytes_to_write = all_or_none ? max_num_bytes_to_write : 0; HandleSignalsState old_consumer_state = - ConsumerGetHandleSignalsStateImplNoLock(); - MojoResult rv = ProducerWriteDataImplNoLock( + impl_->ConsumerGetHandleSignalsState(); + MojoResult rv = impl_->ProducerWriteData( elements, num_bytes, max_num_bytes_to_write, min_num_bytes_to_write); HandleSignalsState new_consumer_state = - ConsumerGetHandleSignalsStateImplNoLock(); + impl_->ConsumerGetHandleSignalsState(); if (!new_consumer_state.equals(old_consumer_state)) AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state); return rv; @@ -151,12 +319,12 @@ uint32_t min_num_bytes_to_write = 0; if (all_or_none) { min_num_bytes_to_write = buffer_num_bytes.Get(); - if (min_num_bytes_to_write % element_num_bytes_ != 0) + if (min_num_bytes_to_write % element_num_bytes() != 0) return MOJO_RESULT_INVALID_ARGUMENT; } - MojoResult rv = ProducerBeginWriteDataImplNoLock(buffer, buffer_num_bytes, - min_num_bytes_to_write); + MojoResult rv = impl_->ProducerBeginWriteData(buffer, buffer_num_bytes, + min_num_bytes_to_write); if (rv != MOJO_RESULT_OK) return rv; // Note: No need to awake producer awakables, even though we're going from @@ -177,25 +345,25 @@ // consumer has been closed. HandleSignalsState old_consumer_state = - ConsumerGetHandleSignalsStateImplNoLock(); + impl_->ConsumerGetHandleSignalsState(); MojoResult rv; if (num_bytes_written > producer_two_phase_max_num_bytes_written_ || - num_bytes_written % element_num_bytes_ != 0) { + num_bytes_written % element_num_bytes() != 0) { rv = MOJO_RESULT_INVALID_ARGUMENT; producer_two_phase_max_num_bytes_written_ = 0; } else { - rv = ProducerEndWriteDataImplNoLock(num_bytes_written); + rv = impl_->ProducerEndWriteData(num_bytes_written); } // Two-phase write ended even on failure. DCHECK(!producer_in_two_phase_write_no_lock()); // If we're now writable, we *became* writable (since we weren't writable // during the two-phase write), so awake producer awakables. HandleSignalsState new_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); + impl_->ProducerGetHandleSignalsState(); if (new_producer_state.satisfies(MOJO_HANDLE_SIGNAL_WRITABLE)) AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); HandleSignalsState new_consumer_state = - ConsumerGetHandleSignalsStateImplNoLock(); + impl_->ConsumerGetHandleSignalsState(); if (!new_consumer_state.equals(old_consumer_state)) AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state); return rv; @@ -204,7 +372,7 @@ HandleSignalsState DataPipe::ProducerGetHandleSignalsState() { base::AutoLock locker(lock_); DCHECK(has_local_producer_no_lock()); - return ProducerGetHandleSignalsStateImplNoLock(); + return impl_->ProducerGetHandleSignalsState(); } MojoResult DataPipe::ProducerAddAwakable(Awakable* awakable, @@ -214,7 +382,7 @@ base::AutoLock locker(lock_); DCHECK(has_local_producer_no_lock()); - HandleSignalsState producer_state = ProducerGetHandleSignalsStateImplNoLock(); + HandleSignalsState producer_state = impl_->ProducerGetHandleSignalsState(); if (producer_state.satisfies(signals)) { if (signals_state) *signals_state = producer_state; @@ -236,7 +404,42 @@ DCHECK(has_local_producer_no_lock()); producer_awakable_list_->Remove(awakable); if (signals_state) - *signals_state = ProducerGetHandleSignalsStateImplNoLock(); + *signals_state = impl_->ProducerGetHandleSignalsState(); +} + +void DataPipe::ProducerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) { + base::AutoLock locker(lock_); + DCHECK(has_local_producer_no_lock()); + impl_->ProducerStartSerialize(channel, max_size, max_platform_handles); +} + +bool DataPipe::ProducerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) { + base::AutoLock locker(lock_); + DCHECK(has_local_producer_no_lock()); + // Warning: After |ProducerEndSerialize()|, quite probably |impl_| has + // changed. + bool rv = impl_->ProducerEndSerialize(channel, destination, actual_size, + platform_handles); + + // TODO(vtl): The code below is similar to, but not quite the same as, + // |ProducerCloseNoLock()|. + DCHECK(has_local_producer_no_lock()); + producer_awakable_list_->CancelAll(); + producer_awakable_list_.reset(); + // Not a bug, except possibly in "user" code. + DVLOG_IF(2, producer_in_two_phase_write_no_lock()) + << "Producer transferred with active two-phase write"; + producer_two_phase_max_num_bytes_written_ = 0; + if (!has_local_consumer_no_lock()) + producer_open_ = false; + + return rv; } bool DataPipe::ProducerIsBusy() const { @@ -252,17 +455,7 @@ void DataPipe::ConsumerClose() { base::AutoLock locker(lock_); - DCHECK(consumer_open_); - consumer_open_ = false; - DCHECK(has_local_consumer_no_lock()); - consumer_awakable_list_.reset(); - // Not a bug, except possibly in "user" code. - DVLOG_IF(2, consumer_in_two_phase_read_no_lock()) - << "Consumer closed with active two-phase read"; - consumer_two_phase_max_num_bytes_read_ = 0; - ConsumerCloseImplNoLock(); - AwakeProducerAwakablesForStateChangeNoLock( - ProducerGetHandleSignalsStateImplNoLock()); + ConsumerCloseNoLock(); } MojoResult DataPipe::ConsumerReadData(UserPointer<void> elements, @@ -276,7 +469,7 @@ return MOJO_RESULT_BUSY; uint32_t max_num_bytes_to_read = num_bytes.Get(); - if (max_num_bytes_to_read % element_num_bytes_ != 0) + if (max_num_bytes_to_read % element_num_bytes() != 0) return MOJO_RESULT_INVALID_ARGUMENT; if (max_num_bytes_to_read == 0) @@ -285,11 +478,11 @@ uint32_t min_num_bytes_to_read = all_or_none ? max_num_bytes_to_read : 0; HandleSignalsState old_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); - MojoResult rv = ConsumerReadDataImplNoLock( + impl_->ProducerGetHandleSignalsState(); + MojoResult rv = impl_->ConsumerReadData( elements, num_bytes, max_num_bytes_to_read, min_num_bytes_to_read, peek); HandleSignalsState new_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); + impl_->ProducerGetHandleSignalsState(); if (!new_producer_state.equals(old_producer_state)) AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); return rv; @@ -304,7 +497,7 @@ return MOJO_RESULT_BUSY; uint32_t max_num_bytes_to_discard = num_bytes.Get(); - if (max_num_bytes_to_discard % element_num_bytes_ != 0) + if (max_num_bytes_to_discard % element_num_bytes() != 0) return MOJO_RESULT_INVALID_ARGUMENT; if (max_num_bytes_to_discard == 0) @@ -314,11 +507,11 @@ all_or_none ? max_num_bytes_to_discard : 0; HandleSignalsState old_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); - MojoResult rv = ConsumerDiscardDataImplNoLock( + impl_->ProducerGetHandleSignalsState(); + MojoResult rv = impl_->ConsumerDiscardData( num_bytes, max_num_bytes_to_discard, min_num_bytes_to_discard); HandleSignalsState new_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); + impl_->ProducerGetHandleSignalsState(); if (!new_producer_state.equals(old_producer_state)) AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); return rv; @@ -332,7 +525,7 @@ return MOJO_RESULT_BUSY; // Note: Don't need to validate |*num_bytes| for query. - return ConsumerQueryDataImplNoLock(num_bytes); + return impl_->ConsumerQueryData(num_bytes); } MojoResult DataPipe::ConsumerBeginReadData( @@ -348,12 +541,12 @@ uint32_t min_num_bytes_to_read = 0; if (all_or_none) { min_num_bytes_to_read = buffer_num_bytes.Get(); - if (min_num_bytes_to_read % element_num_bytes_ != 0) + if (min_num_bytes_to_read % element_num_bytes() != 0) return MOJO_RESULT_INVALID_ARGUMENT; } - MojoResult rv = ConsumerBeginReadDataImplNoLock(buffer, buffer_num_bytes, - min_num_bytes_to_read); + MojoResult rv = impl_->ConsumerBeginReadData(buffer, buffer_num_bytes, + min_num_bytes_to_read); if (rv != MOJO_RESULT_OK) return rv; DCHECK(consumer_in_two_phase_read_no_lock()); @@ -368,25 +561,25 @@ return MOJO_RESULT_FAILED_PRECONDITION; HandleSignalsState old_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); + impl_->ProducerGetHandleSignalsState(); MojoResult rv; if (num_bytes_read > consumer_two_phase_max_num_bytes_read_ || - num_bytes_read % element_num_bytes_ != 0) { + num_bytes_read % element_num_bytes() != 0) { rv = MOJO_RESULT_INVALID_ARGUMENT; consumer_two_phase_max_num_bytes_read_ = 0; } else { - rv = ConsumerEndReadDataImplNoLock(num_bytes_read); + rv = impl_->ConsumerEndReadData(num_bytes_read); } // Two-phase read ended even on failure. DCHECK(!consumer_in_two_phase_read_no_lock()); // If we're now readable, we *became* readable (since we weren't readable // during the two-phase read), so awake consumer awakables. HandleSignalsState new_consumer_state = - ConsumerGetHandleSignalsStateImplNoLock(); + impl_->ConsumerGetHandleSignalsState(); if (new_consumer_state.satisfies(MOJO_HANDLE_SIGNAL_READABLE)) AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state); HandleSignalsState new_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); + impl_->ProducerGetHandleSignalsState(); if (!new_producer_state.equals(old_producer_state)) AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); return rv; @@ -395,7 +588,7 @@ HandleSignalsState DataPipe::ConsumerGetHandleSignalsState() { base::AutoLock locker(lock_); DCHECK(has_local_consumer_no_lock()); - return ConsumerGetHandleSignalsStateImplNoLock(); + return impl_->ConsumerGetHandleSignalsState(); } MojoResult DataPipe::ConsumerAddAwakable(Awakable* awakable, @@ -405,7 +598,7 @@ base::AutoLock locker(lock_); DCHECK(has_local_consumer_no_lock()); - HandleSignalsState consumer_state = ConsumerGetHandleSignalsStateImplNoLock(); + HandleSignalsState consumer_state = impl_->ConsumerGetHandleSignalsState(); if (consumer_state.satisfies(signals)) { if (signals_state) *signals_state = consumer_state; @@ -427,7 +620,41 @@ DCHECK(has_local_consumer_no_lock()); consumer_awakable_list_->Remove(awakable); if (signals_state) - *signals_state = ConsumerGetHandleSignalsStateImplNoLock(); + *signals_state = impl_->ConsumerGetHandleSignalsState(); +} + +void DataPipe::ConsumerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) { + base::AutoLock locker(lock_); + DCHECK(has_local_consumer_no_lock()); + impl_->ConsumerStartSerialize(channel, max_size, max_platform_handles); +} + +bool DataPipe::ConsumerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) { + base::AutoLock locker(lock_); + DCHECK(has_local_consumer_no_lock()); + // Warning: After |ConsumerEndSerialize()|, quite probably |impl_| has + // changed. + bool rv = impl_->ConsumerEndSerialize(channel, destination, actual_size, + platform_handles); + + // TODO(vtl): The code below is similar to, but not quite the same as, + // |ConsumerCloseNoLock()|. + consumer_awakable_list_->CancelAll(); + consumer_awakable_list_.reset(); + // Not a bug, except possibly in "user" code. + DVLOG_IF(2, consumer_in_two_phase_read_no_lock()) + << "Consumer transferred with active two-phase read"; + consumer_two_phase_max_num_bytes_read_ = 0; + if (!has_local_producer_no_lock()) + consumer_open_ = false; + + return rv; } bool DataPipe::ConsumerIsBusy() const { @@ -437,11 +664,9 @@ DataPipe::DataPipe(bool has_local_producer, bool has_local_consumer, - const MojoCreateDataPipeOptions& validated_options) - : may_discard_((validated_options.flags & - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD)), - element_num_bytes_(validated_options.element_num_bytes), - capacity_num_bytes_(validated_options.capacity_num_bytes), + const MojoCreateDataPipeOptions& validated_options, + scoped_ptr<DataPipeImpl> impl) + : validated_options_(validated_options), producer_open_(true), consumer_open_(true), producer_awakable_list_(has_local_producer ? new AwakableList() @@ -449,11 +674,16 @@ consumer_awakable_list_(has_local_consumer ? new AwakableList() : nullptr), producer_two_phase_max_num_bytes_written_(0), - consumer_two_phase_max_num_bytes_read_(0) { + consumer_two_phase_max_num_bytes_read_(0), + impl_(impl.Pass()) { + impl_->set_owner(this); + +#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) // Check that the passed in options actually are validated. - MojoCreateDataPipeOptions unused = {0}; + MojoCreateDataPipeOptions unused = {}; DCHECK_EQ(ValidateCreateOptions(MakeUserPointer(&validated_options), &unused), MOJO_RESULT_OK); +#endif // !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) } DataPipe::~DataPipe() { @@ -463,6 +693,108 @@ DCHECK(!consumer_awakable_list_); } +scoped_ptr<DataPipeImpl> DataPipe::ReplaceImplNoLock( + scoped_ptr<DataPipeImpl> new_impl) { + lock_.AssertAcquired(); + DCHECK(new_impl); + + impl_->set_owner(nullptr); + scoped_ptr<DataPipeImpl> rv(impl_.Pass()); + impl_ = new_impl.Pass(); + impl_->set_owner(this); + return rv.Pass(); +} + +void DataPipe::SetProducerClosedNoLock() { + lock_.AssertAcquired(); + DCHECK(!has_local_producer_no_lock()); + DCHECK(producer_open_); + producer_open_ = false; +} + +void DataPipe::SetConsumerClosedNoLock() { + lock_.AssertAcquired(); + DCHECK(!has_local_consumer_no_lock()); + DCHECK(consumer_open_); + consumer_open_ = false; +} + +void DataPipe::ProducerCloseNoLock() { + lock_.AssertAcquired(); + DCHECK(producer_open_); + producer_open_ = false; + if (has_local_producer_no_lock()) { + producer_awakable_list_.reset(); + // Not a bug, except possibly in "user" code. + DVLOG_IF(2, producer_in_two_phase_write_no_lock()) + << "Producer closed with active two-phase write"; + producer_two_phase_max_num_bytes_written_ = 0; + impl_->ProducerClose(); + AwakeConsumerAwakablesForStateChangeNoLock( + impl_->ConsumerGetHandleSignalsState()); + } +} + +void DataPipe::ConsumerCloseNoLock() { + lock_.AssertAcquired(); + DCHECK(consumer_open_); + consumer_open_ = false; + if (has_local_consumer_no_lock()) { + consumer_awakable_list_.reset(); + // Not a bug, except possibly in "user" code. + DVLOG_IF(2, consumer_in_two_phase_read_no_lock()) + << "Consumer closed with active two-phase read"; + consumer_two_phase_max_num_bytes_read_ = 0; + impl_->ConsumerClose(); + AwakeProducerAwakablesForStateChangeNoLock( + impl_->ProducerGetHandleSignalsState()); + } +} + +bool DataPipe::OnReadMessage(unsigned port, MessageInTransit* message) { + base::AutoLock locker(lock_); + DCHECK(!has_local_producer_no_lock() || !has_local_consumer_no_lock()); + + HandleSignalsState old_producer_state = + impl_->ProducerGetHandleSignalsState(); + HandleSignalsState old_consumer_state = + impl_->ConsumerGetHandleSignalsState(); + + bool rv = impl_->OnReadMessage(port, message); + + HandleSignalsState new_producer_state = + impl_->ProducerGetHandleSignalsState(); + if (!new_producer_state.equals(old_producer_state)) + AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); + HandleSignalsState new_consumer_state = + impl_->ConsumerGetHandleSignalsState(); + if (!new_consumer_state.equals(old_consumer_state)) + AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state); + + return rv; +} + +void DataPipe::OnDetachFromChannel(unsigned port) { + base::AutoLock locker(lock_); + DCHECK(!has_local_producer_no_lock() || !has_local_consumer_no_lock()); + + HandleSignalsState old_producer_state = + impl_->ProducerGetHandleSignalsState(); + HandleSignalsState old_consumer_state = + impl_->ConsumerGetHandleSignalsState(); + + impl_->OnDetachFromChannel(port); + + HandleSignalsState new_producer_state = + impl_->ProducerGetHandleSignalsState(); + if (!new_producer_state.equals(old_producer_state)) + AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); + HandleSignalsState new_consumer_state = + impl_->ConsumerGetHandleSignalsState(); + if (!new_consumer_state.equals(old_consumer_state)) + AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state); +} + void DataPipe::AwakeProducerAwakablesForStateChangeNoLock( const HandleSignalsState& new_producer_state) { lock_.AssertAcquired(); @@ -479,5 +811,15 @@ consumer_awakable_list_->AwakeForStateChange(new_consumer_state); } +void DataPipe::SetProducerClosed() { + base::AutoLock locker(lock_); + SetProducerClosedNoLock(); +} + +void DataPipe::SetConsumerClosed() { + base::AutoLock locker(lock_); + SetConsumerClosedNoLock(); +} + } // namespace system } // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/data_pipe.h b/third_party/mojo/src/mojo/edk/system/data_pipe.h index d893465..8096e011 100644 --- a/third_party/mojo/src/mojo/edk/system/data_pipe.h +++ b/third_party/mojo/src/mojo/edk/system/data_pipe.h
@@ -7,10 +7,12 @@ #include <stdint.h> +#include "base/compiler_specific.h" #include "base/macros.h" -#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_client.h" #include "mojo/edk/system/handle_signals_state.h" #include "mojo/edk/system/memory.h" #include "mojo/edk/system/system_impl_export.h" @@ -22,6 +24,10 @@ class Awakable; class AwakableList; +class Channel; +class ChannelEndpoint; +class DataPipeImpl; +class MessageInTransitQueue; // |DataPipe| is a base class for secondary objects implementing data pipes, // similar to |MessagePipe| (see the explanatory comment in core.cc). It is @@ -29,8 +35,7 @@ // Its subclasses implement the three cases: local producer and consumer, local // producer and remote consumer, and remote producer and local consumer. This // class is thread-safe. -class MOJO_SYSTEM_IMPL_EXPORT DataPipe - : public base::RefCountedThreadSafe<DataPipe> { +class MOJO_SYSTEM_IMPL_EXPORT DataPipe : public ChannelEndpointClient { public: // The default options for |MojoCreateDataPipe()|. (Real uses should obtain // this via |ValidateCreateOptions()| with a null |in_options|; this is @@ -46,6 +51,53 @@ UserPointer<const MojoCreateDataPipeOptions> in_options, MojoCreateDataPipeOptions* out_options); + // Creates a local (both producer and consumer) data pipe (using + // |LocalDataPipeImpl|. |validated_options| should be the output of + // |ValidateOptions()|. In particular: |struct_size| is ignored (so + // |validated_options| must be the current version of the struct) and + // |capacity_num_bytes| must be nonzero. + static DataPipe* CreateLocal( + const MojoCreateDataPipeOptions& validated_options); + + // Creates a data pipe with a remote producer and a local consumer, using an + // existing |ChannelEndpoint| (whose |ReplaceClient()| it'll call) and taking + // |message_queue|'s contents as already-received incoming messages. If + // |channel_endpoint| is null, this will create a "half-open" data pipe (with + // only the consumer open). Note that this may fail, in which case it returns + // null. + static DataPipe* CreateRemoteProducerFromExisting( + const MojoCreateDataPipeOptions& validated_options, + MessageInTransitQueue* message_queue, + ChannelEndpoint* channel_endpoint); + + // Creates a data pipe with a local producer and a remote consumer, using an + // existing |ChannelEndpoint| (whose |ReplaceClient()| it'll call) and taking + // |message_queue|'s contents as already-received incoming messages + // (|message_queue| may be null). If |channel_endpoint| is null, this will + // create a "half-open" data pipe (with only the producer open). Note that + // this may fail, in which case it returns null. + static DataPipe* CreateRemoteConsumerFromExisting( + const MojoCreateDataPipeOptions& validated_options, + size_t consumer_num_bytes, + MessageInTransitQueue* message_queue, + ChannelEndpoint* channel_endpoint); + + // Used by |DataPipeProducerDispatcher::Deserialize()|. Returns true on + // success (in which case, |*data_pipe| is set appropriately) and false on + // failure (in which case |*data_pipe| may or may not be set to null). + static bool ProducerDeserialize(Channel* channel, + const void* source, + size_t size, + scoped_refptr<DataPipe>* data_pipe); + + // Used by |DataPipeConsumerDispatcher::Deserialize()|. Returns true on + // success (in which case, |*data_pipe| is set appropriately) and false on + // failure (in which case |*data_pipe| may or may not be set to null). + static bool ConsumerDeserialize(Channel* channel, + const void* source, + size_t size, + scoped_refptr<DataPipe>* data_pipe); + // These are called by the producer dispatcher to implement its methods of // corresponding names. void ProducerCancelAllAwakables(); @@ -64,6 +116,13 @@ HandleSignalsState* signals_state); void ProducerRemoveAwakable(Awakable* awakable, HandleSignalsState* signals_state); + void ProducerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles); + bool ProducerEndSerialize(Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles); bool ProducerIsBusy() const; // These are called by the consumer dispatcher to implement its methods of @@ -90,60 +149,38 @@ HandleSignalsState* signals_state); void ConsumerRemoveAwakable(Awakable* awakable, HandleSignalsState* signals_state); + void ConsumerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles); + bool ConsumerEndSerialize(Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles); bool ConsumerIsBusy() const; - protected: - DataPipe(bool has_local_producer, - bool has_local_consumer, - const MojoCreateDataPipeOptions& validated_options); + // The following are only to be used by |DataPipeImpl| (and its subclasses): - friend class base::RefCountedThreadSafe<DataPipe>; - virtual ~DataPipe(); + // Replaces |impl_| with |new_impl| (which must not be null). For use when + // serializing data pipe dispatchers (i.e., in |ProducerEndSerialize()| and + // |ConsumerEndSerialize()|). Returns the old value of |impl_| (in case the + // caller needs to manage its lifetime). + scoped_ptr<DataPipeImpl> ReplaceImplNoLock(scoped_ptr<DataPipeImpl> new_impl); + void SetProducerClosedNoLock(); + void SetConsumerClosedNoLock(); - virtual void ProducerCloseImplNoLock() = 0; - // |num_bytes.Get()| will be a nonzero multiple of |element_num_bytes_|. - virtual MojoResult ProducerWriteDataImplNoLock( - UserPointer<const void> elements, - UserPointer<uint32_t> num_bytes, - uint32_t max_num_bytes_to_write, - uint32_t min_num_bytes_to_write) = 0; - virtual MojoResult ProducerBeginWriteDataImplNoLock( - UserPointer<void*> buffer, - UserPointer<uint32_t> buffer_num_bytes, - uint32_t min_num_bytes_to_write) = 0; - virtual MojoResult ProducerEndWriteDataImplNoLock( - uint32_t num_bytes_written) = 0; - // Note: A producer should not be writable during a two-phase write. - virtual HandleSignalsState ProducerGetHandleSignalsStateImplNoLock() - const = 0; - - virtual void ConsumerCloseImplNoLock() = 0; - // |*num_bytes| will be a nonzero multiple of |element_num_bytes_|. - virtual MojoResult ConsumerReadDataImplNoLock(UserPointer<void> elements, - UserPointer<uint32_t> num_bytes, - uint32_t max_num_bytes_to_read, - uint32_t min_num_bytes_to_read, - bool peek) = 0; - virtual MojoResult ConsumerDiscardDataImplNoLock( - UserPointer<uint32_t> num_bytes, - uint32_t max_num_bytes_to_discard, - uint32_t min_num_bytes_to_discard) = 0; - // |*num_bytes| will be a nonzero multiple of |element_num_bytes_|. - virtual MojoResult ConsumerQueryDataImplNoLock( - UserPointer<uint32_t> num_bytes) = 0; - virtual MojoResult ConsumerBeginReadDataImplNoLock( - UserPointer<const void*> buffer, - UserPointer<uint32_t> buffer_num_bytes, - uint32_t min_num_bytes_to_read) = 0; - virtual MojoResult ConsumerEndReadDataImplNoLock(uint32_t num_bytes_read) = 0; - // Note: A consumer should not be writable during a two-phase read. - virtual HandleSignalsState ConsumerGetHandleSignalsStateImplNoLock() - const = 0; + void ProducerCloseNoLock(); + void ConsumerCloseNoLock(); // Thread-safe and fast (they don't take the lock): - bool may_discard() const { return may_discard_; } - size_t element_num_bytes() const { return element_num_bytes_; } - size_t capacity_num_bytes() const { return capacity_num_bytes_; } + const MojoCreateDataPipeOptions& validated_options() const { + return validated_options_; + } + size_t element_num_bytes() const { + return validated_options_.element_num_bytes; + } + size_t capacity_num_bytes() const { + return validated_options_.capacity_num_bytes; + } // Must be called under lock. bool producer_open_no_lock() const { @@ -181,11 +218,32 @@ } private: + // |validated_options| should be the output of |ValidateOptions()|. In + // particular: |struct_size| is ignored (so |validated_options| must be the + // current version of the struct) and |capacity_num_bytes| must be nonzero. + // TODO(vtl): |has_local_producer|/|has_local_consumer| shouldn't really be + // arguments here. Instead, they should be determined from the |impl| ... but + // the |impl|'s typically figures these out by examining the owner, i.e., the + // |DataPipe| object. Probably, this indicates that more stuff should be moved + // to |DataPipeImpl|, but for now we'll live with this. + DataPipe(bool has_local_producer, + bool has_local_consumer, + const MojoCreateDataPipeOptions& validated_options, + scoped_ptr<DataPipeImpl> impl); + virtual ~DataPipe(); + + // |ChannelEndpointClient| implementation: + bool OnReadMessage(unsigned port, MessageInTransit* message) override; + void OnDetachFromChannel(unsigned port) override; + void AwakeProducerAwakablesForStateChangeNoLock( const HandleSignalsState& new_producer_state); void AwakeConsumerAwakablesForStateChangeNoLock( const HandleSignalsState& new_consumer_state); + void SetProducerClosed(); + void SetConsumerClosed(); + bool has_local_producer_no_lock() const { lock_.AssertAcquired(); return !!producer_awakable_list_; @@ -195,9 +253,8 @@ return !!consumer_awakable_list_; } - const bool may_discard_; - const size_t element_num_bytes_; - const size_t capacity_num_bytes_; + MSVC_SUPPRESS_WARNING(4324) + const MojoCreateDataPipeOptions validated_options_; mutable base::Lock lock_; // Protects the following members. // *Known* state of producer or consumer. @@ -209,6 +266,7 @@ // These are nonzero if and only if a two-phase write/read is in progress. uint32_t producer_two_phase_max_num_bytes_written_; uint32_t consumer_two_phase_max_num_bytes_read_; + scoped_ptr<DataPipeImpl> impl_; DISALLOW_COPY_AND_ASSIGN(DataPipe); };
diff --git a/third_party/mojo/src/mojo/edk/system/data_pipe_consumer_dispatcher.cc b/third_party/mojo/src/mojo/edk/system/data_pipe_consumer_dispatcher.cc index 21127c62..bee4b23 100644 --- a/third_party/mojo/src/mojo/edk/system/data_pipe_consumer_dispatcher.cc +++ b/third_party/mojo/src/mojo/edk/system/data_pipe_consumer_dispatcher.cc
@@ -23,6 +23,22 @@ return kTypeDataPipeConsumer; } +// static +scoped_refptr<DataPipeConsumerDispatcher> +DataPipeConsumerDispatcher::Deserialize(Channel* channel, + const void* source, + size_t size) { + scoped_refptr<DataPipe> data_pipe; + if (!DataPipe::ConsumerDeserialize(channel, source, size, &data_pipe)) + return nullptr; + DCHECK(data_pipe); + + scoped_refptr<DataPipeConsumerDispatcher> dispatcher( + new DataPipeConsumerDispatcher()); + dispatcher->Init(data_pipe); + return dispatcher; +} + DataPipeConsumerDispatcher::~DataPipeConsumerDispatcher() { // |Close()|/|CloseImplNoLock()| should have taken care of the pipe. DCHECK(!data_pipe_); @@ -126,6 +142,27 @@ data_pipe_->ConsumerRemoveAwakable(awakable, signals_state); } +void DataPipeConsumerDispatcher::StartSerializeImplNoLock( + Channel* channel, + size_t* max_size, + size_t* max_platform_handles) { + DCHECK(HasOneRef()); // Only one ref => no need to take the lock. + data_pipe_->ConsumerStartSerialize(channel, max_size, max_platform_handles); +} + +bool DataPipeConsumerDispatcher::EndSerializeAndCloseImplNoLock( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) { + DCHECK(HasOneRef()); // Only one ref => no need to take the lock. + + bool rv = data_pipe_->ConsumerEndSerialize(channel, destination, actual_size, + platform_handles); + data_pipe_ = nullptr; + return rv; +} + bool DataPipeConsumerDispatcher::IsBusyNoLock() const { lock().AssertAcquired(); return data_pipe_->ConsumerIsBusy();
diff --git a/third_party/mojo/src/mojo/edk/system/data_pipe_consumer_dispatcher.h b/third_party/mojo/src/mojo/edk/system/data_pipe_consumer_dispatcher.h index 10a3d94..02f8887 100644 --- a/third_party/mojo/src/mojo/edk/system/data_pipe_consumer_dispatcher.h +++ b/third_party/mojo/src/mojo/edk/system/data_pipe_consumer_dispatcher.h
@@ -28,6 +28,14 @@ // |Dispatcher| public methods: Type GetType() const override; + // The "opposite" of |SerializeAndClose()|. (Typically this is called by + // |Dispatcher::Deserialize()|.) + static scoped_refptr<DataPipeConsumerDispatcher> + Deserialize(Channel* channel, const void* source, size_t size); + + // Get access to the |DataPipe| for testing. + DataPipe* GetDataPipeForTest() { return data_pipe_.get(); } + private: ~DataPipeConsumerDispatcher() override; @@ -50,6 +58,14 @@ HandleSignalsState* signals_state) override; void RemoveAwakableImplNoLock(Awakable* awakable, HandleSignalsState* signals_state) override; + void StartSerializeImplNoLock(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) override; + bool EndSerializeAndCloseImplNoLock( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) override; bool IsBusyNoLock() const override; // Protected by |lock()|:
diff --git a/third_party/mojo/src/mojo/edk/system/data_pipe_impl.cc b/third_party/mojo/src/mojo/edk/system/data_pipe_impl.cc new file mode 100644 index 0000000..6a4d0706 --- /dev/null +++ b/third_party/mojo/src/mojo/edk/system/data_pipe_impl.cc
@@ -0,0 +1,50 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/edk/system/data_pipe_impl.h" + +#include <algorithm> + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/edk/system/configuration.h" +#include "mojo/edk/system/message_in_transit.h" +#include "mojo/edk/system/message_in_transit_queue.h" + +namespace mojo { +namespace system { + +void DataPipeImpl::ConvertDataToMessages(const char* buffer, + size_t* start_index, + size_t* current_num_bytes, + MessageInTransitQueue* message_queue) { + // The maximum amount of data to send per message (make it a multiple of the + // element size. + size_t max_message_num_bytes = GetConfiguration().max_message_num_bytes; + max_message_num_bytes -= max_message_num_bytes % element_num_bytes(); + DCHECK_GT(max_message_num_bytes, 0u); + + while (*current_num_bytes > 0) { + size_t current_contiguous_num_bytes = + (*start_index + *current_num_bytes > capacity_num_bytes()) + ? (capacity_num_bytes() - *start_index) + : *current_num_bytes; + size_t message_num_bytes = + std::min(max_message_num_bytes, current_contiguous_num_bytes); + + // Note: |message_num_bytes| fits in a |uint32_t| since the capacity does. + scoped_ptr<MessageInTransit> message(new MessageInTransit( + MessageInTransit::kTypeEndpoint, MessageInTransit::kSubtypeEndpointData, + static_cast<uint32_t>(message_num_bytes), buffer + *start_index)); + message_queue->AddMessage(message.Pass()); + + DCHECK_LE(message_num_bytes, *current_num_bytes); + *start_index += message_num_bytes; + *start_index %= capacity_num_bytes(); + *current_num_bytes -= message_num_bytes; + } +} + +} // namespace system +} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/data_pipe_impl.h b/third_party/mojo/src/mojo/edk/system/data_pipe_impl.h new file mode 100644 index 0000000..20ca900 --- /dev/null +++ b/third_party/mojo/src/mojo/edk/system/data_pipe_impl.h
@@ -0,0 +1,162 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_EDK_SYSTEM_DATA_PIPE_IMPL_H_ +#define MOJO_EDK_SYSTEM_DATA_PIPE_IMPL_H_ + +#include <stdint.h> + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "mojo/edk/embedder/platform_handle_vector.h" +#include "mojo/edk/system/data_pipe.h" +#include "mojo/edk/system/handle_signals_state.h" +#include "mojo/edk/system/memory.h" +#include "mojo/edk/system/system_impl_export.h" +#include "mojo/public/c/system/data_pipe.h" +#include "mojo/public/c/system/types.h" + +namespace mojo { +namespace system { + +class Channel; +class MessageInTransit; + +// Base class/interface for classes that "implement" |DataPipe| for various +// situations (local versus remote). The methods, other than the constructor, +// |set_owner()|, and the destructor, are always protected by |DataPipe|'s +// |lock_|. +class MOJO_SYSTEM_IMPL_EXPORT DataPipeImpl { + public: + virtual ~DataPipeImpl() {} + + // This is only called by |DataPipe| during its construction. + void set_owner(DataPipe* owner) { owner_ = owner; } + + virtual void ProducerClose() = 0; + // |num_bytes.Get()| will be a nonzero multiple of |element_num_bytes()|. + virtual MojoResult ProducerWriteData(UserPointer<const void> elements, + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_write, + uint32_t min_num_bytes_to_write) = 0; + virtual MojoResult ProducerBeginWriteData( + UserPointer<void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, + uint32_t min_num_bytes_to_write) = 0; + virtual MojoResult ProducerEndWriteData(uint32_t num_bytes_written) = 0; + // Note: A producer should not be writable during a two-phase write. + virtual HandleSignalsState ProducerGetHandleSignalsState() const = 0; + virtual void ProducerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) = 0; + virtual bool ProducerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) = 0; + + virtual void ConsumerClose() = 0; + // |num_bytes.Get()| will be a nonzero multiple of |element_num_bytes()|. + virtual MojoResult ConsumerReadData(UserPointer<void> elements, + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_read, + uint32_t min_num_bytes_to_read, + bool peek) = 0; + virtual MojoResult ConsumerDiscardData(UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_discard, + uint32_t min_num_bytes_to_discard) = 0; + // |num_bytes.Get()| will be a nonzero multiple of |element_num_bytes()|. + virtual MojoResult ConsumerQueryData(UserPointer<uint32_t> num_bytes) = 0; + virtual MojoResult ConsumerBeginReadData( + UserPointer<const void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, + uint32_t min_num_bytes_to_read) = 0; + virtual MojoResult ConsumerEndReadData(uint32_t num_bytes_read) = 0; + // Note: A consumer should not be writable during a two-phase read. + virtual HandleSignalsState ConsumerGetHandleSignalsState() const = 0; + virtual void ConsumerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) = 0; + virtual bool ConsumerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) = 0; + + virtual bool OnReadMessage(unsigned port, MessageInTransit* message) = 0; + virtual void OnDetachFromChannel(unsigned port) = 0; + + protected: + DataPipeImpl() : owner_() {} + + // Helper to convert the given circular buffer into messages. The input is a + // circular buffer |buffer| (with appropriate element size and capacity), with + // current contents starting at |start_index| of length |current_num_bytes|. + // This will convert all of the contents. + void ConvertDataToMessages(const char* buffer, + size_t* start_index, + size_t* current_num_bytes, + MessageInTransitQueue* message_queue); + + DataPipe* owner() const { return owner_; } + + const MojoCreateDataPipeOptions& validated_options() const { + return owner_->validated_options(); + } + size_t element_num_bytes() const { return owner_->element_num_bytes(); } + size_t capacity_num_bytes() const { return owner_->capacity_num_bytes(); } + bool producer_open() const { return owner_->producer_open_no_lock(); } + bool consumer_open() const { return owner_->consumer_open_no_lock(); } + uint32_t producer_two_phase_max_num_bytes_written() const { + return owner_->producer_two_phase_max_num_bytes_written_no_lock(); + } + uint32_t consumer_two_phase_max_num_bytes_read() const { + return owner_->consumer_two_phase_max_num_bytes_read_no_lock(); + } + void set_producer_two_phase_max_num_bytes_written(uint32_t num_bytes) { + owner_->set_producer_two_phase_max_num_bytes_written_no_lock(num_bytes); + } + void set_consumer_two_phase_max_num_bytes_read(uint32_t num_bytes) { + owner_->set_consumer_two_phase_max_num_bytes_read_no_lock(num_bytes); + } + bool producer_in_two_phase_write() const { + return owner_->producer_in_two_phase_write_no_lock(); + } + bool consumer_in_two_phase_read() const { + return owner_->consumer_in_two_phase_read_no_lock(); + } + + private: + DataPipe* owner_; + + DISALLOW_COPY_AND_ASSIGN(DataPipeImpl); +}; + +// TODO(vtl): This is not the ideal place for the following structs; find +// somewhere better. + +// Serialized form of a producer dispatcher. This will actually be followed by a +// serialized |ChannelEndpoint|; we want to preserve alignment guarantees. +struct ALIGNAS(8) SerializedDataPipeProducerDispatcher { + // Only validated (and thus canonicalized) options should be serialized. + // However, the deserializer must revalidate (as with everything received). + MojoCreateDataPipeOptions validated_options; + // Number of bytes already enqueued to the consumer. Set to + // |static_cast<size_t>(-1)| if the consumer is already closed, in which case + // this will *not* be followed by a serialized |ChannelEndpoint|. + size_t consumer_num_bytes; +}; + +// Serialized form of a consumer dispatcher. This will actually be followed by a +// serialized |ChannelEndpoint|; we want to preserve alignment guarantees. +struct ALIGNAS(8) SerializedDataPipeConsumerDispatcher { + // Only validated (and thus canonicalized) options should be serialized. + // However, the deserializer must revalidate (as with everything received). + MojoCreateDataPipeOptions validated_options; +}; + +} // namespace system +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_DATA_PIPE_IMPL_H_
diff --git a/third_party/mojo/src/mojo/edk/system/data_pipe_impl_unittest.cc b/third_party/mojo/src/mojo/edk/system/data_pipe_impl_unittest.cc new file mode 100644 index 0000000..b14d3af --- /dev/null +++ b/third_party/mojo/src/mojo/edk/system/data_pipe_impl_unittest.cc
@@ -0,0 +1,1720 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains tests that are shared between different implementations of +// |DataPipeImpl|. + +#include "mojo/edk/system/data_pipe_impl.h" + +#include <stdint.h> + +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/test/test_io_thread.h" +#include "base/threading/platform_thread.h" // For |Sleep()|. +#include "mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/edk/embedder/simple_platform_support.h" +#include "mojo/edk/system/channel.h" +#include "mojo/edk/system/channel_endpoint.h" +#include "mojo/edk/system/data_pipe.h" +#include "mojo/edk/system/data_pipe_consumer_dispatcher.h" +#include "mojo/edk/system/data_pipe_producer_dispatcher.h" +#include "mojo/edk/system/memory.h" +#include "mojo/edk/system/message_pipe.h" +#include "mojo/edk/system/raw_channel.h" +#include "mojo/edk/system/test_utils.h" +#include "mojo/edk/system/waiter.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace system { +namespace { + +const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED; +const uint32_t kSizeOfOptions = + static_cast<uint32_t>(sizeof(MojoCreateDataPipeOptions)); + +// DataPipeImplTestHelper ------------------------------------------------------ + +class DataPipeImplTestHelper { + public: + virtual ~DataPipeImplTestHelper() {} + + virtual void SetUp() = 0; + virtual void TearDown() = 0; + + virtual void Create(const MojoCreateDataPipeOptions& validated_options) = 0; + + // Possibly transfers the producer/consumer. + virtual void DoTransfer() = 0; + + // Returns the |DataPipe| object for the producer and consumer, respectively. + virtual DataPipe* dpp() = 0; + virtual DataPipe* dpc() = 0; + + virtual void ProducerClose() = 0; + virtual void ConsumerClose() = 0; + + protected: + DataPipeImplTestHelper() {} + + private: + DISALLOW_COPY_AND_ASSIGN(DataPipeImplTestHelper); +}; + +// DataPipeImplTest ------------------------------------------------------------ + +template <class Helper> +class DataPipeImplTest : public testing::Test { + public: + DataPipeImplTest() {} + ~DataPipeImplTest() override {} + + void SetUp() override { helper_.SetUp(); } + void TearDown() override { helper_.TearDown(); } + + protected: + void Create(const MojoCreateDataPipeOptions& options) { + MojoCreateDataPipeOptions validated_options = {}; + ASSERT_EQ(MOJO_RESULT_OK, + DataPipe::ValidateCreateOptions(MakeUserPointer(&options), + &validated_options)); + helper_.Create(validated_options); + } + + void DoTransfer() { return helper_.DoTransfer(); } + + DataPipe* dpp() { return helper_.dpp(); } + DataPipe* dpc() { return helper_.dpc(); } + + void ProducerClose() { helper_.ProducerClose(); } + void ConsumerClose() { helper_.ConsumerClose(); } + + private: + Helper helper_; + + DISALLOW_COPY_AND_ASSIGN(DataPipeImplTest); +}; + +// LocalDataPipeImplTestHelper ------------------------------------------------- + +class LocalDataPipeImplTestHelper : public DataPipeImplTestHelper { + public: + LocalDataPipeImplTestHelper() {} + ~LocalDataPipeImplTestHelper() override {} + + void SetUp() override {} + void TearDown() override {} + + void Create(const MojoCreateDataPipeOptions& validated_options) override { + CHECK(!dp_); + dp_ = DataPipe::CreateLocal(validated_options); + } + + void DoTransfer() override {} + + // Returns the |DataPipe| object for the producer and consumer, respectively. + DataPipe* dpp() override { return dp_.get(); } + DataPipe* dpc() override { return dp_.get(); } + + void ProducerClose() override { dp_->ProducerClose(); } + void ConsumerClose() override { dp_->ConsumerClose(); } + + private: + scoped_refptr<DataPipe> dp_; + + DISALLOW_COPY_AND_ASSIGN(LocalDataPipeImplTestHelper); +}; + +// RemoteDataPipeImplTestHelper ------------------------------------------------ + +// Base class for |Remote{Producer,Consumer}DataPipeImplTestHelper|. +class RemoteDataPipeImplTestHelper : public DataPipeImplTestHelper { + public: + RemoteDataPipeImplTestHelper() : io_thread_(base::TestIOThread::kAutoStart) {} + ~RemoteDataPipeImplTestHelper() override {} + + void SetUp() override { + scoped_refptr<ChannelEndpoint> ep[2]; + message_pipes_[0] = MessagePipe::CreateLocalProxy(&ep[0]); + message_pipes_[1] = MessagePipe::CreateLocalProxy(&ep[1]); + + io_thread_.PostTaskAndWait( + FROM_HERE, base::Bind(&RemoteDataPipeImplTestHelper::SetUpOnIOThread, + base::Unretained(this), ep[0], ep[1])); + } + + void TearDown() override { + EnsureMessagePipeClosed(0); + EnsureMessagePipeClosed(1); + io_thread_.PostTaskAndWait( + FROM_HERE, base::Bind(&RemoteDataPipeImplTestHelper::TearDownOnIOThread, + base::Unretained(this))); + } + + void Create(const MojoCreateDataPipeOptions& validated_options) override { + CHECK(!dp_); + dp_ = DataPipe::CreateLocal(validated_options); + } + + protected: + void SendDispatcher(size_t source_i, + scoped_refptr<Dispatcher> to_send, + scoped_refptr<Dispatcher>* to_receive) { + DCHECK(source_i == 0 || source_i == 1); + size_t dest_i = source_i ^ 1; + + // Write the dispatcher to MP |source_i| (port 0). Wait and receive on MP + // |dest_i| (port 0). (Add the waiter first, to avoid any handling the case + // where it's already readable.) + Waiter waiter; + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + message_pipe(dest_i)->AddAwakable( + 0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 987, nullptr)); + { + DispatcherTransport transport( + test::DispatcherTryStartTransport(to_send.get())); + ASSERT_TRUE(transport.is_valid()); + + std::vector<DispatcherTransport> transports; + transports.push_back(transport); + ASSERT_EQ(MOJO_RESULT_OK, message_pipe(source_i)->WriteMessage( + 0, NullUserPointer(), 0, &transports, + MOJO_WRITE_MESSAGE_FLAG_NONE)); + transport.End(); + } + uint32_t context = 0; + ASSERT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context)); + EXPECT_EQ(987u, context); + HandleSignalsState hss = HandleSignalsState(); + message_pipe(dest_i)->RemoveAwakable(0, &waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, + hss.satisfied_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); + char read_buffer[100] = {}; + uint32_t read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); + DispatcherVector read_dispatchers; + uint32_t read_num_dispatchers = 10; // Maximum to get. + ASSERT_EQ(MOJO_RESULT_OK, + message_pipe(dest_i)->ReadMessage( + 0, UserPointer<void>(read_buffer), + MakeUserPointer(&read_buffer_size), &read_dispatchers, + &read_num_dispatchers, MOJO_READ_MESSAGE_FLAG_NONE)); + EXPECT_EQ(0u, static_cast<size_t>(read_buffer_size)); + ASSERT_EQ(1u, read_dispatchers.size()); + ASSERT_EQ(1u, read_num_dispatchers); + ASSERT_TRUE(read_dispatchers[0]); + EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); + + *to_receive = read_dispatchers[0]; + } + + scoped_refptr<MessagePipe> message_pipe(size_t i) { + return message_pipes_[i]; + } + scoped_refptr<DataPipe> dp() { return dp_; } + + private: + void EnsureMessagePipeClosed(size_t i) { + if (!message_pipes_[i]) + return; + message_pipes_[i]->Close(0); + message_pipes_[i] = nullptr; + } + + void SetUpOnIOThread(scoped_refptr<ChannelEndpoint> ep0, + scoped_refptr<ChannelEndpoint> ep1) { + CHECK_EQ(base::MessageLoop::current(), io_thread_.message_loop()); + + embedder::PlatformChannelPair channel_pair; + channels_[0] = new Channel(&platform_support_); + channels_[0]->Init(RawChannel::Create(channel_pair.PassServerHandle())); + channels_[0]->SetBootstrapEndpoint(ep0); + channels_[1] = new Channel(&platform_support_); + channels_[1]->Init(RawChannel::Create(channel_pair.PassClientHandle())); + channels_[1]->SetBootstrapEndpoint(ep1); + } + + void TearDownOnIOThread() { + CHECK_EQ(base::MessageLoop::current(), io_thread_.message_loop()); + + if (channels_[0]) { + channels_[0]->Shutdown(); + channels_[0] = nullptr; + } + if (channels_[1]) { + channels_[1]->Shutdown(); + channels_[1] = nullptr; + } + } + + embedder::SimplePlatformSupport platform_support_; + base::TestIOThread io_thread_; + scoped_refptr<Channel> channels_[2]; + scoped_refptr<MessagePipe> message_pipes_[2]; + + scoped_refptr<DataPipe> dp_; + + DISALLOW_COPY_AND_ASSIGN(RemoteDataPipeImplTestHelper); +}; + +// RemoteProducerDataPipeImplTestHelper ---------------------------------------- + +// Note about naming confusion: This class is named after the "local" class, +// i.e., |dp_| will have a |RemoteProducerDataPipeImpl|. The remote side, of +// course, will have a |RemoteConsumerDataPipeImpl|. +class RemoteProducerDataPipeImplTestHelper + : public RemoteDataPipeImplTestHelper { + public: + RemoteProducerDataPipeImplTestHelper() {} + ~RemoteProducerDataPipeImplTestHelper() override {} + + void DoTransfer() override { + // This is the producer dispatcher we'll send. + scoped_refptr<DataPipeProducerDispatcher> to_send = + new DataPipeProducerDispatcher(); + to_send->Init(dp()); + scoped_refptr<Dispatcher> to_receive; + SendDispatcher(0, to_send, &to_receive); + // |to_send| should have been closed. This is |DCHECK()|ed when it is + // destroyed. + EXPECT_TRUE(to_send->HasOneRef()); + to_send = nullptr; + + ASSERT_EQ(Dispatcher::kTypeDataPipeProducer, to_receive->GetType()); + producer_dispatcher_ = + static_cast<DataPipeProducerDispatcher*>(to_receive.get()); + } + + DataPipe* dpp() override { + if (producer_dispatcher_) + return producer_dispatcher_->GetDataPipeForTest(); + return dp().get(); + } + DataPipe* dpc() override { return dp().get(); } + + void ProducerClose() override { + if (producer_dispatcher_) + ASSERT_EQ(MOJO_RESULT_OK, producer_dispatcher_->Close()); + else + dp()->ProducerClose(); + } + void ConsumerClose() override { dp()->ConsumerClose(); } + + protected: + scoped_refptr<DataPipeProducerDispatcher> producer_dispatcher_; + + private: + DISALLOW_COPY_AND_ASSIGN(RemoteProducerDataPipeImplTestHelper); +}; + +// RemoteConsumerDataPipeImplTestHelper ---------------------------------------- + +// Note about naming confusion: This class is named after the "local" class, +// i.e., |dp_| will have a |RemoteConsumerDataPipeImpl|. The remote side, of +// course, will have a |RemoteProducerDataPipeImpl|. +class RemoteConsumerDataPipeImplTestHelper + : public RemoteDataPipeImplTestHelper { + public: + RemoteConsumerDataPipeImplTestHelper() {} + ~RemoteConsumerDataPipeImplTestHelper() override {} + + void DoTransfer() override { + // This is the consumer dispatcher we'll send. + scoped_refptr<DataPipeConsumerDispatcher> to_send = + new DataPipeConsumerDispatcher(); + to_send->Init(dp()); + scoped_refptr<Dispatcher> to_receive; + SendDispatcher(0, to_send, &to_receive); + // |to_send| should have been closed. This is |DCHECK()|ed when it is + // destroyed. + EXPECT_TRUE(to_send->HasOneRef()); + to_send = nullptr; + + ASSERT_EQ(Dispatcher::kTypeDataPipeConsumer, to_receive->GetType()); + consumer_dispatcher_ = + static_cast<DataPipeConsumerDispatcher*>(to_receive.get()); + } + + DataPipe* dpp() override { return dp().get(); } + DataPipe* dpc() override { + if (consumer_dispatcher_) + return consumer_dispatcher_->GetDataPipeForTest(); + return dp().get(); + } + + void ProducerClose() override { dp()->ProducerClose(); } + void ConsumerClose() override { + if (consumer_dispatcher_) + ASSERT_EQ(MOJO_RESULT_OK, consumer_dispatcher_->Close()); + else + dp()->ConsumerClose(); + } + + protected: + scoped_refptr<DataPipeConsumerDispatcher> consumer_dispatcher_; + + private: + DISALLOW_COPY_AND_ASSIGN(RemoteConsumerDataPipeImplTestHelper); +}; + +// RemoteProducerDataPipeImplTestHelper2 --------------------------------------- + +// This is like |RemoteProducerDataPipeImplTestHelper|, but |DoTransfer()| does +// a second transfer. This thus tests passing a producer handle twice, and in +// particular tests (some of) |RemoteConsumerDataPipeImpl|'s +// |ProducerEndSerialize()| (instead of |LocalDataPipeImpl|'s). +// +// Note about naming confusion: This class is named after the "local" class, +// i.e., |dp_| will have a |RemoteProducerDataPipeImpl|. The remote side, of +// course, will have a |RemoteConsumerDataPipeImpl|. +class RemoteProducerDataPipeImplTestHelper2 + : public RemoteProducerDataPipeImplTestHelper { + public: + RemoteProducerDataPipeImplTestHelper2() {} + ~RemoteProducerDataPipeImplTestHelper2() override {} + + void DoTransfer() override { + // This is the producer dispatcher we'll send. + scoped_refptr<DataPipeProducerDispatcher> to_send = + new DataPipeProducerDispatcher(); + to_send->Init(dp()); + scoped_refptr<Dispatcher> to_receive; + SendDispatcher(0, to_send, &to_receive); + // |to_send| should have been closed. This is |DCHECK()|ed when it is + // destroyed. + EXPECT_TRUE(to_send->HasOneRef()); + to_send = nullptr; + ASSERT_EQ(Dispatcher::kTypeDataPipeProducer, to_receive->GetType()); + to_send = static_cast<DataPipeProducerDispatcher*>(to_receive.get()); + to_receive = nullptr; + + // Now send it back the other way. + SendDispatcher(1, to_send, &to_receive); + // |producer_dispatcher_| should have been closed. This is |DCHECK()|ed when + // it is destroyed. + EXPECT_TRUE(to_send->HasOneRef()); + to_send = nullptr; + + ASSERT_EQ(Dispatcher::kTypeDataPipeProducer, to_receive->GetType()); + producer_dispatcher_ = + static_cast<DataPipeProducerDispatcher*>(to_receive.get()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(RemoteProducerDataPipeImplTestHelper2); +}; + +// RemoteConsumerDataPipeImplTestHelper2 --------------------------------------- + +// This is like |RemoteConsumerDataPipeImplTestHelper|, but |DoTransfer()| does +// a second transfer. This thus tests passing a consumer handle twice, and in +// particular tests (some of) |RemoteProducerDataPipeImpl|'s +// |ConsumerEndSerialize()| (instead of |LocalDataPipeImpl|'s). +// +// Note about naming confusion: This class is named after the "local" class, +// i.e., |dp_| will have a |RemoteConsumerDataPipeImpl|. The remote side, of +// course, will have a |RemoteProducerDataPipeImpl|. +class RemoteConsumerDataPipeImplTestHelper2 + : public RemoteConsumerDataPipeImplTestHelper { + public: + RemoteConsumerDataPipeImplTestHelper2() {} + ~RemoteConsumerDataPipeImplTestHelper2() override {} + + void DoTransfer() override { + // This is the consumer dispatcher we'll send. + scoped_refptr<DataPipeConsumerDispatcher> to_send = + new DataPipeConsumerDispatcher(); + to_send->Init(dp()); + scoped_refptr<Dispatcher> to_receive; + SendDispatcher(0, to_send, &to_receive); + // |to_send| should have been closed. This is |DCHECK()|ed when it is + // destroyed. + EXPECT_TRUE(to_send->HasOneRef()); + to_send = nullptr; + ASSERT_EQ(Dispatcher::kTypeDataPipeConsumer, to_receive->GetType()); + to_send = static_cast<DataPipeConsumerDispatcher*>(to_receive.get()); + to_receive = nullptr; + + // Now send it back the other way. + SendDispatcher(1, to_send, &to_receive); + // |consumer_dispatcher_| should have been closed. This is |DCHECK()|ed when + // it is destroyed. + EXPECT_TRUE(to_send->HasOneRef()); + to_send = nullptr; + + ASSERT_EQ(Dispatcher::kTypeDataPipeConsumer, to_receive->GetType()); + consumer_dispatcher_ = + static_cast<DataPipeConsumerDispatcher*>(to_receive.get()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(RemoteConsumerDataPipeImplTestHelper2); +}; + +// Test case instantiation ----------------------------------------------------- + +typedef testing::Types<LocalDataPipeImplTestHelper, + RemoteProducerDataPipeImplTestHelper, + RemoteConsumerDataPipeImplTestHelper, + RemoteProducerDataPipeImplTestHelper2, + RemoteConsumerDataPipeImplTestHelper2> HelperTypes; + +TYPED_TEST_CASE(DataPipeImplTest, HelperTypes); + +// Tests ----------------------------------------------------------------------- + +TYPED_TEST(DataPipeImplTest, SimpleReadWrite) { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 1000 * sizeof(int32_t) // |capacity_num_bytes|. + }; + this->Create(options); + this->DoTransfer(); + + Waiter waiter; + HandleSignalsState hss; + uint32_t context; + + int32_t elements[10] = {}; + uint32_t num_bytes = 0; + + // Try reading; nothing there yet. + num_bytes = static_cast<uint32_t>(arraysize(elements) * sizeof(elements[0])); + EXPECT_EQ( + MOJO_RESULT_SHOULD_WAIT, + this->dpc()->ConsumerReadData(UserPointer<void>(elements), + MakeUserPointer(&num_bytes), false, false)); + + // Query; nothing there yet. + num_bytes = 0; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(0u, num_bytes); + + // Discard; nothing there yet. + num_bytes = static_cast<uint32_t>(5u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, this->dpc()->ConsumerDiscardData( + MakeUserPointer(&num_bytes), false)); + + // Read with invalid |num_bytes|. + num_bytes = sizeof(elements[0]) + 1; + EXPECT_EQ( + MOJO_RESULT_INVALID_ARGUMENT, + this->dpc()->ConsumerReadData(UserPointer<void>(elements), + MakeUserPointer(&num_bytes), false, false)); + + // For remote data pipes, we'll have to wait; add the waiter before writing. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_READABLE, 123, nullptr)); + + // Write two elements. + elements[0] = 123; + elements[1] = 456; + num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerWriteData(UserPointer<const void>(elements), + MakeUserPointer(&num_bytes), false)); + // It should have written everything (even without "all or none"). + EXPECT_EQ(2u * sizeof(elements[0]), num_bytes); + + // Wait. + context = 0; + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context)); + EXPECT_EQ(123u, context); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Query. + // TODO(vtl): It's theoretically possible (though not with the current + // implementation/configured limits) that not all the data has arrived yet. + // (The theoretically-correct assertion here is that |num_bytes| is |1 * ...| + // or |2 * ...|.) + num_bytes = 0; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(2 * sizeof(elements[0]), num_bytes); + + // Read one element. + elements[0] = -1; + elements[1] = -1; + num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerReadData( + UserPointer<void>(elements), + MakeUserPointer(&num_bytes), false, false)); + EXPECT_EQ(1u * sizeof(elements[0]), num_bytes); + EXPECT_EQ(123, elements[0]); + EXPECT_EQ(-1, elements[1]); + + // Query. + // TODO(vtl): See previous TODO. (If we got 2 elements there, however, we + // should get 1 here.) + num_bytes = 0; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(1 * sizeof(elements[0]), num_bytes); + + // Peek one element. + elements[0] = -1; + elements[1] = -1; + num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerReadData( + UserPointer<void>(elements), + MakeUserPointer(&num_bytes), false, true)); + EXPECT_EQ(1u * sizeof(elements[0]), num_bytes); + EXPECT_EQ(456, elements[0]); + EXPECT_EQ(-1, elements[1]); + + // Query. Still has 1 element remaining. + num_bytes = 0; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(1 * sizeof(elements[0]), num_bytes); + + // Try to read two elements, with "all or none". + elements[0] = -1; + elements[1] = -1; + num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); + EXPECT_EQ( + MOJO_RESULT_OUT_OF_RANGE, + this->dpc()->ConsumerReadData(UserPointer<void>(elements), + MakeUserPointer(&num_bytes), true, false)); + EXPECT_EQ(-1, elements[0]); + EXPECT_EQ(-1, elements[1]); + + // Try to read two elements, without "all or none". + elements[0] = -1; + elements[1] = -1; + num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerReadData( + UserPointer<void>(elements), + MakeUserPointer(&num_bytes), false, false)); + EXPECT_EQ(1u * sizeof(elements[0]), num_bytes); + EXPECT_EQ(456, elements[0]); + EXPECT_EQ(-1, elements[1]); + + // Query. + num_bytes = 0; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(0u, num_bytes); + + this->ProducerClose(); + this->ConsumerClose(); +} + +// Note: The "basic" waiting tests test that the "wait states" are correct in +// various situations; they don't test that waiters are properly awoken on state +// changes. (For that, we need to use multiple threads.) +TYPED_TEST(DataPipeImplTest, BasicProducerWaiting) { + // Note: We take advantage of the fact that current for current + // implementations capacities are strict maximums. This is not guaranteed by + // the API. + + 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|. + }; + this->Create(options); + this->DoTransfer(); + + Waiter pwaiter; // For producer. + Waiter cwaiter; // For consumer. + HandleSignalsState hss; + uint32_t context; + + // Never readable. + pwaiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + this->dpp()->ProducerAddAwakable( + &pwaiter, MOJO_HANDLE_SIGNAL_READABLE, 12, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Already writable. + pwaiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + this->dpp()->ProducerAddAwakable( + &pwaiter, MOJO_HANDLE_SIGNAL_WRITABLE, 34, &hss)); + + // We'll need to wait for readability for the remote cases. + cwaiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &cwaiter, MOJO_HANDLE_SIGNAL_READABLE, 1234, nullptr)); + + // Write two elements. + int32_t elements[2] = {123, 456}; + uint32_t num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerWriteData(UserPointer<const void>(elements), + MakeUserPointer(&num_bytes), true)); + EXPECT_EQ(static_cast<uint32_t>(2u * sizeof(elements[0])), num_bytes); + + // Adding a waiter should now succeed. + pwaiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerAddAwakable( + &pwaiter, MOJO_HANDLE_SIGNAL_WRITABLE, 56, nullptr)); + // And it shouldn't be writable yet. + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, pwaiter.Wait(0, nullptr)); + hss = HandleSignalsState(); + this->dpp()->ProducerRemoveAwakable(&pwaiter, &hss); + EXPECT_EQ(0u, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Wait for data to become available to the consumer. + context = 0; + EXPECT_EQ(MOJO_RESULT_OK, cwaiter.Wait(test::TinyDeadline(), &context)); + EXPECT_EQ(1234u, context); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&cwaiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Peek one element. + elements[0] = -1; + elements[1] = -1; + num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerReadData( + UserPointer<void>(elements), + MakeUserPointer(&num_bytes), true, true)); + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); + EXPECT_EQ(123, elements[0]); + EXPECT_EQ(-1, elements[1]); + + // Add a waiter. + pwaiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerAddAwakable( + &pwaiter, MOJO_HANDLE_SIGNAL_WRITABLE, 56, nullptr)); + // And it still shouldn't be writable yet. + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, pwaiter.Wait(0, nullptr)); + hss = HandleSignalsState(); + this->dpp()->ProducerRemoveAwakable(&pwaiter, &hss); + EXPECT_EQ(0u, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Do it again. + pwaiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerAddAwakable( + &pwaiter, MOJO_HANDLE_SIGNAL_WRITABLE, 78, nullptr)); + + // Read one element. + elements[0] = -1; + elements[1] = -1; + num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerReadData( + UserPointer<void>(elements), + MakeUserPointer(&num_bytes), true, false)); + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); + EXPECT_EQ(123, elements[0]); + EXPECT_EQ(-1, elements[1]); + + // Waiting should now succeed. + context = 0; + EXPECT_EQ(MOJO_RESULT_OK, pwaiter.Wait(test::TinyDeadline(), &context)); + EXPECT_EQ(78u, context); + hss = HandleSignalsState(); + this->dpp()->ProducerRemoveAwakable(&pwaiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_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; + num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerBeginWriteData( + MakeUserPointer(&buffer), MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(buffer); + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); + + static_cast<int32_t*>(buffer)[0] = 789; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerEndWriteData( + static_cast<uint32_t>(1u * sizeof(elements[0])))); + + // Add a waiter. + pwaiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerAddAwakable( + &pwaiter, MOJO_HANDLE_SIGNAL_WRITABLE, 90, nullptr)); + + // Read one element, using a two-phase read. + const void* read_buffer = nullptr; + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerBeginReadData( + MakeUserPointer(&read_buffer), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(read_buffer); + // Since we only read one element (after having written three in all), the + // two-phase read should only allow us to read one. This checks an + // implementation detail! + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); + EXPECT_EQ(456, static_cast<const int32_t*>(read_buffer)[0]); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerEndReadData( + static_cast<uint32_t>(1u * sizeof(elements[0])))); + + // Waiting should succeed. + context = 0; + EXPECT_EQ(MOJO_RESULT_OK, pwaiter.Wait(test::TinyDeadline(), &context)); + EXPECT_EQ(90u, context); + hss = HandleSignalsState(); + this->dpp()->ProducerRemoveAwakable(&pwaiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Write one element. + elements[0] = 123; + num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerWriteData(UserPointer<const void>(elements), + MakeUserPointer(&num_bytes), false)); + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); + + // Add a waiter. + pwaiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerAddAwakable( + &pwaiter, MOJO_HANDLE_SIGNAL_WRITABLE, 12, nullptr)); + + // Close the consumer. + this->ConsumerClose(); + + // It should now be never-writable. + context = 0; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + pwaiter.Wait(test::TinyDeadline(), &context)); + EXPECT_EQ(12u, context); + hss = HandleSignalsState(); + this->dpp()->ProducerRemoveAwakable(&pwaiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + this->ProducerClose(); +} + +TYPED_TEST(DataPipeImplTest, PeerClosedProducerWaiting) { + 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|. + }; + this->Create(options); + this->DoTransfer(); + + Waiter waiter; + HandleSignalsState hss; + uint32_t context; + + // Add a waiter. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 12, nullptr)); + + // Close the consumer. + this->ConsumerClose(); + + // It should be signaled. + context = 0; + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), &context)); + EXPECT_EQ(12u, context); + hss = HandleSignalsState(); + this->dpp()->ProducerRemoveAwakable(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + this->ProducerClose(); +} + +TYPED_TEST(DataPipeImplTest, PeerClosedConsumerWaiting) { + 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|. + }; + this->Create(options); + this->DoTransfer(); + + Waiter waiter; + HandleSignalsState hss; + uint32_t context; + + // Add a waiter. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 12, nullptr)); + + // Close the producer. + this->ProducerClose(); + + // It should be signaled. + context = 0; + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), &context)); + EXPECT_EQ(12u, context); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + this->ConsumerClose(); +} + +TYPED_TEST(DataPipeImplTest, BasicConsumerWaiting) { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 1000 * sizeof(int32_t) // |capacity_num_bytes|. + }; + this->Create(options); + this->DoTransfer(); + + Waiter waiter; + Waiter waiter2; + HandleSignalsState hss; + uint32_t context; + + // Never writable. + waiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 12, &hss)); + EXPECT_EQ(0u, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Add waiter: not yet readable. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_READABLE, 34, nullptr)); + + // Write two elements. + int32_t elements[2] = {123, 456}; + uint32_t num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerWriteData(UserPointer<const void>(elements), + MakeUserPointer(&num_bytes), true)); + + // Wait for readability (needed for remote cases). + context = 0; + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), &context)); + EXPECT_EQ(34u, context); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_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])); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerDiscardData( + MakeUserPointer(&num_bytes), true)); + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); + + // Should still be readable. + waiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_READABLE, 78, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Peek one element. + elements[0] = -1; + elements[1] = -1; + num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerReadData( + UserPointer<void>(elements), + MakeUserPointer(&num_bytes), true, true)); + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); + EXPECT_EQ(456, elements[0]); + EXPECT_EQ(-1, elements[1]); + + // Should still be readable. + waiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_READABLE, 78, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Read one element. + elements[0] = -1; + elements[1] = -1; + num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerReadData( + UserPointer<void>(elements), + MakeUserPointer(&num_bytes), true, false)); + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); + EXPECT_EQ(456, elements[0]); + EXPECT_EQ(-1, elements[1]); + + // Adding a waiter should now succeed. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_READABLE, 90, nullptr)); + + // Write one element. + elements[0] = 789; + elements[1] = -1; + num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerWriteData(UserPointer<const void>(elements), + MakeUserPointer(&num_bytes), true)); + + // Waiting should now succeed. + context = 0; + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), &context)); + EXPECT_EQ(90u, context); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // We'll want to wait for the peer closed signal to propagate. + waiter.Init(); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 12, nullptr)); + + // Close the producer. + this->ProducerClose(); + + // Should still be readable, even if the peer closed signal hasn't propagated + // yet. + waiter2.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + this->dpc()->ConsumerAddAwakable( + &waiter2, MOJO_HANDLE_SIGNAL_READABLE, 34, &hss)); + // We don't know if the peer closed signal has propagated yet (for the remote + // cases). + EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Wait for the peer closed signal. + context = 0; + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), &context)); + EXPECT_EQ(12u, context); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&waiter, &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 one element. + elements[0] = -1; + elements[1] = -1; + num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerReadData( + UserPointer<void>(elements), + MakeUserPointer(&num_bytes), true, false)); + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); + EXPECT_EQ(789, elements[0]); + EXPECT_EQ(-1, elements[1]); + + // Should be never-readable. + waiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_READABLE, 56, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + this->ConsumerClose(); +} + +// Test with two-phase APIs and also closing the producer with an active +// consumer waiter. +TYPED_TEST(DataPipeImplTest, ConsumerWaitingTwoPhase) { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 1000 * sizeof(int32_t) // |capacity_num_bytes|. + }; + this->Create(options); + this->DoTransfer(); + + Waiter waiter; + HandleSignalsState hss; + uint32_t context; + + // Add waiter: not yet readable. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, nullptr)); + + // Write two elements. + int32_t* elements = nullptr; + void* buffer = nullptr; + // Request room for three (but we'll only write two). + uint32_t num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerBeginWriteData( + MakeUserPointer(&buffer), MakeUserPointer(&num_bytes), true)); + EXPECT_TRUE(buffer); + EXPECT_GE(num_bytes, static_cast<uint32_t>(3u * sizeof(elements[0]))); + elements = static_cast<int32_t*>(buffer); + elements[0] = 123; + elements[1] = 456; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerEndWriteData( + static_cast<uint32_t>(2u * sizeof(elements[0])))); + + // Wait for readability (needed for remote cases). + context = 0; + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), &context)); + EXPECT_EQ(12u, context); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_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. + const void* read_buffer = nullptr; + num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerBeginReadData( + MakeUserPointer(&read_buffer), + MakeUserPointer(&num_bytes), true)); + EXPECT_TRUE(read_buffer); + EXPECT_EQ(static_cast<uint32_t>(2u * sizeof(elements[0])), num_bytes); + const int32_t* read_elements = static_cast<const int32_t*>(read_buffer); + EXPECT_EQ(123, read_elements[0]); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerEndReadData( + static_cast<uint32_t>(1u * sizeof(elements[0])))); + + // Should still be readable. + waiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_READABLE, 34, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_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. + read_buffer = nullptr; + num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerBeginReadData( + MakeUserPointer(&read_buffer), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(read_buffer); + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); + read_elements = static_cast<const int32_t*>(read_buffer); + EXPECT_EQ(456, read_elements[0]); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerEndReadData( + static_cast<uint32_t>(1u * sizeof(elements[0])))); + + // Adding a waiter should now succeed. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_READABLE, 56, nullptr)); + + // Close the producer. + this->ProducerClose(); + + // Should be never-readable. + context = 0; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + waiter.Wait(test::TinyDeadline(), &context)); + EXPECT_EQ(56u, context); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + this->ConsumerClose(); +} + +// Tests that data pipes aren't writable/readable during two-phase writes/reads. +TYPED_TEST(DataPipeImplTest, BasicTwoPhaseWaiting) { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 1000 * sizeof(int32_t) // |capacity_num_bytes|. + }; + this->Create(options); + this->DoTransfer(); + + Waiter pwaiter; // For producer. + Waiter cwaiter; // For consumer. + HandleSignalsState hss; + + // It should be writable. + pwaiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + this->dpp()->ProducerAddAwakable( + &pwaiter, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_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; + EXPECT_EQ(MOJO_RESULT_OK, this->dpp()->ProducerBeginWriteData( + MakeUserPointer(&write_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(write_ptr); + EXPECT_GE(num_bytes, static_cast<uint32_t>(1u * sizeof(int32_t))); + + // At this point, it shouldn't be writable. + pwaiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerAddAwakable( + &pwaiter, MOJO_HANDLE_SIGNAL_WRITABLE, 1, nullptr)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, pwaiter.Wait(0, nullptr)); + hss = HandleSignalsState(); + this->dpp()->ProducerRemoveAwakable(&pwaiter, &hss); + EXPECT_EQ(0u, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // It shouldn't be readable yet either (we'll wait later). + cwaiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &cwaiter, MOJO_HANDLE_SIGNAL_READABLE, 2, nullptr)); + + static_cast<int32_t*>(write_ptr)[0] = 123; + EXPECT_EQ(MOJO_RESULT_OK, this->dpp()->ProducerEndWriteData( + static_cast<uint32_t>(1u * sizeof(int32_t)))); + + // It should immediately be writable again. + pwaiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + this->dpp()->ProducerAddAwakable( + &pwaiter, MOJO_HANDLE_SIGNAL_WRITABLE, 3, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // It should become readable. + EXPECT_EQ(MOJO_RESULT_OK, cwaiter.Wait(test::TinyDeadline(), nullptr)); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&cwaiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_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. + num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t)); + write_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_OK, this->dpp()->ProducerBeginWriteData( + MakeUserPointer(&write_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(write_ptr); + EXPECT_GE(num_bytes, static_cast<uint32_t>(1u * sizeof(int32_t))); + + // It should be readable. + cwaiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + this->dpc()->ConsumerAddAwakable( + &cwaiter, MOJO_HANDLE_SIGNAL_READABLE, 5, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_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, this->dpp()->ProducerEndWriteData(0u)); + + // Start a two-phase read. + num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t)); + const void* read_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerBeginReadData( + MakeUserPointer(&read_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(read_ptr); + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(int32_t)), num_bytes); + + // At this point, it should still be writable. + pwaiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + this->dpp()->ProducerAddAwakable( + &pwaiter, MOJO_HANDLE_SIGNAL_WRITABLE, 6, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // But not readable. + cwaiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &cwaiter, MOJO_HANDLE_SIGNAL_READABLE, 7, nullptr)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, cwaiter.Wait(0, nullptr)); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&cwaiter, &hss); + EXPECT_EQ(0u, hss.satisfied_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, this->dpc()->ConsumerEndReadData(0u)); + + // It should be readable again. + cwaiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + this->dpc()->ConsumerAddAwakable( + &cwaiter, MOJO_HANDLE_SIGNAL_READABLE, 8, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + this->ProducerClose(); + this->ConsumerClose(); +} + +void Seq(int32_t start, size_t count, int32_t* out) { + for (size_t i = 0; i < count; i++) + out[i] = start + static_cast<int32_t>(i); +} + +TYPED_TEST(DataPipeImplTest, AllOrNone) { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 10 * sizeof(int32_t) // |capacity_num_bytes|. + }; + this->Create(options); + this->DoTransfer(); + + Waiter waiter; + HandleSignalsState hss; + + // Try writing way too much. + uint32_t num_bytes = 20u * sizeof(int32_t); + int32_t buffer[100]; + Seq(0, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + this->dpp()->ProducerWriteData(UserPointer<const void>(buffer), + MakeUserPointer(&num_bytes), true)); + + // Should still be empty. + num_bytes = ~0u; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(0u, num_bytes); + + // Add waiter. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_READABLE, 1, nullptr)); + + // Write some data. + num_bytes = 5u * sizeof(int32_t); + Seq(100, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerWriteData(UserPointer<const void>(buffer), + MakeUserPointer(&num_bytes), true)); + EXPECT_EQ(5u * sizeof(int32_t), num_bytes); + + // Wait for data. + // TODO(vtl): There's no real guarantee that all the data will become + // available at once (except that in current implementations, with reasonable + // limits, it will). Eventually, we'll be able to wait for a specified amount + // of data to become available. + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr)); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Half full. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(5u * sizeof(int32_t), num_bytes); + + // Too much. + num_bytes = 6u * sizeof(int32_t); + Seq(200, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + this->dpp()->ProducerWriteData(UserPointer<const void>(buffer), + MakeUserPointer(&num_bytes), true)); + + // Try reading too much. + num_bytes = 11u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ( + MOJO_RESULT_OUT_OF_RANGE, + this->dpc()->ConsumerReadData(UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), true, false)); + int32_t expected_buffer[100]; + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + // Try discarding too much. + num_bytes = 11u * sizeof(int32_t); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, this->dpc()->ConsumerDiscardData( + MakeUserPointer(&num_bytes), true)); + + // Just a little. + num_bytes = 2u * sizeof(int32_t); + Seq(300, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerWriteData(UserPointer<const void>(buffer), + MakeUserPointer(&num_bytes), true)); + EXPECT_EQ(2u * sizeof(int32_t), num_bytes); + + // Just right. + num_bytes = 3u * sizeof(int32_t); + Seq(400, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerWriteData(UserPointer<const void>(buffer), + MakeUserPointer(&num_bytes), true)); + EXPECT_EQ(3u * sizeof(int32_t), num_bytes); + + // TODO(vtl): Hack (see also the TODO above): We can't currently wait for a + // specified amount of data to be available, so poll. + const size_t kMaxPoll = 100; + for (size_t i = 0; i < kMaxPoll; i++) { + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerQueryData(MakeUserPointer(&num_bytes))); + if (num_bytes >= 10u * sizeof(int32_t)) + break; + + base::PlatformThread::Sleep(test::EpsilonTimeout()); + } + EXPECT_EQ(10u * sizeof(int32_t), num_bytes); + + // Read half. + num_bytes = 5u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerReadData( + UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), true, false)); + EXPECT_EQ(5u * sizeof(int32_t), num_bytes); + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + Seq(100, 5, expected_buffer); + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + // Try reading too much again. + num_bytes = 6u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ( + MOJO_RESULT_OUT_OF_RANGE, + this->dpc()->ConsumerReadData(UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), true, false)); + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + // Try discarding too much again. + num_bytes = 6u * sizeof(int32_t); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, this->dpc()->ConsumerDiscardData( + MakeUserPointer(&num_bytes), true)); + + // Discard a little. + num_bytes = 2u * sizeof(int32_t); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerDiscardData( + MakeUserPointer(&num_bytes), true)); + EXPECT_EQ(2u * sizeof(int32_t), num_bytes); + + // Three left. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(3u * sizeof(int32_t), num_bytes); + + // We'll need to wait for the peer closed to propagate. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 2, nullptr)); + + // Close the producer, then test producer-closed cases. + this->ProducerClose(); + + // Wait. + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr)); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&waiter, &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); + + // Try reading too much; "failed precondition" since the producer is closed. + num_bytes = 4u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ( + MOJO_RESULT_FAILED_PRECONDITION, + this->dpc()->ConsumerReadData(UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), true, false)); + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + // Try discarding too much; "failed precondition" again. + num_bytes = 4u * sizeof(int32_t); + EXPECT_EQ( + MOJO_RESULT_FAILED_PRECONDITION, + this->dpc()->ConsumerDiscardData(MakeUserPointer(&num_bytes), true)); + + // Read a little. + num_bytes = 2u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerReadData( + UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), true, false)); + EXPECT_EQ(2u * sizeof(int32_t), num_bytes); + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + Seq(400, 2, expected_buffer); + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + // Discard the remaining element. + num_bytes = 1u * sizeof(int32_t); + EXPECT_EQ(MOJO_RESULT_OK, this->dpc()->ConsumerDiscardData( + MakeUserPointer(&num_bytes), true)); + EXPECT_EQ(1u * sizeof(int32_t), num_bytes); + + // Empty again. + num_bytes = ~0u; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(0u, num_bytes); + + this->ConsumerClose(); +} + +TYPED_TEST(DataPipeImplTest, TwoPhaseAllOrNone) { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 10 * sizeof(int32_t) // |capacity_num_bytes|. + }; + this->Create(options); + this->DoTransfer(); + + Waiter waiter; + HandleSignalsState hss; + + // Try writing way too much (two-phase). + uint32_t num_bytes = 20u * sizeof(int32_t); + void* write_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, this->dpp()->ProducerBeginWriteData( + MakeUserPointer(&write_ptr), + MakeUserPointer(&num_bytes), true)); + + // Try writing an amount which isn't a multiple of the element size + // (two-phase). + static_assert(sizeof(int32_t) > 1u, "Wow! int32_t's have size 1"); + num_bytes = 1u; + write_ptr = nullptr; + EXPECT_EQ( + MOJO_RESULT_INVALID_ARGUMENT, + this->dpp()->ProducerBeginWriteData(MakeUserPointer(&write_ptr), + MakeUserPointer(&num_bytes), true)); + + // Try reading way too much (two-phase). + num_bytes = 20u * sizeof(int32_t); + const void* read_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + this->dpc()->ConsumerBeginReadData( + MakeUserPointer(&read_ptr), MakeUserPointer(&num_bytes), true)); + + // Add waiter. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_READABLE, 1, nullptr)); + + // Write half (two-phase). + num_bytes = 5u * sizeof(int32_t); + write_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_OK, this->dpp()->ProducerBeginWriteData( + MakeUserPointer(&write_ptr), + MakeUserPointer(&num_bytes), true)); + // May provide more space than requested. + EXPECT_GE(num_bytes, 5u * sizeof(int32_t)); + EXPECT_TRUE(write_ptr); + Seq(0, 5, static_cast<int32_t*>(write_ptr)); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpp()->ProducerEndWriteData(5u * sizeof(int32_t))); + + // Wait for data. + // TODO(vtl): (See corresponding TODO in AllOrNone.) + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr)); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Try reading an amount which isn't a multiple of the element size + // (two-phase). + num_bytes = 1u; + read_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + this->dpc()->ConsumerBeginReadData( + MakeUserPointer(&read_ptr), MakeUserPointer(&num_bytes), true)); + + // Read one (two-phase). + num_bytes = 1u * sizeof(int32_t); + read_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerBeginReadData( + MakeUserPointer(&read_ptr), MakeUserPointer(&num_bytes), true)); + EXPECT_GE(num_bytes, 1u * sizeof(int32_t)); + EXPECT_EQ(0, static_cast<const int32_t*>(read_ptr)[0]); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerEndReadData(1u * sizeof(int32_t))); + + // We should have four left, leaving room for six. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(4u * sizeof(int32_t), num_bytes); + + // Assuming a tight circular buffer of the specified capacity, we can't do a + // two-phase write of six now. + num_bytes = 6u * sizeof(int32_t); + write_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, this->dpp()->ProducerBeginWriteData( + MakeUserPointer(&write_ptr), + MakeUserPointer(&num_bytes), true)); + + // TODO(vtl): Hack (see also the TODO above): We can't currently wait for a + // specified amount of space to be available, so poll. + const size_t kMaxPoll = 100; + for (size_t i = 0; i < kMaxPoll; i++) { + // Write six elements (simple), filling the buffer. + num_bytes = 6u * sizeof(int32_t); + int32_t buffer[100]; + Seq(100, 6, buffer); + MojoResult result = this->dpp()->ProducerWriteData( + UserPointer<const void>(buffer), MakeUserPointer(&num_bytes), true); + if (result == MOJO_RESULT_OK) + break; + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, result); + + base::PlatformThread::Sleep(test::EpsilonTimeout()); + } + EXPECT_EQ(6u * sizeof(int32_t), num_bytes); + + // TODO(vtl): Hack: poll again. + for (size_t i = 0; i < kMaxPoll; i++) { + // We have ten. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerQueryData(MakeUserPointer(&num_bytes))); + if (num_bytes >= 10u * sizeof(int32_t)) + break; + + base::PlatformThread::Sleep(test::EpsilonTimeout()); + } + EXPECT_EQ(10u * sizeof(int32_t), num_bytes); + + // Note: Whether a two-phase read of ten would fail here or not is + // implementation-dependent. + + // Add waiter. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerAddAwakable( + &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 2, nullptr)); + + // Close the producer. + this->ProducerClose(); + + // A two-phase read of nine should work. + num_bytes = 9u * sizeof(int32_t); + read_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerBeginReadData( + MakeUserPointer(&read_ptr), MakeUserPointer(&num_bytes), true)); + EXPECT_GE(num_bytes, 9u * sizeof(int32_t)); + EXPECT_EQ(1, static_cast<const int32_t*>(read_ptr)[0]); + EXPECT_EQ(2, static_cast<const int32_t*>(read_ptr)[1]); + EXPECT_EQ(3, static_cast<const int32_t*>(read_ptr)[2]); + EXPECT_EQ(4, static_cast<const int32_t*>(read_ptr)[3]); + EXPECT_EQ(100, static_cast<const int32_t*>(read_ptr)[4]); + EXPECT_EQ(101, static_cast<const int32_t*>(read_ptr)[5]); + EXPECT_EQ(102, static_cast<const int32_t*>(read_ptr)[6]); + EXPECT_EQ(103, static_cast<const int32_t*>(read_ptr)[7]); + EXPECT_EQ(104, static_cast<const int32_t*>(read_ptr)[8]); + EXPECT_EQ(MOJO_RESULT_OK, + this->dpc()->ConsumerEndReadData(9u * sizeof(int32_t))); + + // Wait for peer closed. + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr)); + hss = HandleSignalsState(); + this->dpc()->ConsumerRemoveAwakable(&waiter, &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); + + // A two-phase read of two should fail, with "failed precondition". + num_bytes = 2u * sizeof(int32_t); + read_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + this->dpc()->ConsumerBeginReadData( + MakeUserPointer(&read_ptr), MakeUserPointer(&num_bytes), true)); + + this->ConsumerClose(); +} + +} // namespace +} // namespace system +} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/data_pipe_producer_dispatcher.cc b/third_party/mojo/src/mojo/edk/system/data_pipe_producer_dispatcher.cc index 0531126..2480097 100644 --- a/third_party/mojo/src/mojo/edk/system/data_pipe_producer_dispatcher.cc +++ b/third_party/mojo/src/mojo/edk/system/data_pipe_producer_dispatcher.cc
@@ -23,6 +23,22 @@ return kTypeDataPipeProducer; } +// static +scoped_refptr<DataPipeProducerDispatcher> +DataPipeProducerDispatcher::Deserialize(Channel* channel, + const void* source, + size_t size) { + scoped_refptr<DataPipe> data_pipe; + if (!DataPipe::ProducerDeserialize(channel, source, size, &data_pipe)) + return nullptr; + DCHECK(data_pipe); + + scoped_refptr<DataPipeProducerDispatcher> dispatcher( + new DataPipeProducerDispatcher()); + dispatcher->Init(data_pipe); + return dispatcher; +} + DataPipeProducerDispatcher::~DataPipeProducerDispatcher() { // |Close()|/|CloseImplNoLock()| should have taken care of the pipe. DCHECK(!data_pipe_); @@ -99,6 +115,27 @@ data_pipe_->ProducerRemoveAwakable(awakable, signals_state); } +void DataPipeProducerDispatcher::StartSerializeImplNoLock( + Channel* channel, + size_t* max_size, + size_t* max_platform_handles) { + DCHECK(HasOneRef()); // Only one ref => no need to take the lock. + data_pipe_->ProducerStartSerialize(channel, max_size, max_platform_handles); +} + +bool DataPipeProducerDispatcher::EndSerializeAndCloseImplNoLock( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) { + DCHECK(HasOneRef()); // Only one ref => no need to take the lock. + + bool rv = data_pipe_->ProducerEndSerialize(channel, destination, actual_size, + platform_handles); + data_pipe_ = nullptr; + return rv; +} + bool DataPipeProducerDispatcher::IsBusyNoLock() const { lock().AssertAcquired(); return data_pipe_->ProducerIsBusy();
diff --git a/third_party/mojo/src/mojo/edk/system/data_pipe_producer_dispatcher.h b/third_party/mojo/src/mojo/edk/system/data_pipe_producer_dispatcher.h index 39c070c..0a563d74 100644 --- a/third_party/mojo/src/mojo/edk/system/data_pipe_producer_dispatcher.h +++ b/third_party/mojo/src/mojo/edk/system/data_pipe_producer_dispatcher.h
@@ -28,6 +28,14 @@ // |Dispatcher| public methods: Type GetType() const override; + // The "opposite" of |SerializeAndClose()|. (Typically this is called by + // |Dispatcher::Deserialize()|.) + static scoped_refptr<DataPipeProducerDispatcher> + Deserialize(Channel* channel, const void* source, size_t size); + + // Get access to the |DataPipe| for testing. + DataPipe* GetDataPipeForTest() { return data_pipe_.get(); } + private: ~DataPipeProducerDispatcher() override; @@ -50,6 +58,14 @@ HandleSignalsState* signals_state) override; void RemoveAwakableImplNoLock(Awakable* awakable, HandleSignalsState* signals_state) override; + void StartSerializeImplNoLock(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) override; + bool EndSerializeAndCloseImplNoLock( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) override; bool IsBusyNoLock() const override; // Protected by |lock()|:
diff --git a/third_party/mojo/src/mojo/edk/system/data_pipe_unittest.cc b/third_party/mojo/src/mojo/edk/system/data_pipe_unittest.cc index ad02222..c298238 100644 --- a/third_party/mojo/src/mojo/edk/system/data_pipe_unittest.cc +++ b/third_party/mojo/src/mojo/edk/system/data_pipe_unittest.cc
@@ -79,8 +79,7 @@ // Different flags. MojoCreateDataPipeOptionsFlags flags_values[] = { - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD}; + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE}; for (size_t i = 0; i < arraysize(flags_values); i++) { const MojoCreateDataPipeOptionsFlags flags = flags_values[i];
diff --git a/third_party/mojo/src/mojo/edk/system/dispatcher.cc b/third_party/mojo/src/mojo/edk/system/dispatcher.cc index e2f2b87..e8695e8 100644 --- a/third_party/mojo/src/mojo/edk/system/dispatcher.cc +++ b/third_party/mojo/src/mojo/edk/system/dispatcher.cc
@@ -6,6 +6,8 @@ #include "base/logging.h" #include "mojo/edk/system/configuration.h" +#include "mojo/edk/system/data_pipe_consumer_dispatcher.h" +#include "mojo/edk/system/data_pipe_producer_dispatcher.h" #include "mojo/edk/system/message_pipe_dispatcher.h" #include "mojo/edk/system/platform_handle_dispatcher.h" #include "mojo/edk/system/shared_buffer_dispatcher.h" @@ -77,11 +79,11 @@ return scoped_refptr<Dispatcher>( MessagePipeDispatcher::Deserialize(channel, source, size)); case kTypeDataPipeProducer: + return scoped_refptr<Dispatcher>( + DataPipeProducerDispatcher::Deserialize(channel, source, size)); case kTypeDataPipeConsumer: - // TODO(vtl): Implement. - LOG(WARNING) << "Deserialization of dispatcher type " << type - << " not supported"; - return nullptr; + return scoped_refptr<Dispatcher>( + DataPipeConsumerDispatcher::Deserialize(channel, source, size)); case kTypeSharedBuffer: return scoped_refptr<Dispatcher>(SharedBufferDispatcher::Deserialize( channel, source, size, platform_handles));
diff --git a/third_party/mojo/src/mojo/edk/system/dispatcher.h b/third_party/mojo/src/mojo/edk/system/dispatcher.h index c069269..4bbc5ed 100644 --- a/third_party/mojo/src/mojo/edk/system/dispatcher.h +++ b/third_party/mojo/src/mojo/edk/system/dispatcher.h
@@ -297,6 +297,11 @@ size_t* actual_size, embedder::PlatformHandleVector* platform_handles); + // This should be overridden to return true if/when there's an ongoing + // operation (e.g., two-phase read/writes on data pipes) that should prevent a + // handle from being sent over a message pipe (with status "busy"). + virtual bool IsBusyNoLock() const; + // Available to subclasses. (Note: Returns a non-const reference, just like // |base::AutoLock|'s constructor takes a non-const reference.) base::Lock& lock() const { return lock_; } @@ -304,11 +309,6 @@ private: friend class DispatcherTransport; - // This should be overridden to return true if/when there's an ongoing - // operation (e.g., two-phase read/writes on data pipes) that should prevent a - // handle from being sent over a message pipe (with status "busy"). - virtual bool IsBusyNoLock() const; - // Closes the dispatcher. This must be done under lock, and unlike |Close()|, // the dispatcher must not be closed already. (This is the "equivalent" of // |CreateEquivalentDispatcherAndCloseNoLock()|, for situations where the
diff --git a/third_party/mojo/src/mojo/edk/system/incoming_endpoint.cc b/third_party/mojo/src/mojo/edk/system/incoming_endpoint.cc index 14f1a718..cd091b1 100644 --- a/third_party/mojo/src/mojo/edk/system/incoming_endpoint.cc +++ b/third_party/mojo/src/mojo/edk/system/incoming_endpoint.cc
@@ -6,8 +6,10 @@ #include "base/logging.h" #include "mojo/edk/system/channel_endpoint.h" +#include "mojo/edk/system/data_pipe.h" #include "mojo/edk/system/message_in_transit.h" #include "mojo/edk/system/message_pipe.h" +#include "mojo/edk/system/remote_producer_data_pipe_impl.h" namespace mojo { namespace system { @@ -30,6 +32,27 @@ return message_pipe; } +scoped_refptr<DataPipe> IncomingEndpoint::ConvertToDataPipeProducer( + const MojoCreateDataPipeOptions& validated_options, + size_t consumer_num_bytes) { + base::AutoLock locker(lock_); + scoped_refptr<DataPipe> data_pipe(DataPipe::CreateRemoteConsumerFromExisting( + validated_options, consumer_num_bytes, &message_queue_, endpoint_.get())); + DCHECK(message_queue_.IsEmpty()); + endpoint_ = nullptr; + return data_pipe; +} + +scoped_refptr<DataPipe> IncomingEndpoint::ConvertToDataPipeConsumer( + const MojoCreateDataPipeOptions& validated_options) { + base::AutoLock locker(lock_); + scoped_refptr<DataPipe> data_pipe(DataPipe::CreateRemoteProducerFromExisting( + validated_options, &message_queue_, endpoint_.get())); + DCHECK(message_queue_.IsEmpty()); + endpoint_ = nullptr; + return data_pipe; +} + void IncomingEndpoint::Close() { base::AutoLock locker(lock_); if (endpoint_) {
diff --git a/third_party/mojo/src/mojo/edk/system/incoming_endpoint.h b/third_party/mojo/src/mojo/edk/system/incoming_endpoint.h index 4db7d5a..6a6f04f 100644 --- a/third_party/mojo/src/mojo/edk/system/incoming_endpoint.h +++ b/third_party/mojo/src/mojo/edk/system/incoming_endpoint.h
@@ -5,6 +5,8 @@ #ifndef MOJO_EDK_SYSTEM_INCOMING_ENDPOINT_H_ #define MOJO_EDK_SYSTEM_INCOMING_ENDPOINT_H_ +#include <stddef.h> + #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" @@ -12,15 +14,18 @@ #include "mojo/edk/system/message_in_transit_queue.h" #include "mojo/edk/system/system_impl_export.h" +struct MojoCreateDataPipeOptions; + namespace mojo { namespace system { class ChannelEndpoint; +class DataPipe; class MessagePipe; // This is a simple |ChannelEndpointClient| that only receives messages. It's // used for endpoints that are "received" by |Channel|, but not yet turned into -// |MessagePipe|s. +// |MessagePipe|s or |DataPipe|s. class MOJO_SYSTEM_IMPL_EXPORT IncomingEndpoint : public ChannelEndpointClient { public: IncomingEndpoint(); @@ -29,6 +34,11 @@ scoped_refptr<ChannelEndpoint> Init(); scoped_refptr<MessagePipe> ConvertToMessagePipe(); + scoped_refptr<DataPipe> ConvertToDataPipeProducer( + const MojoCreateDataPipeOptions& validated_options, + size_t consumer_num_bytes); + scoped_refptr<DataPipe> ConvertToDataPipeConsumer( + const MojoCreateDataPipeOptions& validated_options); // Must be called before destroying this object if |ConvertToMessagePipe()| // wasn't called (but |Init()| was).
diff --git a/third_party/mojo/src/mojo/edk/system/local_data_pipe.cc b/third_party/mojo/src/mojo/edk/system/local_data_pipe.cc deleted file mode 100644 index 8b9f673..0000000 --- a/third_party/mojo/src/mojo/edk/system/local_data_pipe.cc +++ /dev/null
@@ -1,350 +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. - -// TODO(vtl): I currently potentially overflow in doing index calculations. -// E.g., |start_index_| and |current_num_bytes_| fit into a |uint32_t|, but -// their sum may not. This is bad and poses a security risk. (We're currently -// saved by the limit on capacity -- the maximum size of the buffer, checked in -// |DataPipe::ValidateOptions()|, is currently sufficiently small.) - -#include "mojo/edk/system/local_data_pipe.h" - -#include <string.h> - -#include <algorithm> - -#include "base/logging.h" -#include "mojo/edk/system/configuration.h" - -namespace mojo { -namespace system { - -LocalDataPipe::LocalDataPipe(const MojoCreateDataPipeOptions& options) - : DataPipe(true, true, options), start_index_(0), current_num_bytes_(0) { - // Note: |buffer_| is lazily allocated, since a common case will be that one - // of the handles is immediately passed off to another process. -} - -LocalDataPipe::~LocalDataPipe() { -} - -void LocalDataPipe::ProducerCloseImplNoLock() { - // If the consumer is still open and we still have data, we have to keep the - // buffer around. Currently, we won't free it even if it empties later. (We - // could do this -- requiring a check on every read -- but that seems to be - // optimizing for the uncommon case.) - if (!consumer_open_no_lock() || !current_num_bytes_) { - // Note: There can only be a two-phase *read* (by the consumer) if we still - // have data. - DCHECK(!consumer_in_two_phase_read_no_lock()); - DestroyBufferNoLock(); - } -} - -MojoResult LocalDataPipe::ProducerWriteDataImplNoLock( - UserPointer<const void> elements, - UserPointer<uint32_t> num_bytes, - uint32_t max_num_bytes_to_write, - uint32_t min_num_bytes_to_write) { - DCHECK_EQ(max_num_bytes_to_write % element_num_bytes(), 0u); - DCHECK_EQ(min_num_bytes_to_write % element_num_bytes(), 0u); - DCHECK_GT(max_num_bytes_to_write, 0u); - DCHECK(consumer_open_no_lock()); - - size_t num_bytes_to_write = 0; - if (may_discard()) { - if (min_num_bytes_to_write > capacity_num_bytes()) - return MOJO_RESULT_OUT_OF_RANGE; - - num_bytes_to_write = std::min(static_cast<size_t>(max_num_bytes_to_write), - capacity_num_bytes()); - if (num_bytes_to_write > capacity_num_bytes() - current_num_bytes_) { - // Discard as much as needed (discard oldest first). - MarkDataAsConsumedNoLock(num_bytes_to_write - - (capacity_num_bytes() - current_num_bytes_)); - // No need to wake up write waiters, since we're definitely going to leave - // the buffer full. - } - } else { - if (min_num_bytes_to_write > capacity_num_bytes() - current_num_bytes_) { - // Don't return "should wait" since you can't wait for a specified amount - // of data. - return MOJO_RESULT_OUT_OF_RANGE; - } - - num_bytes_to_write = std::min(static_cast<size_t>(max_num_bytes_to_write), - capacity_num_bytes() - current_num_bytes_); - } - if (num_bytes_to_write == 0) - return MOJO_RESULT_SHOULD_WAIT; - - // The amount we can write in our first |memcpy()|. - size_t num_bytes_to_write_first = - std::min(num_bytes_to_write, GetMaxNumBytesToWriteNoLock()); - // Do the first (and possibly only) |memcpy()|. - size_t first_write_index = - (start_index_ + current_num_bytes_) % capacity_num_bytes(); - EnsureBufferNoLock(); - elements.GetArray(buffer_.get() + first_write_index, - num_bytes_to_write_first); - - if (num_bytes_to_write_first < num_bytes_to_write) { - // The "second write index" is zero. - elements.At(num_bytes_to_write_first) - .GetArray(buffer_.get(), num_bytes_to_write - num_bytes_to_write_first); - } - - current_num_bytes_ += num_bytes_to_write; - DCHECK_LE(current_num_bytes_, capacity_num_bytes()); - num_bytes.Put(static_cast<uint32_t>(num_bytes_to_write)); - return MOJO_RESULT_OK; -} - -MojoResult LocalDataPipe::ProducerBeginWriteDataImplNoLock( - UserPointer<void*> buffer, - UserPointer<uint32_t> buffer_num_bytes, - uint32_t min_num_bytes_to_write) { - DCHECK(consumer_open_no_lock()); - - // The index we need to start writing at. - size_t write_index = - (start_index_ + current_num_bytes_) % capacity_num_bytes(); - - size_t max_num_bytes_to_write = GetMaxNumBytesToWriteNoLock(); - if (min_num_bytes_to_write > max_num_bytes_to_write) { - // In "may discard" mode, we can always write from the write index to the - // end of the buffer. - if (may_discard() && - min_num_bytes_to_write <= capacity_num_bytes() - write_index) { - // To do so, we need to discard an appropriate amount of data. - // We should only reach here if the start index is after the write index! - DCHECK_GE(start_index_, write_index); - DCHECK_GT(min_num_bytes_to_write - max_num_bytes_to_write, 0u); - MarkDataAsConsumedNoLock(min_num_bytes_to_write - max_num_bytes_to_write); - max_num_bytes_to_write = min_num_bytes_to_write; - } else { - // Don't return "should wait" since you can't wait for a specified amount - // of data. - return MOJO_RESULT_OUT_OF_RANGE; - } - } - - // Don't go into a two-phase write if there's no room. - if (max_num_bytes_to_write == 0) - return MOJO_RESULT_SHOULD_WAIT; - - EnsureBufferNoLock(); - buffer.Put(buffer_.get() + write_index); - buffer_num_bytes.Put(static_cast<uint32_t>(max_num_bytes_to_write)); - set_producer_two_phase_max_num_bytes_written_no_lock( - static_cast<uint32_t>(max_num_bytes_to_write)); - return MOJO_RESULT_OK; -} - -MojoResult LocalDataPipe::ProducerEndWriteDataImplNoLock( - uint32_t num_bytes_written) { - DCHECK_LE(num_bytes_written, - producer_two_phase_max_num_bytes_written_no_lock()); - current_num_bytes_ += num_bytes_written; - DCHECK_LE(current_num_bytes_, capacity_num_bytes()); - set_producer_two_phase_max_num_bytes_written_no_lock(0); - return MOJO_RESULT_OK; -} - -HandleSignalsState LocalDataPipe::ProducerGetHandleSignalsStateImplNoLock() - const { - HandleSignalsState rv; - if (consumer_open_no_lock()) { - if ((may_discard() || current_num_bytes_ < capacity_num_bytes()) && - !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; -} - -void LocalDataPipe::ConsumerCloseImplNoLock() { - // If the producer is around and in a two-phase write, we have to keep the - // buffer around. (We then don't free it until the producer is closed. This - // could be rectified, but again seems like optimizing for the uncommon case.) - if (!producer_open_no_lock() || !producer_in_two_phase_write_no_lock()) - DestroyBufferNoLock(); - current_num_bytes_ = 0; -} - -MojoResult LocalDataPipe::ConsumerReadDataImplNoLock( - UserPointer<void> elements, - UserPointer<uint32_t> num_bytes, - uint32_t max_num_bytes_to_read, - uint32_t min_num_bytes_to_read, - bool peek) { - DCHECK_EQ(max_num_bytes_to_read % element_num_bytes(), 0u); - DCHECK_EQ(min_num_bytes_to_read % element_num_bytes(), 0u); - DCHECK_GT(max_num_bytes_to_read, 0u); - - if (min_num_bytes_to_read > current_num_bytes_) { - // Don't return "should wait" since you can't wait for a specified amount of - // data. - return producer_open_no_lock() ? MOJO_RESULT_OUT_OF_RANGE - : MOJO_RESULT_FAILED_PRECONDITION; - } - - size_t num_bytes_to_read = - std::min(static_cast<size_t>(max_num_bytes_to_read), current_num_bytes_); - if (num_bytes_to_read == 0) { - return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT - : MOJO_RESULT_FAILED_PRECONDITION; - } - - // The amount we can read in our first |memcpy()|. - size_t num_bytes_to_read_first = - std::min(num_bytes_to_read, GetMaxNumBytesToReadNoLock()); - elements.PutArray(buffer_.get() + start_index_, num_bytes_to_read_first); - - if (num_bytes_to_read_first < num_bytes_to_read) { - // The "second read index" is zero. - elements.At(num_bytes_to_read_first) - .PutArray(buffer_.get(), num_bytes_to_read - num_bytes_to_read_first); - } - - if (!peek) - MarkDataAsConsumedNoLock(num_bytes_to_read); - num_bytes.Put(static_cast<uint32_t>(num_bytes_to_read)); - return MOJO_RESULT_OK; -} - -MojoResult LocalDataPipe::ConsumerDiscardDataImplNoLock( - UserPointer<uint32_t> num_bytes, - uint32_t max_num_bytes_to_discard, - uint32_t min_num_bytes_to_discard) { - DCHECK_EQ(max_num_bytes_to_discard % element_num_bytes(), 0u); - DCHECK_EQ(min_num_bytes_to_discard % element_num_bytes(), 0u); - DCHECK_GT(max_num_bytes_to_discard, 0u); - - if (min_num_bytes_to_discard > current_num_bytes_) { - // Don't return "should wait" since you can't wait for a specified amount of - // data. - return producer_open_no_lock() ? MOJO_RESULT_OUT_OF_RANGE - : MOJO_RESULT_FAILED_PRECONDITION; - } - - // Be consistent with other operations; error if no data available. - if (current_num_bytes_ == 0) { - return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT - : MOJO_RESULT_FAILED_PRECONDITION; - } - - size_t num_bytes_to_discard = std::min( - static_cast<size_t>(max_num_bytes_to_discard), current_num_bytes_); - MarkDataAsConsumedNoLock(num_bytes_to_discard); - num_bytes.Put(static_cast<uint32_t>(num_bytes_to_discard)); - return MOJO_RESULT_OK; -} - -MojoResult LocalDataPipe::ConsumerQueryDataImplNoLock( - UserPointer<uint32_t> num_bytes) { - // Note: This cast is safe, since the capacity fits into a |uint32_t|. - num_bytes.Put(static_cast<uint32_t>(current_num_bytes_)); - return MOJO_RESULT_OK; -} - -MojoResult LocalDataPipe::ConsumerBeginReadDataImplNoLock( - UserPointer<const void*> buffer, - UserPointer<uint32_t> buffer_num_bytes, - uint32_t min_num_bytes_to_read) { - size_t max_num_bytes_to_read = GetMaxNumBytesToReadNoLock(); - if (min_num_bytes_to_read > max_num_bytes_to_read) { - // Don't return "should wait" since you can't wait for a specified amount of - // data. - return producer_open_no_lock() ? MOJO_RESULT_OUT_OF_RANGE - : MOJO_RESULT_FAILED_PRECONDITION; - } - - // Don't go into a two-phase read if there's no data. - if (max_num_bytes_to_read == 0) { - return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT - : MOJO_RESULT_FAILED_PRECONDITION; - } - - buffer.Put(buffer_.get() + start_index_); - buffer_num_bytes.Put(static_cast<uint32_t>(max_num_bytes_to_read)); - set_consumer_two_phase_max_num_bytes_read_no_lock( - static_cast<uint32_t>(max_num_bytes_to_read)); - return MOJO_RESULT_OK; -} - -MojoResult LocalDataPipe::ConsumerEndReadDataImplNoLock( - uint32_t num_bytes_read) { - DCHECK_LE(num_bytes_read, consumer_two_phase_max_num_bytes_read_no_lock()); - DCHECK_LE(start_index_ + num_bytes_read, capacity_num_bytes()); - MarkDataAsConsumedNoLock(num_bytes_read); - set_consumer_two_phase_max_num_bytes_read_no_lock(0); - return MOJO_RESULT_OK; -} - -HandleSignalsState LocalDataPipe::ConsumerGetHandleSignalsStateImplNoLock() - const { - HandleSignalsState rv; - if (current_num_bytes_ > 0) { - if (!consumer_in_two_phase_read_no_lock()) - rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_READABLE; - rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; - } 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; -} - -void LocalDataPipe::EnsureBufferNoLock() { - DCHECK(producer_open_no_lock()); - if (buffer_) - return; - buffer_.reset(static_cast<char*>( - base::AlignedAlloc(capacity_num_bytes(), - GetConfiguration().data_pipe_buffer_alignment_bytes))); -} - -void LocalDataPipe::DestroyBufferNoLock() { -#ifndef NDEBUG - // Scribble on the buffer to help detect use-after-frees. (This also helps the - // unit test detect certain bugs without needing ASAN or similar.) - if (buffer_) - memset(buffer_.get(), 0xcd, capacity_num_bytes()); -#endif - buffer_.reset(); -} - -size_t LocalDataPipe::GetMaxNumBytesToWriteNoLock() { - size_t next_index = start_index_ + current_num_bytes_; - if (next_index >= capacity_num_bytes()) { - next_index %= capacity_num_bytes(); - DCHECK_GE(start_index_, next_index); - DCHECK_EQ(start_index_ - next_index, - capacity_num_bytes() - current_num_bytes_); - return start_index_ - next_index; - } - return capacity_num_bytes() - next_index; -} - -size_t LocalDataPipe::GetMaxNumBytesToReadNoLock() { - if (start_index_ + current_num_bytes_ > capacity_num_bytes()) - return capacity_num_bytes() - start_index_; - return current_num_bytes_; -} - -void LocalDataPipe::MarkDataAsConsumedNoLock(size_t num_bytes) { - DCHECK_LE(num_bytes, current_num_bytes_); - start_index_ += num_bytes; - start_index_ %= capacity_num_bytes(); - current_num_bytes_ -= num_bytes; -} - -} // namespace system -} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/local_data_pipe.h b/third_party/mojo/src/mojo/edk/system/local_data_pipe.h deleted file mode 100644 index abe3a462..0000000 --- a/third_party/mojo/src/mojo/edk/system/local_data_pipe.h +++ /dev/null
@@ -1,89 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_EDK_SYSTEM_LOCAL_DATA_PIPE_H_ -#define MOJO_EDK_SYSTEM_LOCAL_DATA_PIPE_H_ - -#include "base/macros.h" -#include "base/memory/aligned_memory.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "mojo/edk/system/data_pipe.h" -#include "mojo/edk/system/system_impl_export.h" - -namespace mojo { -namespace system { - -// |LocalDataPipe| is a subclass that "implements" |DataPipe| for data pipes -// whose producer and consumer are both local. This class is thread-safe (with -// protection provided by |DataPipe|'s |lock_|. -class MOJO_SYSTEM_IMPL_EXPORT LocalDataPipe : public DataPipe { - public: - // |validated_options| should be the output of |DataPipe::ValidateOptions()|. - // In particular: |struct_size| is ignored (so |validated_options| must be the - // current version of the struct) and |capacity_num_bytes| must be nonzero. - explicit LocalDataPipe(const MojoCreateDataPipeOptions& validated_options); - - private: - friend class base::RefCountedThreadSafe<LocalDataPipe>; - ~LocalDataPipe() override; - - // |DataPipe| implementation: - void ProducerCloseImplNoLock() override; - MojoResult ProducerWriteDataImplNoLock( - UserPointer<const void> elements, - UserPointer<uint32_t> num_bytes, - uint32_t max_num_bytes_to_write, - uint32_t min_num_bytes_to_write) override; - MojoResult ProducerBeginWriteDataImplNoLock( - UserPointer<void*> buffer, - UserPointer<uint32_t> buffer_num_bytes, - uint32_t min_num_bytes_to_write) override; - MojoResult ProducerEndWriteDataImplNoLock( - uint32_t num_bytes_written) override; - HandleSignalsState ProducerGetHandleSignalsStateImplNoLock() const override; - void ConsumerCloseImplNoLock() override; - MojoResult ConsumerReadDataImplNoLock(UserPointer<void> elements, - UserPointer<uint32_t> num_bytes, - uint32_t max_num_bytes_to_read, - uint32_t min_num_bytes_to_read, - bool peek) override; - MojoResult ConsumerDiscardDataImplNoLock( - UserPointer<uint32_t> num_bytes, - uint32_t max_num_bytes_to_discard, - uint32_t min_num_bytes_to_discard) override; - MojoResult ConsumerQueryDataImplNoLock( - UserPointer<uint32_t> num_bytes) override; - MojoResult ConsumerBeginReadDataImplNoLock( - UserPointer<const void*> buffer, - UserPointer<uint32_t> buffer_num_bytes, - uint32_t min_num_bytes_to_read) override; - MojoResult ConsumerEndReadDataImplNoLock(uint32_t num_bytes_read) override; - HandleSignalsState ConsumerGetHandleSignalsStateImplNoLock() const override; - - void EnsureBufferNoLock(); - void DestroyBufferNoLock(); - - // Get the maximum (single) write/read size right now (in number of elements); - // result fits in a |uint32_t|. - size_t GetMaxNumBytesToWriteNoLock(); - size_t GetMaxNumBytesToReadNoLock(); - - // Marks the given number of bytes as consumed/discarded. |num_bytes| must be - // greater than |current_num_bytes_|. - void MarkDataAsConsumedNoLock(size_t num_bytes); - - // The members below are protected by |DataPipe|'s |lock_|: - scoped_ptr<char, base::AlignedFreeDeleter> buffer_; - // Circular buffer. - size_t start_index_; - size_t current_num_bytes_; - - DISALLOW_COPY_AND_ASSIGN(LocalDataPipe); -}; - -} // namespace system -} // namespace mojo - -#endif // MOJO_EDK_SYSTEM_LOCAL_DATA_PIPE_H_
diff --git a/third_party/mojo/src/mojo/edk/system/local_data_pipe_impl.cc b/third_party/mojo/src/mojo/edk/system/local_data_pipe_impl.cc new file mode 100644 index 0000000..938ce68 --- /dev/null +++ b/third_party/mojo/src/mojo/edk/system/local_data_pipe_impl.cc
@@ -0,0 +1,445 @@ +// 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. + +// TODO(vtl): I currently potentially overflow in doing index calculations. +// E.g., |start_index_| and |current_num_bytes_| fit into a |uint32_t|, but +// their sum may not. This is bad and poses a security risk. (We're currently +// saved by the limit on capacity -- the maximum size of the buffer, checked in +// |DataPipe::ValidateOptions()|, is currently sufficiently small.) + +#include "mojo/edk/system/local_data_pipe_impl.h" + +#include <string.h> + +#include <algorithm> + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/edk/system/channel.h" +#include "mojo/edk/system/configuration.h" +#include "mojo/edk/system/data_pipe.h" +#include "mojo/edk/system/message_in_transit.h" +#include "mojo/edk/system/message_in_transit_queue.h" +#include "mojo/edk/system/remote_consumer_data_pipe_impl.h" +#include "mojo/edk/system/remote_producer_data_pipe_impl.h" + +namespace mojo { +namespace system { + +// Assert some things about some things defined in data_pipe_impl.h (don't make +// the assertions there, to avoid including message_in_transit.h). +static_assert(ALIGNOF(SerializedDataPipeConsumerDispatcher) == + MessageInTransit::kMessageAlignment, + "Wrong alignment"); +static_assert(sizeof(SerializedDataPipeConsumerDispatcher) % + MessageInTransit::kMessageAlignment == + 0, + "Wrong size"); + +LocalDataPipeImpl::LocalDataPipeImpl() + : start_index_(0), current_num_bytes_(0) { + // Note: |buffer_| is lazily allocated, since a common case will be that one + // of the handles is immediately passed off to another process. +} + +LocalDataPipeImpl::~LocalDataPipeImpl() { +} + +void LocalDataPipeImpl::ProducerClose() { + // If the consumer is still open and we still have data, we have to keep the + // buffer around. Currently, we won't free it even if it empties later. (We + // could do this -- requiring a check on every read -- but that seems to be + // optimizing for the uncommon case.) + if (!consumer_open() || !current_num_bytes_) { + // Note: There can only be a two-phase *read* (by the consumer) if we still + // have data. + DCHECK(!consumer_in_two_phase_read()); + DestroyBuffer(); + } +} + +MojoResult LocalDataPipeImpl::ProducerWriteData( + UserPointer<const void> elements, + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_write, + uint32_t min_num_bytes_to_write) { + DCHECK_EQ(max_num_bytes_to_write % element_num_bytes(), 0u); + DCHECK_EQ(min_num_bytes_to_write % element_num_bytes(), 0u); + DCHECK_GT(max_num_bytes_to_write, 0u); + DCHECK_GE(max_num_bytes_to_write, min_num_bytes_to_write); + DCHECK(consumer_open()); + + if (min_num_bytes_to_write > capacity_num_bytes() - current_num_bytes_) { + // Don't return "should wait" since you can't wait for a specified amount + // of data. + return MOJO_RESULT_OUT_OF_RANGE; + } + + size_t num_bytes_to_write = + std::min(static_cast<size_t>(max_num_bytes_to_write), + capacity_num_bytes() - current_num_bytes_); + if (num_bytes_to_write == 0) + return MOJO_RESULT_SHOULD_WAIT; + + // The amount we can write in our first copy. + size_t num_bytes_to_write_first = + std::min(num_bytes_to_write, GetMaxNumBytesToWrite()); + // Do the first (and possibly only) copy. + size_t first_write_index = + (start_index_ + current_num_bytes_) % capacity_num_bytes(); + EnsureBuffer(); + elements.GetArray(buffer_.get() + first_write_index, + num_bytes_to_write_first); + + if (num_bytes_to_write_first < num_bytes_to_write) { + // The "second write index" is zero. + elements.At(num_bytes_to_write_first) + .GetArray(buffer_.get(), num_bytes_to_write - num_bytes_to_write_first); + } + + current_num_bytes_ += num_bytes_to_write; + DCHECK_LE(current_num_bytes_, capacity_num_bytes()); + num_bytes.Put(static_cast<uint32_t>(num_bytes_to_write)); + return MOJO_RESULT_OK; +} + +MojoResult LocalDataPipeImpl::ProducerBeginWriteData( + UserPointer<void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, + uint32_t min_num_bytes_to_write) { + DCHECK(consumer_open()); + + // The index we need to start writing at. + size_t write_index = + (start_index_ + current_num_bytes_) % capacity_num_bytes(); + + size_t max_num_bytes_to_write = GetMaxNumBytesToWrite(); + if (min_num_bytes_to_write > max_num_bytes_to_write) { + // Don't return "should wait" since you can't wait for a specified amount + // of data. + return MOJO_RESULT_OUT_OF_RANGE; + } + + // Don't go into a two-phase write if there's no room. + if (max_num_bytes_to_write == 0) + return MOJO_RESULT_SHOULD_WAIT; + + EnsureBuffer(); + buffer.Put(buffer_.get() + write_index); + buffer_num_bytes.Put(static_cast<uint32_t>(max_num_bytes_to_write)); + set_producer_two_phase_max_num_bytes_written( + static_cast<uint32_t>(max_num_bytes_to_write)); + return MOJO_RESULT_OK; +} + +MojoResult LocalDataPipeImpl::ProducerEndWriteData(uint32_t num_bytes_written) { + DCHECK_LE(num_bytes_written, producer_two_phase_max_num_bytes_written()); + DCHECK_EQ(num_bytes_written % element_num_bytes(), 0u); + current_num_bytes_ += num_bytes_written; + DCHECK_LE(current_num_bytes_, capacity_num_bytes()); + set_producer_two_phase_max_num_bytes_written(0); + return MOJO_RESULT_OK; +} + +HandleSignalsState LocalDataPipeImpl::ProducerGetHandleSignalsState() const { + HandleSignalsState rv; + if (consumer_open()) { + if (current_num_bytes_ < capacity_num_bytes() && + !producer_in_two_phase_write()) + 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; +} + +void LocalDataPipeImpl::ProducerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) { + *max_size = sizeof(SerializedDataPipeProducerDispatcher) + + channel->GetSerializedEndpointSize(); + *max_platform_handles = 0; +} + +bool LocalDataPipeImpl::ProducerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) { + SerializedDataPipeProducerDispatcher* s = + static_cast<SerializedDataPipeProducerDispatcher*>(destination); + s->validated_options = validated_options(); + void* destination_for_endpoint = static_cast<char*>(destination) + + sizeof(SerializedDataPipeProducerDispatcher); + + if (!consumer_open()) { + // Case 1: The consumer is closed. + s->consumer_num_bytes = static_cast<size_t>(-1); + *actual_size = sizeof(SerializedDataPipeProducerDispatcher); + return true; + } + + // Case 2: The consumer isn't closed. We'll replace ourselves with a + // |RemoteProducerDataPipeImpl|. + + s->consumer_num_bytes = current_num_bytes_; + // Note: We don't use |port|. + scoped_refptr<ChannelEndpoint> channel_endpoint = + channel->SerializeEndpointWithLocalPeer(destination_for_endpoint, nullptr, + owner(), 0); + // Note: Keep |*this| alive until the end of this method, to make things + // slightly easier on ourselves. + scoped_ptr<DataPipeImpl> self(owner()->ReplaceImplNoLock(make_scoped_ptr( + new RemoteProducerDataPipeImpl(channel_endpoint.get(), buffer_.Pass(), + start_index_, current_num_bytes_)))); + + *actual_size = sizeof(SerializedDataPipeProducerDispatcher) + + channel->GetSerializedEndpointSize(); + return true; +} + +void LocalDataPipeImpl::ConsumerClose() { + // If the producer is around and in a two-phase write, we have to keep the + // buffer around. (We then don't free it until the producer is closed. This + // could be rectified, but again seems like optimizing for the uncommon case.) + if (!producer_open() || !producer_in_two_phase_write()) + DestroyBuffer(); + current_num_bytes_ = 0; +} + +MojoResult LocalDataPipeImpl::ConsumerReadData(UserPointer<void> elements, + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_read, + uint32_t min_num_bytes_to_read, + bool peek) { + DCHECK_EQ(max_num_bytes_to_read % element_num_bytes(), 0u); + DCHECK_EQ(min_num_bytes_to_read % element_num_bytes(), 0u); + DCHECK_GT(max_num_bytes_to_read, 0u); + + if (min_num_bytes_to_read > current_num_bytes_) { + // Don't return "should wait" since you can't wait for a specified amount of + // data. + return producer_open() ? MOJO_RESULT_OUT_OF_RANGE + : MOJO_RESULT_FAILED_PRECONDITION; + } + + size_t num_bytes_to_read = + std::min(static_cast<size_t>(max_num_bytes_to_read), current_num_bytes_); + if (num_bytes_to_read == 0) { + return producer_open() ? MOJO_RESULT_SHOULD_WAIT + : MOJO_RESULT_FAILED_PRECONDITION; + } + + // The amount we can read in our first copy. + size_t num_bytes_to_read_first = + std::min(num_bytes_to_read, GetMaxNumBytesToRead()); + elements.PutArray(buffer_.get() + start_index_, num_bytes_to_read_first); + + if (num_bytes_to_read_first < num_bytes_to_read) { + // The "second read index" is zero. + elements.At(num_bytes_to_read_first) + .PutArray(buffer_.get(), num_bytes_to_read - num_bytes_to_read_first); + } + + if (!peek) + MarkDataAsConsumed(num_bytes_to_read); + num_bytes.Put(static_cast<uint32_t>(num_bytes_to_read)); + return MOJO_RESULT_OK; +} + +MojoResult LocalDataPipeImpl::ConsumerDiscardData( + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_discard, + uint32_t min_num_bytes_to_discard) { + DCHECK_EQ(max_num_bytes_to_discard % element_num_bytes(), 0u); + DCHECK_EQ(min_num_bytes_to_discard % element_num_bytes(), 0u); + DCHECK_GT(max_num_bytes_to_discard, 0u); + + if (min_num_bytes_to_discard > current_num_bytes_) { + // Don't return "should wait" since you can't wait for a specified amount of + // data. + return producer_open() ? MOJO_RESULT_OUT_OF_RANGE + : MOJO_RESULT_FAILED_PRECONDITION; + } + + // Be consistent with other operations; error if no data available. + if (current_num_bytes_ == 0) { + return producer_open() ? MOJO_RESULT_SHOULD_WAIT + : MOJO_RESULT_FAILED_PRECONDITION; + } + + size_t num_bytes_to_discard = std::min( + static_cast<size_t>(max_num_bytes_to_discard), current_num_bytes_); + MarkDataAsConsumed(num_bytes_to_discard); + num_bytes.Put(static_cast<uint32_t>(num_bytes_to_discard)); + return MOJO_RESULT_OK; +} + +MojoResult LocalDataPipeImpl::ConsumerQueryData( + UserPointer<uint32_t> num_bytes) { + // Note: This cast is safe, since the capacity fits into a |uint32_t|. + num_bytes.Put(static_cast<uint32_t>(current_num_bytes_)); + return MOJO_RESULT_OK; +} + +MojoResult LocalDataPipeImpl::ConsumerBeginReadData( + UserPointer<const void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, + uint32_t min_num_bytes_to_read) { + size_t max_num_bytes_to_read = GetMaxNumBytesToRead(); + if (min_num_bytes_to_read > max_num_bytes_to_read) { + // Don't return "should wait" since you can't wait for a specified amount of + // data. + return producer_open() ? MOJO_RESULT_OUT_OF_RANGE + : MOJO_RESULT_FAILED_PRECONDITION; + } + + // Don't go into a two-phase read if there's no data. + if (max_num_bytes_to_read == 0) { + return producer_open() ? MOJO_RESULT_SHOULD_WAIT + : MOJO_RESULT_FAILED_PRECONDITION; + } + + buffer.Put(buffer_.get() + start_index_); + buffer_num_bytes.Put(static_cast<uint32_t>(max_num_bytes_to_read)); + set_consumer_two_phase_max_num_bytes_read( + static_cast<uint32_t>(max_num_bytes_to_read)); + return MOJO_RESULT_OK; +} + +MojoResult LocalDataPipeImpl::ConsumerEndReadData(uint32_t num_bytes_read) { + DCHECK_LE(num_bytes_read, consumer_two_phase_max_num_bytes_read()); + DCHECK_EQ(num_bytes_read % element_num_bytes(), 0u); + DCHECK_LE(start_index_ + num_bytes_read, capacity_num_bytes()); + MarkDataAsConsumed(num_bytes_read); + set_consumer_two_phase_max_num_bytes_read(0); + return MOJO_RESULT_OK; +} + +HandleSignalsState LocalDataPipeImpl::ConsumerGetHandleSignalsState() const { + HandleSignalsState rv; + if (current_num_bytes_ > 0) { + if (!consumer_in_two_phase_read()) + rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_READABLE; + rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; + } else if (producer_open()) { + rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; + } + if (!producer_open()) + rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; + rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; + return rv; +} + +void LocalDataPipeImpl::ConsumerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) { + *max_size = sizeof(SerializedDataPipeConsumerDispatcher) + + channel->GetSerializedEndpointSize(); + *max_platform_handles = 0; +} + +bool LocalDataPipeImpl::ConsumerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) { + SerializedDataPipeConsumerDispatcher* s = + static_cast<SerializedDataPipeConsumerDispatcher*>(destination); + s->validated_options = validated_options(); + void* destination_for_endpoint = static_cast<char*>(destination) + + sizeof(SerializedDataPipeConsumerDispatcher); + + size_t old_num_bytes = current_num_bytes_; + MessageInTransitQueue message_queue; + ConvertDataToMessages(buffer_.get(), &start_index_, ¤t_num_bytes_, + &message_queue); + start_index_ = 0; + current_num_bytes_ = 0; + + if (!producer_open()) { + // Case 1: The producer is closed. + channel->SerializeEndpointWithClosedPeer(destination_for_endpoint, + &message_queue); + *actual_size = sizeof(SerializedDataPipeConsumerDispatcher) + + channel->GetSerializedEndpointSize(); + return true; + } + + // Case 2: The producer isn't closed. We'll replace ourselves with a + // |RemoteConsumerDataPipeImpl|. + + // Note: We don't use |port|. + scoped_refptr<ChannelEndpoint> channel_endpoint = + channel->SerializeEndpointWithLocalPeer(destination_for_endpoint, + &message_queue, owner(), 0); + // Note: Keep |*this| alive until the end of this method, to make things + // slightly easier on ourselves. + scoped_ptr<DataPipeImpl> self(owner()->ReplaceImplNoLock(make_scoped_ptr( + new RemoteConsumerDataPipeImpl(channel_endpoint.get(), old_num_bytes)))); + + *actual_size = sizeof(SerializedDataPipeConsumerDispatcher) + + channel->GetSerializedEndpointSize(); + return true; +} + +bool LocalDataPipeImpl::OnReadMessage(unsigned /*port*/, + MessageInTransit* /*message*/) { + NOTREACHED(); + return false; +} + +void LocalDataPipeImpl::OnDetachFromChannel(unsigned /*port*/) { + NOTREACHED(); +} + +void LocalDataPipeImpl::EnsureBuffer() { + DCHECK(producer_open()); + if (buffer_) + return; + buffer_.reset(static_cast<char*>( + base::AlignedAlloc(capacity_num_bytes(), + GetConfiguration().data_pipe_buffer_alignment_bytes))); +} + +void LocalDataPipeImpl::DestroyBuffer() { +#ifndef NDEBUG + // Scribble on the buffer to help detect use-after-frees. (This also helps the + // unit test detect certain bugs without needing ASAN or similar.) + if (buffer_) + memset(buffer_.get(), 0xcd, capacity_num_bytes()); +#endif + buffer_.reset(); +} + +size_t LocalDataPipeImpl::GetMaxNumBytesToWrite() { + size_t next_index = start_index_ + current_num_bytes_; + if (next_index >= capacity_num_bytes()) { + next_index %= capacity_num_bytes(); + DCHECK_GE(start_index_, next_index); + DCHECK_EQ(start_index_ - next_index, + capacity_num_bytes() - current_num_bytes_); + return start_index_ - next_index; + } + return capacity_num_bytes() - next_index; +} + +size_t LocalDataPipeImpl::GetMaxNumBytesToRead() { + if (start_index_ + current_num_bytes_ > capacity_num_bytes()) + return capacity_num_bytes() - start_index_; + return current_num_bytes_; +} + +void LocalDataPipeImpl::MarkDataAsConsumed(size_t num_bytes) { + DCHECK_LE(num_bytes, current_num_bytes_); + start_index_ += num_bytes; + start_index_ %= capacity_num_bytes(); + current_num_bytes_ -= num_bytes; +} + +} // namespace system +} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/local_data_pipe_impl.h b/third_party/mojo/src/mojo/edk/system/local_data_pipe_impl.h new file mode 100644 index 0000000..48233f2 --- /dev/null +++ b/third_party/mojo/src/mojo/edk/system/local_data_pipe_impl.h
@@ -0,0 +1,96 @@ +// 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 MOJO_EDK_SYSTEM_LOCAL_DATA_PIPE_IMPL_H_ +#define MOJO_EDK_SYSTEM_LOCAL_DATA_PIPE_IMPL_H_ + +#include "base/macros.h" +#include "base/memory/aligned_memory.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/edk/system/data_pipe_impl.h" +#include "mojo/edk/system/system_impl_export.h" + +namespace mojo { +namespace system { + +class MessageInTransitQueue; + +// |LocalDataPipeImpl| is a subclass that "implements" |DataPipe| for data pipes +// whose producer and consumer are both local. See |DataPipeImpl| for more +// details. +class MOJO_SYSTEM_IMPL_EXPORT LocalDataPipeImpl : public DataPipeImpl { + public: + LocalDataPipeImpl(); + ~LocalDataPipeImpl() override; + + private: + // |DataPipeImpl| implementation: + void ProducerClose() override; + MojoResult ProducerWriteData(UserPointer<const void> elements, + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_write, + uint32_t min_num_bytes_to_write) override; + MojoResult ProducerBeginWriteData(UserPointer<void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, + uint32_t min_num_bytes_to_write) override; + MojoResult ProducerEndWriteData(uint32_t num_bytes_written) override; + HandleSignalsState ProducerGetHandleSignalsState() const override; + void ProducerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) override; + bool ProducerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) override; + void ConsumerClose() override; + MojoResult ConsumerReadData(UserPointer<void> elements, + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_read, + uint32_t min_num_bytes_to_read, + bool peek) override; + MojoResult ConsumerDiscardData(UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_discard, + uint32_t min_num_bytes_to_discard) override; + MojoResult ConsumerQueryData(UserPointer<uint32_t> num_bytes) override; + MojoResult ConsumerBeginReadData(UserPointer<const void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, + uint32_t min_num_bytes_to_read) override; + MojoResult ConsumerEndReadData(uint32_t num_bytes_read) override; + HandleSignalsState ConsumerGetHandleSignalsState() const override; + void ConsumerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) override; + bool ConsumerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) override; + bool OnReadMessage(unsigned port, MessageInTransit* message) override; + void OnDetachFromChannel(unsigned port) override; + + void EnsureBuffer(); + void DestroyBuffer(); + + // Get the maximum (single) write/read size right now (in number of elements); + // result fits in a |uint32_t|. + size_t GetMaxNumBytesToWrite(); + size_t GetMaxNumBytesToRead(); + + // Marks the given number of bytes as consumed/discarded. |num_bytes| must be + // no greater than |current_num_bytes_|. + void MarkDataAsConsumed(size_t num_bytes); + + scoped_ptr<char, base::AlignedFreeDeleter> buffer_; + // Circular buffer. + size_t start_index_; + size_t current_num_bytes_; + + DISALLOW_COPY_AND_ASSIGN(LocalDataPipeImpl); +}; + +} // namespace system +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_LOCAL_DATA_PIPE_IMPL_H_
diff --git a/third_party/mojo/src/mojo/edk/system/local_data_pipe_impl_unittest.cc b/third_party/mojo/src/mojo/edk/system/local_data_pipe_impl_unittest.cc new file mode 100644 index 0000000..7a0bb19 --- /dev/null +++ b/third_party/mojo/src/mojo/edk/system/local_data_pipe_impl_unittest.cc
@@ -0,0 +1,491 @@ +// 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 "mojo/edk/system/local_data_pipe_impl.h" + +#include <string.h> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "mojo/edk/system/data_pipe.h" +#include "mojo/edk/system/waiter.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace system { +namespace { + +const uint32_t kSizeOfOptions = + static_cast<uint32_t>(sizeof(MojoCreateDataPipeOptions)); + +// Validate options. +TEST(LocalDataPipeImplTest, Creation) { + // Create using default options. + { + // Get default options. + MojoCreateDataPipeOptions default_options = {0}; + EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( + NullUserPointer(), &default_options)); + scoped_refptr<DataPipe> dp(DataPipe::CreateLocal(default_options)); + dp->ProducerClose(); + dp->ConsumerClose(); + } + + // Create using non-default options. + { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + 1, // |element_num_bytes|. + 1000 // |capacity_num_bytes|. + }; + MojoCreateDataPipeOptions validated_options = {0}; + EXPECT_EQ(MOJO_RESULT_OK, + DataPipe::ValidateCreateOptions(MakeUserPointer(&options), + &validated_options)); + scoped_refptr<DataPipe> dp(DataPipe::CreateLocal(validated_options)); + dp->ProducerClose(); + dp->ConsumerClose(); + } + { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + 4, // |element_num_bytes|. + 4000 // |capacity_num_bytes|. + }; + MojoCreateDataPipeOptions validated_options = {0}; + EXPECT_EQ(MOJO_RESULT_OK, + DataPipe::ValidateCreateOptions(MakeUserPointer(&options), + &validated_options)); + scoped_refptr<DataPipe> dp(DataPipe::CreateLocal(validated_options)); + dp->ProducerClose(); + dp->ConsumerClose(); + } + // Default capacity. + { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + 100, // |element_num_bytes|. + 0 // |capacity_num_bytes|. + }; + MojoCreateDataPipeOptions validated_options = {0}; + EXPECT_EQ(MOJO_RESULT_OK, + DataPipe::ValidateCreateOptions(MakeUserPointer(&options), + &validated_options)); + scoped_refptr<DataPipe> dp(DataPipe::CreateLocal(validated_options)); + dp->ProducerClose(); + dp->ConsumerClose(); + } +} + +// Tests that |ProducerWriteData()| and |ConsumerReadData()| writes and reads, +// respectively, as much as possible, even if it has to "wrap around" the +// internal circular buffer. (Note that the two-phase write and read do not do +// this.) +TEST(LocalDataPipeImplTest, WrapAround) { + unsigned char test_data[1000]; + for (size_t i = 0; i < arraysize(test_data); i++) + test_data[i] = static_cast<unsigned char>(i); + + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + 1u, // |element_num_bytes|. + 100u // |capacity_num_bytes|. + }; + MojoCreateDataPipeOptions validated_options = {0}; + EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( + MakeUserPointer(&options), &validated_options)); + // This test won't be valid if |ValidateCreateOptions()| decides to give the + // pipe more space. + ASSERT_EQ(100u, validated_options.capacity_num_bytes); + + scoped_refptr<DataPipe> dp(DataPipe::CreateLocal(validated_options)); + + // Write 20 bytes. + uint32_t num_bytes = 20u; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerWriteData(UserPointer<const void>(&test_data[0]), + MakeUserPointer(&num_bytes), false)); + EXPECT_EQ(20u, num_bytes); + + // Read 10 bytes. + unsigned char read_buffer[1000] = {0}; + num_bytes = 10u; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ConsumerReadData(UserPointer<void>(read_buffer), + MakeUserPointer(&num_bytes), false, false)); + EXPECT_EQ(10u, num_bytes); + EXPECT_EQ(0, memcmp(read_buffer, &test_data[0], 10u)); + + // Check that a two-phase write can now only write (at most) 80 bytes. (This + // checks an implementation detail; this behavior is not guaranteed, but we + // need it for this test.) + void* write_buffer_ptr = nullptr; + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerBeginWriteData(MakeUserPointer(&write_buffer_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(write_buffer_ptr); + EXPECT_EQ(80u, num_bytes); + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(0u)); + + // Write as much data as we can (using |ProducerWriteData()|). We should write + // 90 bytes. + num_bytes = 200u; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerWriteData(UserPointer<const void>(&test_data[20]), + MakeUserPointer(&num_bytes), false)); + EXPECT_EQ(90u, num_bytes); + + // Check that a two-phase read can now only read (at most) 90 bytes. (This + // checks an implementation detail; this behavior is not guaranteed, but we + // need it for this test.) + const void* read_buffer_ptr = nullptr; + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(read_buffer_ptr); + EXPECT_EQ(90u, num_bytes); + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(0u)); + + // Read as much as possible (using |ConsumerReadData()|). We should read 100 + // bytes. + num_bytes = + static_cast<uint32_t>(arraysize(read_buffer) * sizeof(read_buffer[0])); + memset(read_buffer, 0, num_bytes); + EXPECT_EQ(MOJO_RESULT_OK, + dp->ConsumerReadData(UserPointer<void>(read_buffer), + MakeUserPointer(&num_bytes), false, false)); + EXPECT_EQ(100u, num_bytes); + EXPECT_EQ(0, memcmp(read_buffer, &test_data[10], 100u)); + + dp->ProducerClose(); + dp->ConsumerClose(); +} + +// Tests the behavior of closing the producer or consumer with respect to +// writes and reads (simple and two-phase). +TEST(LocalDataPipeImplTest, CloseWriteRead) { + const char kTestData[] = "hello world"; + const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kTestData)); + + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + 1u, // |element_num_bytes|. + 1000u // |capacity_num_bytes|. + }; + MojoCreateDataPipeOptions validated_options = {0}; + EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( + MakeUserPointer(&options), &validated_options)); + + // Close producer first, then consumer. + { + scoped_refptr<DataPipe> dp(DataPipe::CreateLocal(validated_options)); + + // Write some data, so we'll have something to read. + uint32_t num_bytes = kTestDataSize; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerWriteData(UserPointer<const void>(kTestData), + MakeUserPointer(&num_bytes), false)); + EXPECT_EQ(kTestDataSize, num_bytes); + + // Write it again, so we'll have something left over. + num_bytes = kTestDataSize; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerWriteData(UserPointer<const void>(kTestData), + MakeUserPointer(&num_bytes), false)); + EXPECT_EQ(kTestDataSize, num_bytes); + + // Start two-phase write. + void* write_buffer_ptr = nullptr; + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerBeginWriteData(MakeUserPointer(&write_buffer_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(write_buffer_ptr); + EXPECT_GT(num_bytes, 0u); + + // Start two-phase read. + const void* read_buffer_ptr = nullptr; + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(read_buffer_ptr); + EXPECT_EQ(2u * kTestDataSize, num_bytes); + + // Close the producer. + dp->ProducerClose(); + + // The consumer can finish its two-phase read. + EXPECT_EQ(0, memcmp(read_buffer_ptr, kTestData, kTestDataSize)); + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(kTestDataSize)); + + // And start another. + read_buffer_ptr = nullptr; + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(read_buffer_ptr); + EXPECT_EQ(kTestDataSize, num_bytes); + + // Close the consumer, which cancels the two-phase read. + dp->ConsumerClose(); + } + + // Close consumer first, then producer. + { + scoped_refptr<DataPipe> dp(DataPipe::CreateLocal(validated_options)); + + // Write some data, so we'll have something to read. + uint32_t num_bytes = kTestDataSize; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerWriteData(UserPointer<const void>(kTestData), + MakeUserPointer(&num_bytes), false)); + EXPECT_EQ(kTestDataSize, num_bytes); + + // Start two-phase write. + void* write_buffer_ptr = nullptr; + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerBeginWriteData(MakeUserPointer(&write_buffer_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(write_buffer_ptr); + ASSERT_GT(num_bytes, kTestDataSize); + + // Start two-phase read. + const void* read_buffer_ptr = nullptr; + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(read_buffer_ptr); + EXPECT_EQ(kTestDataSize, num_bytes); + + // Close the consumer. + dp->ConsumerClose(); + + // Actually write some data. (Note: Premature freeing of the buffer would + // probably only be detected under ASAN or similar.) + memcpy(write_buffer_ptr, kTestData, kTestDataSize); + // Note: Even though the consumer has been closed, ending the two-phase + // write will report success. + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(kTestDataSize)); + + // But trying to write should result in failure. + num_bytes = kTestDataSize; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + dp->ProducerWriteData(UserPointer<const void>(kTestData), + MakeUserPointer(&num_bytes), false)); + + // As will trying to start another two-phase write. + write_buffer_ptr = nullptr; + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + dp->ProducerBeginWriteData(MakeUserPointer(&write_buffer_ptr), + MakeUserPointer(&num_bytes), false)); + + dp->ProducerClose(); + } + + // Test closing the consumer first, then the producer, with an active + // two-phase write. + { + scoped_refptr<DataPipe> dp(DataPipe::CreateLocal(validated_options)); + + // Start two-phase write. + void* write_buffer_ptr = nullptr; + uint32_t num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerBeginWriteData(MakeUserPointer(&write_buffer_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_TRUE(write_buffer_ptr); + ASSERT_GT(num_bytes, kTestDataSize); + + dp->ConsumerClose(); + dp->ProducerClose(); + } + + // Test closing the producer and then trying to read (with no data). + { + scoped_refptr<DataPipe> dp(DataPipe::CreateLocal(validated_options)); + + // Write some data, so we'll have something to read. + uint32_t num_bytes = kTestDataSize; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerWriteData(UserPointer<const void>(kTestData), + MakeUserPointer(&num_bytes), false)); + EXPECT_EQ(kTestDataSize, num_bytes); + + // Close the producer. + dp->ProducerClose(); + + // Peek that data. + char buffer[1000]; + num_bytes = static_cast<uint32_t>(sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_OK, + dp->ConsumerReadData(UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), false, true)); + EXPECT_EQ(kTestDataSize, num_bytes); + EXPECT_EQ(0, memcmp(buffer, kTestData, kTestDataSize)); + + // Read that data. + memset(buffer, 0, 1000); + num_bytes = static_cast<uint32_t>(sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_OK, + dp->ConsumerReadData(UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), false, false)); + EXPECT_EQ(kTestDataSize, num_bytes); + EXPECT_EQ(0, memcmp(buffer, kTestData, kTestDataSize)); + + // A second read should fail. + num_bytes = static_cast<uint32_t>(sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + dp->ConsumerReadData(UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), false, false)); + + // A two-phase read should also fail. + const void* read_buffer_ptr = nullptr; + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer_ptr), + MakeUserPointer(&num_bytes), false)); + + // Ditto for discard. + num_bytes = 10u; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + dp->ConsumerDiscardData(MakeUserPointer(&num_bytes), false)); + + dp->ConsumerClose(); + } +} + +TEST(LocalDataPipeImplTest, TwoPhaseMoreInvalidArguments) { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 10 * sizeof(int32_t) // |capacity_num_bytes|. + }; + MojoCreateDataPipeOptions validated_options = {0}; + EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( + MakeUserPointer(&options), &validated_options)); + + scoped_refptr<DataPipe> dp(DataPipe::CreateLocal(validated_options)); + + // No data. + uint32_t num_bytes = 1000u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(0u, num_bytes); + + // Try "ending" a two-phase write when one isn't active. + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + dp->ProducerEndWriteData(1u * sizeof(int32_t))); + + // Still no data. + num_bytes = 1000u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(0u, num_bytes); + + // Try ending a two-phase write with an invalid amount (too much). + num_bytes = 0u; + void* write_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + dp->ProducerEndWriteData(num_bytes + + static_cast<uint32_t>(sizeof(int32_t)))); + + // But the two-phase write still ended. + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, dp->ProducerEndWriteData(0u)); + + // Still no data. + num_bytes = 1000u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(0u, num_bytes); + + // Try ending a two-phase write with an invalid amount (not a multiple of the + // element size). + num_bytes = 0u; + write_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_GE(num_bytes, 1u); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, dp->ProducerEndWriteData(1u)); + + // But the two-phase write still ended. + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, dp->ProducerEndWriteData(0u)); + + // Still no data. + num_bytes = 1000u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(0u, num_bytes); + + // Now write some data, so we'll be able to try reading. + int32_t element = 123; + num_bytes = 1u * sizeof(int32_t); + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerWriteData(UserPointer<const void>(&element), + MakeUserPointer(&num_bytes), false)); + + // One element available. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(1u * sizeof(int32_t), num_bytes); + + // Try "ending" a two-phase read when one isn't active. + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + dp->ConsumerEndReadData(1u * sizeof(int32_t))); + + // Still one element available. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(1u * sizeof(int32_t), num_bytes); + + // Try ending a two-phase read with an invalid amount (too much). + num_bytes = 0u; + const void* read_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + dp->ConsumerEndReadData(num_bytes + + static_cast<uint32_t>(sizeof(int32_t)))); + + // Still one element available. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(1u * sizeof(int32_t), num_bytes); + + // Try ending a two-phase read with an invalid amount (not a multiple of the + // element size). + num_bytes = 0u; + read_ptr = nullptr; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), + MakeUserPointer(&num_bytes), false)); + EXPECT_EQ(1u * sizeof(int32_t), num_bytes); + EXPECT_EQ(123, static_cast<const int32_t*>(read_ptr)[0]); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, dp->ConsumerEndReadData(1u)); + + // Still one element available. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); + EXPECT_EQ(1u * sizeof(int32_t), num_bytes); + + dp->ProducerClose(); + dp->ConsumerClose(); +} + +} // namespace +} // namespace system +} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/local_data_pipe_unittest.cc b/third_party/mojo/src/mojo/edk/system/local_data_pipe_unittest.cc deleted file mode 100644 index 1223a2ba..0000000 --- a/third_party/mojo/src/mojo/edk/system/local_data_pipe_unittest.cc +++ /dev/null
@@ -1,2071 +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. - -#include "mojo/edk/system/local_data_pipe.h" - -#include <string.h> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "mojo/edk/system/data_pipe.h" -#include "mojo/edk/system/waiter.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace system { -namespace { - -const uint32_t kSizeOfOptions = - static_cast<uint32_t>(sizeof(MojoCreateDataPipeOptions)); - -// Validate options. -TEST(LocalDataPipeTest, Creation) { - // Create using default options. - { - // Get default options. - MojoCreateDataPipeOptions default_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - NullUserPointer(), &default_options)); - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(default_options)); - dp->ProducerClose(); - dp->ConsumerClose(); - } - - // Create using non-default options. - { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1, // |element_num_bytes|. - 1000 // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, - DataPipe::ValidateCreateOptions(MakeUserPointer(&options), - &validated_options)); - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - dp->ProducerClose(); - dp->ConsumerClose(); - } - { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 4, // |element_num_bytes|. - 4000 // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, - DataPipe::ValidateCreateOptions(MakeUserPointer(&options), - &validated_options)); - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - dp->ProducerClose(); - dp->ConsumerClose(); - } - { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD, // |flags|. - 7, // |element_num_bytes|. - 7000000 // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, - DataPipe::ValidateCreateOptions(MakeUserPointer(&options), - &validated_options)); - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - dp->ProducerClose(); - dp->ConsumerClose(); - } - // Default capacity. - { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD, // |flags|. - 100, // |element_num_bytes|. - 0 // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, - DataPipe::ValidateCreateOptions(MakeUserPointer(&options), - &validated_options)); - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - dp->ProducerClose(); - dp->ConsumerClose(); - } -} - -TEST(LocalDataPipeTest, SimpleReadWrite) { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 1000 * sizeof(int32_t) // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - MakeUserPointer(&options), &validated_options)); - - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - - int32_t elements[10] = {0}; - uint32_t num_bytes = 0; - - // Try reading; nothing there yet. - num_bytes = static_cast<uint32_t>(arraysize(elements) * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, - dp->ConsumerReadData(UserPointer<void>(elements), - MakeUserPointer(&num_bytes), false, false)); - - // Query; nothing there yet. - num_bytes = 0; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(0u, num_bytes); - - // Discard; nothing there yet. - num_bytes = static_cast<uint32_t>(5u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, - dp->ConsumerDiscardData(MakeUserPointer(&num_bytes), false)); - - // Read with invalid |num_bytes|. - num_bytes = sizeof(elements[0]) + 1; - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - dp->ConsumerReadData(UserPointer<void>(elements), - MakeUserPointer(&num_bytes), false, false)); - - // Write two elements. - elements[0] = 123; - elements[1] = 456; - num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(elements), - MakeUserPointer(&num_bytes), false)); - // It should have written everything (even without "all or none"). - EXPECT_EQ(2u * sizeof(elements[0]), num_bytes); - - // Query. - num_bytes = 0; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(2 * sizeof(elements[0]), num_bytes); - - // Read one element. - elements[0] = -1; - elements[1] = -1; - num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(elements), - MakeUserPointer(&num_bytes), false, false)); - EXPECT_EQ(1u * sizeof(elements[0]), num_bytes); - EXPECT_EQ(123, elements[0]); - EXPECT_EQ(-1, elements[1]); - - // Query. - num_bytes = 0; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(1 * sizeof(elements[0]), num_bytes); - - // Peek one element. - elements[0] = -1; - elements[1] = -1; - num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(elements), - MakeUserPointer(&num_bytes), false, true)); - EXPECT_EQ(1u * sizeof(elements[0]), num_bytes); - EXPECT_EQ(456, elements[0]); - EXPECT_EQ(-1, elements[1]); - - // Query. Still has 1 element remaining. - num_bytes = 0; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(1 * sizeof(elements[0]), num_bytes); - - // Try to read two elements, with "all or none". - elements[0] = -1; - elements[1] = -1; - num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ConsumerReadData(UserPointer<void>(elements), - MakeUserPointer(&num_bytes), true, false)); - EXPECT_EQ(-1, elements[0]); - EXPECT_EQ(-1, elements[1]); - - // Try to read two elements, without "all or none". - elements[0] = -1; - elements[1] = -1; - num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(elements), - MakeUserPointer(&num_bytes), false, false)); - EXPECT_EQ(456, elements[0]); - EXPECT_EQ(-1, elements[1]); - - // Query. - num_bytes = 0; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(0u, num_bytes); - - dp->ProducerClose(); - dp->ConsumerClose(); -} - -// Note: The "basic" waiting tests test that the "wait states" are correct in -// various situations; they don't test that waiters are properly awoken on state -// changes. (For that, we need to use multiple threads.) -TEST(LocalDataPipeTest, BasicProducerWaiting) { - // Note: We take advantage of the fact that for |LocalDataPipe|, capacities - // are strict maximums. This is not guaranteed by the API. - - 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)); - - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - Waiter waiter; - uint32_t context = 0; - HandleSignalsState hss; - - // Never readable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_FAILED_PRECONDITION, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // Already writable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 34, &hss)); - - // Write two elements. - int32_t elements[2] = {123, 456}; - uint32_t num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(elements), - MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(static_cast<uint32_t>(2u * sizeof(elements[0])), num_bytes); - - // Adding a waiter should now succeed. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 56, - nullptr)); - // And it shouldn't be writable yet. - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, nullptr)); - hss = HandleSignalsState(); - dp->ProducerRemoveAwakable(&waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // Peek one element. - elements[0] = -1; - elements[1] = -1; - num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(elements), - MakeUserPointer(&num_bytes), true, true)); - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); - EXPECT_EQ(123, elements[0]); - EXPECT_EQ(-1, elements[1]); - - // Add a waiter. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 56, - nullptr)); - // And it still shouldn't be writable yet. - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, nullptr)); - hss = HandleSignalsState(); - dp->ProducerRemoveAwakable(&waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // Do it again. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 78, - nullptr)); - - // Read one element. - elements[0] = -1; - elements[1] = -1; - num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(elements), - MakeUserPointer(&num_bytes), true, false)); - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); - EXPECT_EQ(123, elements[0]); - EXPECT_EQ(-1, elements[1]); - - // Waiting should now succeed. - EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(1000, &context)); - EXPECT_EQ(78u, context); - hss = HandleSignalsState(); - dp->ProducerRemoveAwakable(&waiter, &hss); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_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; - num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&buffer), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(buffer); - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); - - static_cast<int32_t*>(buffer)[0] = 789; - EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(static_cast<uint32_t>( - 1u * sizeof(elements[0])))); - - // Add a waiter. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 90, - nullptr)); - - // Read one element, using a two-phase read. - const void* read_buffer = nullptr; - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(read_buffer); - // Since we only read one element (after having written three in all), the - // two-phase read should only allow us to read one. This checks an - // implementation detail! - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); - EXPECT_EQ(456, static_cast<const int32_t*>(read_buffer)[0]); - EXPECT_EQ( - MOJO_RESULT_OK, - dp->ConsumerEndReadData(static_cast<uint32_t>(1u * sizeof(elements[0])))); - - // Waiting should succeed. - EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(1000, &context)); - EXPECT_EQ(90u, context); - hss = HandleSignalsState(); - dp->ProducerRemoveAwakable(&waiter, &hss); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // Write one element. - elements[0] = 123; - num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(elements), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); - - // Add a waiter. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 12, - nullptr)); - - // Close the consumer. - dp->ConsumerClose(); - - // It should now be never-writable. - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, waiter.Wait(1000, &context)); - EXPECT_EQ(12u, context); - hss = HandleSignalsState(); - dp->ProducerRemoveAwakable(&waiter, &hss); - 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->ProducerAddAwakable(&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->ProducerRemoveAwakable(&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->ConsumerAddAwakable(&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->ConsumerRemoveAwakable(&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|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 1000 * sizeof(int32_t) // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - MakeUserPointer(&options), &validated_options)); - - { - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - Waiter waiter; - uint32_t context = 0; - HandleSignalsState hss; - - // Never writable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 12, - &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // Not yet readable. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 34, - nullptr)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, nullptr)); - hss = HandleSignalsState(); - dp->ConsumerRemoveAwakable(&waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // Write two elements. - int32_t elements[2] = {123, 456}; - uint32_t num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(elements), - MakeUserPointer(&num_bytes), true)); - - // Should already be readable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 56, - &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_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])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerDiscardData(MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); - - // Should still be readable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 78, - &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // Peek one element. - elements[0] = -1; - elements[1] = -1; - num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(elements), - MakeUserPointer(&num_bytes), true, true)); - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); - EXPECT_EQ(456, elements[0]); - EXPECT_EQ(-1, elements[1]); - - // Should still be readable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 78, - &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // Read one element. - elements[0] = -1; - elements[1] = -1; - num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(elements), - MakeUserPointer(&num_bytes), true, false)); - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); - EXPECT_EQ(456, elements[0]); - EXPECT_EQ(-1, elements[1]); - - // Adding a waiter should now succeed. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 90, - nullptr)); - - // Write one element. - elements[0] = 789; - elements[1] = -1; - num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(elements), - MakeUserPointer(&num_bytes), true)); - - // Waiting should now succeed. - EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(1000, &context)); - EXPECT_EQ(90u, context); - hss = HandleSignalsState(); - dp->ConsumerRemoveAwakable(&waiter, &hss); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // Close the producer. - dp->ProducerClose(); - - // Should still be readable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, - &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 one element. - elements[0] = -1; - elements[1] = -1; - num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(elements), - MakeUserPointer(&num_bytes), true, false)); - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); - EXPECT_EQ(789, elements[0]); - EXPECT_EQ(-1, elements[1]); - - // Should be never-readable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 34, - &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); - - dp->ConsumerClose(); - } - - // Test with two-phase APIs and closing the producer with an active consumer - // waiter. - { - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - Waiter waiter; - uint32_t context = 0; - HandleSignalsState hss; - - // Write two elements. - int32_t* elements = nullptr; - void* buffer = nullptr; - // Request room for three (but we'll only write two). - uint32_t num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&buffer), - MakeUserPointer(&num_bytes), true)); - EXPECT_TRUE(buffer); - EXPECT_GE(num_bytes, static_cast<uint32_t>(3u * sizeof(elements[0]))); - elements = static_cast<int32_t*>(buffer); - elements[0] = 123; - elements[1] = 456; - EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(static_cast<uint32_t>( - 2u * sizeof(elements[0])))); - - // Should already be readable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, - &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_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. - const void* read_buffer = nullptr; - num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer), - MakeUserPointer(&num_bytes), true)); - EXPECT_TRUE(read_buffer); - EXPECT_EQ(static_cast<uint32_t>(2u * sizeof(elements[0])), num_bytes); - const int32_t* read_elements = static_cast<const int32_t*>(read_buffer); - EXPECT_EQ(123, read_elements[0]); - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(static_cast<uint32_t>( - 1u * sizeof(elements[0])))); - - // Should still be readable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 34, - &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_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. - read_buffer = nullptr; - num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0])); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(read_buffer); - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes); - read_elements = static_cast<const int32_t*>(read_buffer); - EXPECT_EQ(456, read_elements[0]); - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(static_cast<uint32_t>( - 1u * sizeof(elements[0])))); - - // Adding a waiter should now succeed. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 56, - nullptr)); - - // Close the producer. - dp->ProducerClose(); - - // Should be never-readable. - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, waiter.Wait(1000, &context)); - EXPECT_EQ(56u, context); - hss = HandleSignalsState(); - dp->ConsumerRemoveAwakable(&waiter, &hss); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); - - dp->ConsumerClose(); - } -} - -// Tests that data pipes aren't writable/readable during two-phase writes/reads. -TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 1000 * sizeof(int32_t) // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - MakeUserPointer(&options), &validated_options)); - - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - Waiter waiter; - HandleSignalsState hss; - - // It should be writable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_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; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(write_ptr); - EXPECT_GE(num_bytes, static_cast<uint32_t>(1u * sizeof(int32_t))); - - // At this point, it shouldn't be writable. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 1, - nullptr)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, nullptr)); - hss = HandleSignalsState(); - dp->ProducerRemoveAwakable(&waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // It shouldn't be readable yet either. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 2, - nullptr)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, nullptr)); - hss = HandleSignalsState(); - dp->ConsumerRemoveAwakable(&waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_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( - static_cast<uint32_t>(1u * sizeof(int32_t)))); - - // It should be writable again. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 3, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // And readable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 4, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_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. - num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t)); - write_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(write_ptr); - EXPECT_GE(num_bytes, static_cast<uint32_t>(1u * sizeof(int32_t))); - - // It should be readable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 5, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_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)); - - // Start a two-phase read. - num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t)); - const void* read_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(read_ptr); - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(int32_t)), num_bytes); - - // At this point, it should still be writable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 6, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // But not readable. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 7, - nullptr)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, nullptr)); - hss = HandleSignalsState(); - dp->ConsumerRemoveAwakable(&waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_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)); - - // It should be readable again. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 8, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - dp->ProducerClose(); - dp->ConsumerClose(); -} - -// Test that a "may discard" data pipe is writable even when it's full. -TEST(LocalDataPipeTest, BasicMayDiscardWaiting) { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 1 * sizeof(int32_t) // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - MakeUserPointer(&options), &validated_options)); - - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - Waiter waiter; - HandleSignalsState hss; - - // Writable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // Not readable. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 1, - nullptr)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, nullptr)); - hss = HandleSignalsState(); - dp->ConsumerRemoveAwakable(&waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_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; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(&element), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(static_cast<uint32_t>(sizeof(int32_t)), num_bytes); - - // Still writable (even though it's full). - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 2, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // Now readable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 3, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_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)); - element = 456; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(&element), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(static_cast<uint32_t>(sizeof(int32_t)), num_bytes); - - // Still writable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // And still readable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 5, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_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)); - element = 0; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(&element), - MakeUserPointer(&num_bytes), false, false)); - EXPECT_EQ(static_cast<uint32_t>(sizeof(int32_t)), num_bytes); - EXPECT_EQ(456, element); - - // Still writable. - waiter.Init(); - hss = HandleSignalsState(); - EXPECT_EQ( - MOJO_RESULT_ALREADY_EXISTS, - dp->ProducerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 6, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - // No longer readable. - waiter.Init(); - ASSERT_EQ(MOJO_RESULT_OK, - dp->ConsumerAddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 7, - nullptr)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, nullptr)); - hss = HandleSignalsState(); - dp->ConsumerRemoveAwakable(&waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, - hss.satisfiable_signals); - - dp->ProducerClose(); - dp->ConsumerClose(); -} - -void Seq(int32_t start, size_t count, int32_t* out) { - for (size_t i = 0; i < count; i++) - out[i] = start + static_cast<int32_t>(i); -} - -TEST(LocalDataPipeTest, MayDiscard) { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 10 * sizeof(int32_t) // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - MakeUserPointer(&options), &validated_options)); - - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - - int32_t buffer[100] = {0}; - uint32_t num_bytes = 0; - - num_bytes = 20u * sizeof(int32_t); - Seq(0, arraysize(buffer), buffer); - // Try writing more than capacity. (This test relies on the implementation - // enforcing the capacity strictly.) - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(10u * sizeof(int32_t), num_bytes); - - // Read half of what we wrote. - num_bytes = 5u * sizeof(int32_t); - memset(buffer, 0xab, sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), false, false)); - EXPECT_EQ(5u * sizeof(int32_t), num_bytes); - int32_t expected_buffer[100]; - memset(expected_buffer, 0xab, sizeof(expected_buffer)); - Seq(0, 5u, expected_buffer); - EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); - // Internally, a circular buffer would now look like: - // -, -, -, -, -, 5, 6, 7, 8, 9 - - // Write a bit more than the space that's available. - num_bytes = 8u * sizeof(int32_t); - Seq(100, arraysize(buffer), buffer); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(8u * sizeof(int32_t), num_bytes); - // Internally, a circular buffer would now look like: - // 100, 101, 102, 103, 104, 105, 106, 107, 8, 9 - - // Read half of what's available. - num_bytes = 5u * sizeof(int32_t); - memset(buffer, 0xab, sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), false, false)); - EXPECT_EQ(5u * sizeof(int32_t), num_bytes); - memset(expected_buffer, 0xab, sizeof(expected_buffer)); - expected_buffer[0] = 8; - expected_buffer[1] = 9; - expected_buffer[2] = 100; - expected_buffer[3] = 101; - expected_buffer[4] = 102; - EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); - // Internally, a circular buffer would now look like: - // -, -, -, 103, 104, 105, 106, 107, -, - - - // Write one integer. - num_bytes = 1u * sizeof(int32_t); - Seq(200, arraysize(buffer), buffer); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(1u * sizeof(int32_t), num_bytes); - // Internally, a circular buffer would now look like: - // -, -, -, 103, 104, 105, 106, 107, 200, - - - // Write five more. - num_bytes = 5u * sizeof(int32_t); - Seq(300, arraysize(buffer), buffer); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(5u * sizeof(int32_t), num_bytes); - // Internally, a circular buffer would now look like: - // 301, 302, 303, 304, 104, 105, 106, 107, 200, 300 - - // Read it all. - num_bytes = sizeof(buffer); - memset(buffer, 0xab, sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), false, false)); - EXPECT_EQ(10u * sizeof(int32_t), num_bytes); - memset(expected_buffer, 0xab, sizeof(expected_buffer)); - expected_buffer[0] = 104; - expected_buffer[1] = 105; - expected_buffer[2] = 106; - expected_buffer[3] = 107; - expected_buffer[4] = 200; - expected_buffer[5] = 300; - expected_buffer[6] = 301; - expected_buffer[7] = 302; - expected_buffer[8] = 303; - expected_buffer[9] = 304; - EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); - - // Test two-phase writes, including in all-or-none mode. - // Note: Again, the following depends on an implementation detail -- namely - // that the write pointer will point at the 5th element of the buffer (and the - // buffer has exactly the capacity requested). - - num_bytes = 0u; - void* write_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(write_ptr); - EXPECT_EQ(6u * sizeof(int32_t), num_bytes); - Seq(400, 6, static_cast<int32_t*>(write_ptr)); - EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(6u * sizeof(int32_t))); - // Internally, a circular buffer would now look like: - // -, -, -, -, 400, 401, 402, 403, 404, 405 - - // |ProducerBeginWriteData()| ignores |*num_bytes| except in "all-or-none" - // mode. - num_bytes = 6u * sizeof(int32_t); - write_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(4u * sizeof(int32_t), num_bytes); - static_cast<int32_t*>(write_ptr)[0] = 500; - EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(1u * sizeof(int32_t))); - // Internally, a circular buffer would now look like: - // 500, -, -, -, 400, 401, 402, 403, 404, 405 - - // Requesting a 10-element buffer in all-or-none mode fails at this point. - num_bytes = 10u * sizeof(int32_t); - write_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), true)); - - // But requesting, say, a 5-element (up to 9, really) buffer should be okay. - // It will discard two elements. - num_bytes = 5u * sizeof(int32_t); - write_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(5u * sizeof(int32_t), num_bytes); - // Only write 4 elements though. - Seq(600, 4, static_cast<int32_t*>(write_ptr)); - EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(4u * sizeof(int32_t))); - // Internally, a circular buffer would now look like: - // 500, 600, 601, 602, 603, -, 402, 403, 404, 405 - - // Do this again. Make sure we can get a buffer all the way out to the end of - // the internal buffer. - num_bytes = 5u * sizeof(int32_t); - write_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(5u * sizeof(int32_t), num_bytes); - // Only write 3 elements though. - Seq(700, 3, static_cast<int32_t*>(write_ptr)); - EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(3u * sizeof(int32_t))); - // Internally, a circular buffer would now look like: - // 500, 600, 601, 602, 603, 700, 701, 702, -, - - - // Read everything. - num_bytes = sizeof(buffer); - memset(buffer, 0xab, sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), false, false)); - EXPECT_EQ(8u * sizeof(int32_t), num_bytes); - memset(expected_buffer, 0xab, sizeof(expected_buffer)); - expected_buffer[0] = 500; - expected_buffer[1] = 600; - expected_buffer[2] = 601; - expected_buffer[3] = 602; - expected_buffer[4] = 603; - expected_buffer[5] = 700; - expected_buffer[6] = 701; - expected_buffer[7] = 702; - EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); - - dp->ProducerClose(); - dp->ConsumerClose(); -} - -TEST(LocalDataPipeTest, AllOrNone) { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 10 * sizeof(int32_t) // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - MakeUserPointer(&options), &validated_options)); - - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - - // Try writing way too much. - uint32_t num_bytes = 20u * sizeof(int32_t); - int32_t buffer[100]; - Seq(0, arraysize(buffer), buffer); - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), true)); - - // Should still be empty. - num_bytes = ~0u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(0u, num_bytes); - - // Write some data. - num_bytes = 5u * sizeof(int32_t); - Seq(100, arraysize(buffer), buffer); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(5u * sizeof(int32_t), num_bytes); - - // Half full. - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(5u * sizeof(int32_t), num_bytes); - - // Too much. - num_bytes = 6u * sizeof(int32_t); - Seq(200, arraysize(buffer), buffer); - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), true)); - - // Try reading too much. - num_bytes = 11u * sizeof(int32_t); - memset(buffer, 0xab, sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), true, false)); - int32_t expected_buffer[100]; - memset(expected_buffer, 0xab, sizeof(expected_buffer)); - EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); - - // Try discarding too much. - num_bytes = 11u * sizeof(int32_t); - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ConsumerDiscardData(MakeUserPointer(&num_bytes), true)); - - // Just a little. - num_bytes = 2u * sizeof(int32_t); - Seq(300, arraysize(buffer), buffer); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(2u * sizeof(int32_t), num_bytes); - - // Just right. - num_bytes = 3u * sizeof(int32_t); - Seq(400, arraysize(buffer), buffer); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(3u * sizeof(int32_t), num_bytes); - - // Exactly full. - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(10u * sizeof(int32_t), num_bytes); - - // Read half. - num_bytes = 5u * sizeof(int32_t); - memset(buffer, 0xab, sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), true, false)); - EXPECT_EQ(5u * sizeof(int32_t), num_bytes); - memset(expected_buffer, 0xab, sizeof(expected_buffer)); - Seq(100, 5, expected_buffer); - EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); - - // Try reading too much again. - num_bytes = 6u * sizeof(int32_t); - memset(buffer, 0xab, sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), true, false)); - memset(expected_buffer, 0xab, sizeof(expected_buffer)); - EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); - - // Try discarding too much again. - num_bytes = 6u * sizeof(int32_t); - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ConsumerDiscardData(MakeUserPointer(&num_bytes), true)); - - // Discard a little. - num_bytes = 2u * sizeof(int32_t); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerDiscardData(MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(2u * sizeof(int32_t), num_bytes); - - // Three left. - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(3u * sizeof(int32_t), num_bytes); - - // Close the producer, then test producer-closed cases. - dp->ProducerClose(); - - // Try reading too much; "failed precondition" since the producer is closed. - num_bytes = 4u * sizeof(int32_t); - memset(buffer, 0xab, sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), true, false)); - memset(expected_buffer, 0xab, sizeof(expected_buffer)); - EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); - - // Try discarding too much; "failed precondition" again. - num_bytes = 4u * sizeof(int32_t); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - dp->ConsumerDiscardData(MakeUserPointer(&num_bytes), true)); - - // Read a little. - num_bytes = 2u * sizeof(int32_t); - memset(buffer, 0xab, sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), true, false)); - EXPECT_EQ(2u * sizeof(int32_t), num_bytes); - memset(expected_buffer, 0xab, sizeof(expected_buffer)); - Seq(400, 2, expected_buffer); - EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); - - // Discard the remaining element. - num_bytes = 1u * sizeof(int32_t); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerDiscardData(MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(1u * sizeof(int32_t), num_bytes); - - // Empty again. - num_bytes = ~0u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(0u, num_bytes); - - dp->ConsumerClose(); -} - -TEST(LocalDataPipeTest, AllOrNoneMayDiscard) { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 10 * sizeof(int32_t) // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - MakeUserPointer(&options), &validated_options)); - - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - - // Try writing way too much. - uint32_t num_bytes = 20u * sizeof(int32_t); - int32_t buffer[100]; - Seq(0, arraysize(buffer), buffer); - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), true)); - - // Write some stuff. - num_bytes = 5u * sizeof(int32_t); - Seq(100, arraysize(buffer), buffer); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(5u * sizeof(int32_t), num_bytes); - - // Write lots of stuff (discarding all but "104"). - num_bytes = 9u * sizeof(int32_t); - Seq(200, arraysize(buffer), buffer); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(9u * sizeof(int32_t), num_bytes); - - // Read one. - num_bytes = 1u * sizeof(int32_t); - memset(buffer, 0xab, sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), true, false)); - EXPECT_EQ(1u * sizeof(int32_t), num_bytes); - int32_t expected_buffer[100]; - memset(expected_buffer, 0xab, sizeof(expected_buffer)); - expected_buffer[0] = 104; - EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); - - // Try reading too many. - num_bytes = 10u * sizeof(int32_t); - memset(buffer, 0xab, sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), true, false)); - memset(expected_buffer, 0xab, sizeof(expected_buffer)); - EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); - - // Try discarding too many. - num_bytes = 10u * sizeof(int32_t); - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ConsumerDiscardData(MakeUserPointer(&num_bytes), true)); - - // Discard a bunch. - num_bytes = 4u * sizeof(int32_t); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerDiscardData(MakeUserPointer(&num_bytes), true)); - - // Half full. - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(5u * sizeof(int32_t), num_bytes); - - // Write as much as possible. - num_bytes = 10u * sizeof(int32_t); - Seq(300, arraysize(buffer), buffer); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(10u * sizeof(int32_t), num_bytes); - - // Read everything. - num_bytes = 10u * sizeof(int32_t); - memset(buffer, 0xab, sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), true, false)); - memset(expected_buffer, 0xab, sizeof(expected_buffer)); - EXPECT_EQ(10u * sizeof(int32_t), num_bytes); - Seq(300, 10, expected_buffer); - EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); - - // Note: All-or-none two-phase writes on a "may discard" data pipe are tested - // in LocalDataPipeTest.MayDiscard. - - dp->ProducerClose(); - dp->ConsumerClose(); -} - -TEST(LocalDataPipeTest, TwoPhaseAllOrNone) { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 10 * sizeof(int32_t) // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - MakeUserPointer(&options), &validated_options)); - - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - - // Try writing way too much (two-phase). - uint32_t num_bytes = 20u * sizeof(int32_t); - void* write_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), true)); - - // Try writing an amount which isn't a multiple of the element size - // (two-phase). - static_assert(sizeof(int32_t) > 1u, "Wow! int32_t's have size 1"); - num_bytes = 1u; - write_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), true)); - - // Try reading way too much (two-phase). - num_bytes = 20u * sizeof(int32_t); - const void* read_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), - MakeUserPointer(&num_bytes), true)); - - // Write half (two-phase). - num_bytes = 5u * sizeof(int32_t); - write_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), true)); - // May provide more space than requested. - EXPECT_GE(num_bytes, 5u * sizeof(int32_t)); - EXPECT_TRUE(write_ptr); - Seq(0, 5, static_cast<int32_t*>(write_ptr)); - EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(5u * sizeof(int32_t))); - - // Try reading an amount which isn't a multiple of the element size - // (two-phase). - num_bytes = 1u; - read_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), - MakeUserPointer(&num_bytes), true)); - - // Read one (two-phase). - num_bytes = 1u * sizeof(int32_t); - read_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), - MakeUserPointer(&num_bytes), true)); - EXPECT_GE(num_bytes, 1u * sizeof(int32_t)); - EXPECT_EQ(0, static_cast<const int32_t*>(read_ptr)[0]); - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(1u * sizeof(int32_t))); - - // We should have four left, leaving room for six. - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(4u * sizeof(int32_t), num_bytes); - - // Assuming a tight circular buffer of the specified capacity, we can't do a - // two-phase write of six now. - num_bytes = 6u * sizeof(int32_t); - write_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), true)); - - // Write six elements (simple), filling the buffer. - num_bytes = 6u * sizeof(int32_t); - int32_t buffer[100]; - Seq(100, 6, buffer); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(buffer), - MakeUserPointer(&num_bytes), true)); - EXPECT_EQ(6u * sizeof(int32_t), num_bytes); - - // We have ten. - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(10u * sizeof(int32_t), num_bytes); - - // But a two-phase read of ten should fail. - num_bytes = 10u * sizeof(int32_t); - read_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), - MakeUserPointer(&num_bytes), true)); - - // Close the producer. - dp->ProducerClose(); - - // A two-phase read of nine should work. - num_bytes = 9u * sizeof(int32_t); - read_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), - MakeUserPointer(&num_bytes), true)); - EXPECT_GE(num_bytes, 9u * sizeof(int32_t)); - EXPECT_EQ(1, static_cast<const int32_t*>(read_ptr)[0]); - EXPECT_EQ(2, static_cast<const int32_t*>(read_ptr)[1]); - EXPECT_EQ(3, static_cast<const int32_t*>(read_ptr)[2]); - EXPECT_EQ(4, static_cast<const int32_t*>(read_ptr)[3]); - EXPECT_EQ(100, static_cast<const int32_t*>(read_ptr)[4]); - EXPECT_EQ(101, static_cast<const int32_t*>(read_ptr)[5]); - EXPECT_EQ(102, static_cast<const int32_t*>(read_ptr)[6]); - EXPECT_EQ(103, static_cast<const int32_t*>(read_ptr)[7]); - EXPECT_EQ(104, static_cast<const int32_t*>(read_ptr)[8]); - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(9u * sizeof(int32_t))); - - // A two-phase read of two should fail, with "failed precondition". - num_bytes = 2u * sizeof(int32_t); - read_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), - MakeUserPointer(&num_bytes), true)); - - dp->ConsumerClose(); -} - -// Tests that |ProducerWriteData()| and |ConsumerReadData()| writes and reads, -// respectively, as much as possible, even if it has to "wrap around" the -// internal circular buffer. (Note that the two-phase write and read do not do -// this.) -TEST(LocalDataPipeTest, WrapAround) { - unsigned char test_data[1000]; - for (size_t i = 0; i < arraysize(test_data); i++) - test_data[i] = static_cast<unsigned char>(i); - - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1u, // |element_num_bytes|. - 100u // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - MakeUserPointer(&options), &validated_options)); - // This test won't be valid if |ValidateCreateOptions()| decides to give the - // pipe more space. - ASSERT_EQ(100u, validated_options.capacity_num_bytes); - - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - - // Write 20 bytes. - uint32_t num_bytes = 20u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(&test_data[0]), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(20u, num_bytes); - - // Read 10 bytes. - unsigned char read_buffer[1000] = {0}; - num_bytes = 10u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(read_buffer), - MakeUserPointer(&num_bytes), false, false)); - EXPECT_EQ(10u, num_bytes); - EXPECT_EQ(0, memcmp(read_buffer, &test_data[0], 10u)); - - // Check that a two-phase write can now only write (at most) 80 bytes. (This - // checks an implementation detail; this behavior is not guaranteed, but we - // need it for this test.) - void* write_buffer_ptr = nullptr; - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_buffer_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(write_buffer_ptr); - EXPECT_EQ(80u, num_bytes); - EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(0u)); - - // Write as much data as we can (using |ProducerWriteData()|). We should write - // 90 bytes. - num_bytes = 200u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(&test_data[20]), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(90u, num_bytes); - - // Check that a two-phase read can now only read (at most) 90 bytes. (This - // checks an implementation detail; this behavior is not guaranteed, but we - // need it for this test.) - const void* read_buffer_ptr = nullptr; - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(read_buffer_ptr); - EXPECT_EQ(90u, num_bytes); - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(0u)); - - // Read as much as possible (using |ConsumerReadData()|). We should read 100 - // bytes. - num_bytes = - static_cast<uint32_t>(arraysize(read_buffer) * sizeof(read_buffer[0])); - memset(read_buffer, 0, num_bytes); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(read_buffer), - MakeUserPointer(&num_bytes), false, false)); - EXPECT_EQ(100u, num_bytes); - EXPECT_EQ(0, memcmp(read_buffer, &test_data[10], 100u)); - - dp->ProducerClose(); - dp->ConsumerClose(); -} - -// Tests the behavior of closing the producer or consumer with respect to -// writes and reads (simple and two-phase). -TEST(LocalDataPipeTest, CloseWriteRead) { - const char kTestData[] = "hello world"; - const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kTestData)); - - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1u, // |element_num_bytes|. - 1000u // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - MakeUserPointer(&options), &validated_options)); - - // Close producer first, then consumer. - { - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - - // Write some data, so we'll have something to read. - uint32_t num_bytes = kTestDataSize; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(kTestData), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(kTestDataSize, num_bytes); - - // Write it again, so we'll have something left over. - num_bytes = kTestDataSize; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(kTestData), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(kTestDataSize, num_bytes); - - // Start two-phase write. - void* write_buffer_ptr = nullptr; - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_buffer_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(write_buffer_ptr); - EXPECT_GT(num_bytes, 0u); - - // Start two-phase read. - const void* read_buffer_ptr = nullptr; - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(read_buffer_ptr); - EXPECT_EQ(2u * kTestDataSize, num_bytes); - - // Close the producer. - dp->ProducerClose(); - - // The consumer can finish its two-phase read. - EXPECT_EQ(0, memcmp(read_buffer_ptr, kTestData, kTestDataSize)); - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(kTestDataSize)); - - // And start another. - read_buffer_ptr = nullptr; - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(read_buffer_ptr); - EXPECT_EQ(kTestDataSize, num_bytes); - - // Close the consumer, which cancels the two-phase read. - dp->ConsumerClose(); - } - - // Close consumer first, then producer. - { - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - - // Write some data, so we'll have something to read. - uint32_t num_bytes = kTestDataSize; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(kTestData), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(kTestDataSize, num_bytes); - - // Start two-phase write. - void* write_buffer_ptr = nullptr; - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_buffer_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(write_buffer_ptr); - ASSERT_GT(num_bytes, kTestDataSize); - - // Start two-phase read. - const void* read_buffer_ptr = nullptr; - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(read_buffer_ptr); - EXPECT_EQ(kTestDataSize, num_bytes); - - // Close the consumer. - dp->ConsumerClose(); - - // Actually write some data. (Note: Premature freeing of the buffer would - // probably only be detected under ASAN or similar.) - memcpy(write_buffer_ptr, kTestData, kTestDataSize); - // Note: Even though the consumer has been closed, ending the two-phase - // write will report success. - EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(kTestDataSize)); - - // But trying to write should result in failure. - num_bytes = kTestDataSize; - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - dp->ProducerWriteData(UserPointer<const void>(kTestData), - MakeUserPointer(&num_bytes), false)); - - // As will trying to start another two-phase write. - write_buffer_ptr = nullptr; - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - dp->ProducerBeginWriteData(MakeUserPointer(&write_buffer_ptr), - MakeUserPointer(&num_bytes), false)); - - dp->ProducerClose(); - } - - // Test closing the consumer first, then the producer, with an active - // two-phase write. - { - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - - // Start two-phase write. - void* write_buffer_ptr = nullptr; - uint32_t num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_buffer_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_TRUE(write_buffer_ptr); - ASSERT_GT(num_bytes, kTestDataSize); - - dp->ConsumerClose(); - dp->ProducerClose(); - } - - // Test closing the producer and then trying to read (with no data). - { - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - - // Write some data, so we'll have something to read. - uint32_t num_bytes = kTestDataSize; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(kTestData), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(kTestDataSize, num_bytes); - - // Close the producer. - dp->ProducerClose(); - - // Peek that data. - char buffer[1000]; - num_bytes = static_cast<uint32_t>(sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), false, true)); - EXPECT_EQ(kTestDataSize, num_bytes); - EXPECT_EQ(0, memcmp(buffer, kTestData, kTestDataSize)); - - // Read that data. - memset(buffer, 0, 1000); - num_bytes = static_cast<uint32_t>(sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), false, false)); - EXPECT_EQ(kTestDataSize, num_bytes); - EXPECT_EQ(0, memcmp(buffer, kTestData, kTestDataSize)); - - // A second read should fail. - num_bytes = static_cast<uint32_t>(sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - dp->ConsumerReadData(UserPointer<void>(buffer), - MakeUserPointer(&num_bytes), false, false)); - - // A two-phase read should also fail. - const void* read_buffer_ptr = nullptr; - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - dp->ConsumerBeginReadData(MakeUserPointer(&read_buffer_ptr), - MakeUserPointer(&num_bytes), false)); - - // Ditto for discard. - num_bytes = 10u; - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - dp->ConsumerDiscardData(MakeUserPointer(&num_bytes), false)); - - dp->ConsumerClose(); - } -} - -TEST(LocalDataPipeTest, TwoPhaseMoreInvalidArguments) { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 10 * sizeof(int32_t) // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - MakeUserPointer(&options), &validated_options)); - - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - - // No data. - uint32_t num_bytes = 1000u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(0u, num_bytes); - - // Try "ending" a two-phase write when one isn't active. - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - dp->ProducerEndWriteData(1u * sizeof(int32_t))); - - // Still no data. - num_bytes = 1000u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(0u, num_bytes); - - // Try ending a two-phase write with an invalid amount (too much). - num_bytes = 0u; - void* write_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - dp->ProducerEndWriteData(num_bytes + - static_cast<uint32_t>(sizeof(int32_t)))); - - // But the two-phase write still ended. - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, dp->ProducerEndWriteData(0u)); - - // Still no data. - num_bytes = 1000u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(0u, num_bytes); - - // Try ending a two-phase write with an invalid amount (not a multiple of the - // element size). - num_bytes = 0u; - write_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerBeginWriteData(MakeUserPointer(&write_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_GE(num_bytes, 1u); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, dp->ProducerEndWriteData(1u)); - - // But the two-phase write still ended. - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, dp->ProducerEndWriteData(0u)); - - // Still no data. - num_bytes = 1000u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(0u, num_bytes); - - // Now write some data, so we'll be able to try reading. - int32_t element = 123; - num_bytes = 1u * sizeof(int32_t); - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(&element), - MakeUserPointer(&num_bytes), false)); - - // One element available. - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(1u * sizeof(int32_t), num_bytes); - - // Try "ending" a two-phase read when one isn't active. - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - dp->ConsumerEndReadData(1u * sizeof(int32_t))); - - // Still one element available. - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(1u * sizeof(int32_t), num_bytes); - - // Try ending a two-phase read with an invalid amount (too much). - num_bytes = 0u; - const void* read_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - dp->ConsumerEndReadData(num_bytes + - static_cast<uint32_t>(sizeof(int32_t)))); - - // Still one element available. - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(1u * sizeof(int32_t), num_bytes); - - // Try ending a two-phase read with an invalid amount (not a multiple of the - // element size). - num_bytes = 0u; - read_ptr = nullptr; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(1u * sizeof(int32_t), num_bytes); - EXPECT_EQ(123, static_cast<const int32_t*>(read_ptr)[0]); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, dp->ConsumerEndReadData(1u)); - - // Still one element available. - num_bytes = 0u; - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(MakeUserPointer(&num_bytes))); - EXPECT_EQ(1u * sizeof(int32_t), num_bytes); - - dp->ProducerClose(); - dp->ConsumerClose(); -} - -// Tests that even with "may discard", the data won't change under a two-phase -// read. -// TODO(vtl): crbug.com/348644: We currently don't pass this. (There are two -// related issues: First, we don't recognize that the data given to -// |ConsumerBeginReadData()| isn't discardable until |ConsumerEndReadData()|, -// and thus we erroneously allow |ProducerWriteData()| to succeed. Second, the -// |ProducerWriteData()| then changes the data underneath the two-phase read.) -TEST(LocalDataPipeTest, DISABLED_MayDiscardTwoPhaseConsistent) { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD, // |flags|. - 1, // |element_num_bytes|. - 2 // |capacity_num_bytes|. - }; - MojoCreateDataPipeOptions validated_options = {0}; - EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( - MakeUserPointer(&options), &validated_options)); - - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); - - // Write some elements. - char elements[2] = {'a', 'b'}; - uint32_t num_bytes = 2u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(elements), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(2u, num_bytes); - - // Begin reading. - const void* read_ptr = nullptr; - num_bytes = 2u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(2u, num_bytes); - EXPECT_EQ('a', static_cast<const char*>(read_ptr)[0]); - EXPECT_EQ('b', static_cast<const char*>(read_ptr)[1]); - - // Try to write some more. But nothing should be discardable right now. - elements[0] = 'x'; - elements[1] = 'y'; - num_bytes = 2u; - // TODO(vtl): This should be: - // EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, - // dp->ProducerWriteData(elements, &num_bytes, false)); - // but we incorrectly think that the bytes being read are discardable. Letting - // this through reveals the significant consequence. - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(elements), - MakeUserPointer(&num_bytes), false)); - - // Check that our read buffer hasn't changed underneath us. - EXPECT_EQ('a', static_cast<const char*>(read_ptr)[0]); - EXPECT_EQ('b', static_cast<const char*>(read_ptr)[1]); - - // End reading. - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(2u)); - - // Now writing should succeed. - EXPECT_EQ(MOJO_RESULT_OK, - dp->ProducerWriteData(UserPointer<const void>(elements), - MakeUserPointer(&num_bytes), false)); - - // And if we read, we should get the new values. - read_ptr = nullptr; - num_bytes = 2u; - EXPECT_EQ(MOJO_RESULT_OK, - dp->ConsumerBeginReadData(MakeUserPointer(&read_ptr), - MakeUserPointer(&num_bytes), false)); - EXPECT_EQ(2u, num_bytes); - EXPECT_EQ('x', static_cast<const char*>(read_ptr)[0]); - EXPECT_EQ('y', static_cast<const char*>(read_ptr)[1]); - - // End reading. - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(2u)); - - dp->ProducerClose(); - dp->ConsumerClose(); -} - -} // namespace -} // namespace system -} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc b/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc index b401bcd..e98908d 100644 --- a/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc +++ b/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc
@@ -37,12 +37,12 @@ public: Helper(MasterConnectionManager* owner, ProcessIdentifier process_identifier, - scoped_ptr<embedder::SlaveInfo> slave_info, + embedder::SlaveInfo slave_info, embedder::ScopedPlatformHandle platform_handle); ~Helper() override; void Init(); - scoped_ptr<embedder::SlaveInfo> Shutdown(); + embedder::SlaveInfo Shutdown(); private: // |RawChannel::Delegate| methods: @@ -58,7 +58,7 @@ MasterConnectionManager* const owner_; const ProcessIdentifier process_identifier_; - scoped_ptr<embedder::SlaveInfo> slave_info_; + embedder::SlaveInfo const slave_info_; scoped_ptr<RawChannel> raw_channel_; DISALLOW_COPY_AND_ASSIGN(Helper); @@ -67,26 +67,26 @@ MasterConnectionManager::Helper::Helper( MasterConnectionManager* owner, ProcessIdentifier process_identifier, - scoped_ptr<embedder::SlaveInfo> slave_info, + embedder::SlaveInfo slave_info, embedder::ScopedPlatformHandle platform_handle) : owner_(owner), process_identifier_(process_identifier), - slave_info_(slave_info.Pass()), + slave_info_(slave_info), raw_channel_(RawChannel::Create(platform_handle.Pass())) { } MasterConnectionManager::Helper::~Helper() { - DCHECK(!slave_info_); + DCHECK(!raw_channel_); } void MasterConnectionManager::Helper::Init() { raw_channel_->Init(this); } -scoped_ptr<embedder::SlaveInfo> MasterConnectionManager::Helper::Shutdown() { +embedder::SlaveInfo MasterConnectionManager::Helper::Shutdown() { raw_channel_->Shutdown(); raw_channel_.reset(); - return slave_info_.Pass(); + return slave_info_; } void MasterConnectionManager::Helper::OnReadMessage( @@ -243,14 +243,31 @@ DCHECK(!private_thread_.message_loop()); delegate_thread_task_runner_ = delegate_thread_task_runner; - AssertOnDelegateThread(); master_process_delegate_ = master_process_delegate; CHECK(private_thread_.StartWithOptions( base::Thread::Options(base::MessageLoop::TYPE_IO, 0))); } +void MasterConnectionManager::AddSlave( + embedder::SlaveInfo slave_info, + embedder::ScopedPlatformHandle platform_handle) { + // We don't really care if |slave_info| is non-null or not. + DCHECK(platform_handle.is_valid()); + AssertNotOnPrivateThread(); + + // We have to wait for the task to be executed, in case someone calls + // |AddSlave()| followed immediately by |Shutdown()|. + base::WaitableEvent event(false, false); + private_thread_.message_loop()->PostTask( + FROM_HERE, + base::Bind(&MasterConnectionManager::AddSlaveOnPrivateThread, + base::Unretained(this), base::Unretained(slave_info), + base::Passed(&platform_handle), base::Unretained(&event))); + event.Wait(); +} + void MasterConnectionManager::Shutdown() { - AssertOnDelegateThread(); + AssertNotOnPrivateThread(); DCHECK(master_process_delegate_); DCHECK(private_thread_.message_loop()); @@ -265,24 +282,6 @@ delegate_thread_task_runner_ = nullptr; } -void MasterConnectionManager::AddSlave( - scoped_ptr<embedder::SlaveInfo> slave_info, - embedder::ScopedPlatformHandle platform_handle) { - // We don't really care if |slave_info| is non-null or not. - DCHECK(platform_handle.is_valid()); - AssertNotOnPrivateThread(); - - // We have to wait for the task to be executed, in case someone calls - // |AddSlave()| followed immediately by |Shutdown()|. - base::WaitableEvent event(false, false); - private_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&MasterConnectionManager::AddSlaveOnPrivateThread, - base::Unretained(this), base::Passed(&slave_info), - base::Passed(&platform_handle), base::Unretained(&event))); - event.Wait(); -} - bool MasterConnectionManager::AllowConnect( const ConnectionIdentifier& connection_id) { AssertNotOnPrivateThread(); @@ -482,16 +481,16 @@ if (!helpers_.empty()) { DVLOG(1) << "Shutting down with slaves still connected"; for (auto& p : helpers_) { - scoped_ptr<embedder::SlaveInfo> slave_info = p.second->Shutdown(); + embedder::SlaveInfo slave_info = p.second->Shutdown(); delete p.second; - CallOnSlaveDisconnect(slave_info.Pass()); + CallOnSlaveDisconnect(slave_info); } helpers_.clear(); } } void MasterConnectionManager::AddSlaveOnPrivateThread( - scoped_ptr<embedder::SlaveInfo> slave_info, + embedder::SlaveInfo slave_info, embedder::ScopedPlatformHandle platform_handle, base::WaitableEvent* event) { DCHECK(platform_handle.is_valid()); @@ -502,8 +501,8 @@ ProcessIdentifier process_identifier = next_process_identifier_; next_process_identifier_++; - scoped_ptr<Helper> helper(new Helper( - this, process_identifier, slave_info.Pass(), platform_handle.Pass())); + scoped_ptr<Helper> helper( + new Helper(this, process_identifier, slave_info, platform_handle.Pass())); helper->Init(); DCHECK(helpers_.find(process_identifier) == helpers_.end()); @@ -520,7 +519,7 @@ auto it = helpers_.find(process_identifier); DCHECK(it != helpers_.end()); Helper* helper = it->second; - scoped_ptr<embedder::SlaveInfo> slave_info = helper->Shutdown(); + embedder::SlaveInfo slave_info = helper->Shutdown(); helpers_.erase(it); delete helper; @@ -542,23 +541,17 @@ } } - CallOnSlaveDisconnect(slave_info.Pass()); + CallOnSlaveDisconnect(slave_info); } void MasterConnectionManager::CallOnSlaveDisconnect( - scoped_ptr<embedder::SlaveInfo> slave_info) { + embedder::SlaveInfo slave_info) { AssertOnPrivateThread(); DCHECK(master_process_delegate_); delegate_thread_task_runner_->PostTask( FROM_HERE, base::Bind(&embedder::MasterProcessDelegate::OnSlaveDisconnect, base::Unretained(master_process_delegate_), - base::Passed(&slave_info))); -} - -void MasterConnectionManager::AssertOnDelegateThread() const { - DCHECK(base::MessageLoop::current()); - DCHECK_EQ(base::MessageLoop::current()->task_runner(), - delegate_thread_task_runner_); + base::Unretained(slave_info))); } void MasterConnectionManager::AssertNotOnPrivateThread() const {
diff --git a/third_party/mojo/src/mojo/edk/system/master_connection_manager.h b/third_party/mojo/src/mojo/edk/system/master_connection_manager.h index 5bdb810f..24e82e3f 100644 --- a/third_party/mojo/src/mojo/edk/system/master_connection_manager.h +++ b/third_party/mojo/src/mojo/edk/system/master_connection_manager.h
@@ -25,7 +25,7 @@ namespace embedder { class MasterProcessDelegate; -class SlaveInfo; +typedef void* SlaveInfo; } namespace system { @@ -35,10 +35,10 @@ // The |ConnectionManager| implementation for the master process. // -// Objects of this class may be created and destroyed on any thread. However, -// |Init()| and |Shutdown()| must be called on the "delegate thread". Otherwise, -// its public methods are thread-safe (except that they may not be called from -// its internal, private thread). +// This class is thread-safe (except that no public methods may be called from +// its internal, private thread), with condition that |Init()| be called before +// anything else and |Shutdown()| be called before destruction (and no other +// public methods may be called during/after |Shutdown()|). class MOJO_SYSTEM_IMPL_EXPORT MasterConnectionManager : public ConnectionManager { public: @@ -54,18 +54,17 @@ void Init(scoped_refptr<base::TaskRunner> delegate_thread_task_runner, embedder::MasterProcessDelegate* master_process_delegate); - // No other methods may be called after this is (or while it is being) called. - void Shutdown(); - // Adds a slave process and sets up/tracks a connection to that slave (using - // |platform_handle|). (|slave_info| is used by the caller/implementation of - // |embedder::MasterProcessDelegate| to track this process; ownership of - // |slave_info| will be returned to the delegate via |OnSlaveDisconnect()|, - // which will always be called for each slave, assuming proper shutdown.) - void AddSlave(scoped_ptr<embedder::SlaveInfo> slave_info, + // |platform_handle|). |slave_info| is used by the caller/implementation of + // |embedder::MasterProcessDelegate| to track this process. It must remain + // alive until the delegate's |OnSlaveDisconnect()| is called with it as the + // argument. |OnSlaveDisconnect()| will always be called for each slave, + // assuming proper shutdown.) + void AddSlave(embedder::SlaveInfo slave_info, embedder::ScopedPlatformHandle platform_handle); // |ConnectionManager| methods: + void Shutdown() override; bool AllowConnect(const ConnectionIdentifier& connection_id) override; bool CancelConnect(const ConnectionIdentifier& connection_id) override; bool Connect(const ConnectionIdentifier& connection_id, @@ -89,18 +88,13 @@ // These should only be called on |private_thread_|: void ShutdownOnPrivateThread(); // Signals |*event| on completion. - void AddSlaveOnPrivateThread(scoped_ptr<embedder::SlaveInfo> slave_info, + void AddSlaveOnPrivateThread(embedder::SlaveInfo slave_info, embedder::ScopedPlatformHandle platform_handle, base::WaitableEvent* event); // Called by |Helper::OnError()|. void OnError(ProcessIdentifier process_identifier); // Posts a call to |master_process_delegate_->OnSlaveDisconnect()|. - void CallOnSlaveDisconnect(scoped_ptr<embedder::SlaveInfo> slave_info); - - // Asserts that the current thread is the delegate thread. (This actually - // checks the current message loop.) - // TODO(vtl): Probably we should actually check the thread. - void AssertOnDelegateThread() const; + void CallOnSlaveDisconnect(embedder::SlaveInfo slave_info); // Asserts that the current thread is *not* |private_thread_| (no-op if // DCHECKs are not enabled). This should only be called while
diff --git a/third_party/mojo/src/mojo/edk/system/message_in_transit.cc b/third_party/mojo/src/mojo/edk/system/message_in_transit.cc index 9e38064..6107608 100644 --- a/third_party/mojo/src/mojo/edk/system/message_in_transit.cc +++ b/third_party/mojo/src/mojo/edk/system/message_in_transit.cc
@@ -28,6 +28,8 @@ STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype MessageInTransit::kSubtypeEndpointData; STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype + MessageInTransit::kSubtypeEndpointDataPipeAck; +STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype MessageInTransit::kSubtypeChannelAttachAndRunEndpoint; STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype MessageInTransit::kSubtypeChannelRemoveEndpoint;
diff --git a/third_party/mojo/src/mojo/edk/system/message_in_transit.h b/third_party/mojo/src/mojo/edk/system/message_in_transit.h index 9f118f9..9b3d398 100644 --- a/third_party/mojo/src/mojo/edk/system/message_in_transit.h +++ b/third_party/mojo/src/mojo/edk/system/message_in_transit.h
@@ -59,6 +59,7 @@ typedef uint16_t Subtype; // Subtypes for type |kTypeEndpoint|: static const Subtype kSubtypeEndpointData = 0; + static const Subtype kSubtypeEndpointDataPipeAck = 1; // Subtypes for type |kTypeChannel|: static const Subtype kSubtypeChannelAttachAndRunEndpoint = 0; static const Subtype kSubtypeChannelRemoveEndpoint = 1;
diff --git a/third_party/mojo/src/mojo/edk/system/message_pipe_dispatcher_unittest.cc b/third_party/mojo/src/mojo/edk/system/message_pipe_dispatcher_unittest.cc index b5562b0..760aced 100644 --- a/third_party/mojo/src/mojo/edk/system/message_pipe_dispatcher_unittest.cc +++ b/third_party/mojo/src/mojo/edk/system/message_pipe_dispatcher_unittest.cc
@@ -139,7 +139,7 @@ EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); // It should be signaled. - EXPECT_EQ(MOJO_RESULT_OK, w.Wait(1000, &context)); + EXPECT_EQ(MOJO_RESULT_OK, w.Wait(test::TinyDeadline(), &context)); EXPECT_EQ(12u, context); hss = HandleSignalsState(); d0->RemoveAwakable(&w, &hss);
diff --git a/third_party/mojo/src/mojo/edk/system/remote_consumer_data_pipe_impl.cc b/third_party/mojo/src/mojo/edk/system/remote_consumer_data_pipe_impl.cc new file mode 100644 index 0000000..fa59df06 --- /dev/null +++ b/third_party/mojo/src/mojo/edk/system/remote_consumer_data_pipe_impl.cc
@@ -0,0 +1,418 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/edk/system/remote_consumer_data_pipe_impl.h" + +#include <string.h> + +#include <algorithm> + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/edk/system/channel.h" +#include "mojo/edk/system/channel_endpoint.h" +#include "mojo/edk/system/configuration.h" +#include "mojo/edk/system/data_pipe.h" +#include "mojo/edk/system/message_in_transit.h" +#include "mojo/edk/system/remote_data_pipe_ack.h" + +namespace mojo { +namespace system { + +namespace { + +bool ValidateIncomingMessage(size_t element_num_bytes, + size_t capacity_num_bytes, + size_t consumer_num_bytes, + const MessageInTransit* message) { + // We should only receive endpoint messages. + DCHECK_EQ(message->type(), MessageInTransit::kTypeEndpoint); + + // But we should check the subtype; only take data pipe acks. + if (message->subtype() != MessageInTransit::kSubtypeEndpointDataPipeAck) { + LOG(WARNING) << "Received message of unexpected subtype: " + << message->subtype(); + return false; + } + + if (message->num_bytes() != sizeof(RemoteDataPipeAck)) { + LOG(WARNING) << "Incorrect message size: " << message->num_bytes() + << " bytes (expected: " << sizeof(RemoteDataPipeAck) + << " bytes)"; + return false; + } + + const RemoteDataPipeAck* ack = + static_cast<const RemoteDataPipeAck*>(message->bytes()); + size_t num_bytes_consumed = ack->num_bytes_consumed; + + if (num_bytes_consumed > consumer_num_bytes) { + LOG(WARNING) << "Number of bytes consumed too large: " << num_bytes_consumed + << " bytes (outstanding: " << consumer_num_bytes << " bytes)"; + return false; + } + + if (num_bytes_consumed % element_num_bytes != 0) { + LOG(WARNING) << "Number of bytes consumed not a multiple of element size: " + << num_bytes_consumed + << " bytes (element size: " << element_num_bytes << " bytes)"; + return false; + } + + return true; +} + +} // namespace + +RemoteConsumerDataPipeImpl::RemoteConsumerDataPipeImpl( + ChannelEndpoint* channel_endpoint, + size_t consumer_num_bytes) + : channel_endpoint_(channel_endpoint), + consumer_num_bytes_(consumer_num_bytes) { + // Note: |buffer_| is lazily allocated. +} + +RemoteConsumerDataPipeImpl::~RemoteConsumerDataPipeImpl() { +} + +void RemoteConsumerDataPipeImpl::ProducerClose() { + if (!consumer_open()) { + DCHECK(!channel_endpoint_); + return; + } + + Disconnect(); +} + +// static +bool RemoteConsumerDataPipeImpl::ProcessMessagesFromIncomingEndpoint( + const MojoCreateDataPipeOptions& validated_options, + size_t* consumer_num_bytes, + MessageInTransitQueue* messages) { + const size_t element_num_bytes = validated_options.element_num_bytes; + const size_t capacity_num_bytes = validated_options.capacity_num_bytes; + + if (messages) { + while (!messages->IsEmpty()) { + scoped_ptr<MessageInTransit> message(messages->GetMessage()); + if (!ValidateIncomingMessage(element_num_bytes, capacity_num_bytes, + *consumer_num_bytes, message.get())) { + messages->Clear(); + return false; + } + + const RemoteDataPipeAck* ack = + static_cast<const RemoteDataPipeAck*>(message->bytes()); + size_t num_bytes_consumed = ack->num_bytes_consumed; + *consumer_num_bytes -= num_bytes_consumed; + } + } + + return true; +} + +MojoResult RemoteConsumerDataPipeImpl::ProducerWriteData( + UserPointer<const void> elements, + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_write, + uint32_t min_num_bytes_to_write) { + DCHECK_EQ(max_num_bytes_to_write % element_num_bytes(), 0u); + DCHECK_EQ(min_num_bytes_to_write % element_num_bytes(), 0u); + DCHECK_GT(max_num_bytes_to_write, 0u); + DCHECK_GE(max_num_bytes_to_write, min_num_bytes_to_write); + DCHECK(consumer_open()); + DCHECK(channel_endpoint_); + + DCHECK_LE(consumer_num_bytes_, capacity_num_bytes()); + DCHECK_EQ(consumer_num_bytes_ % element_num_bytes(), 0u); + + if (min_num_bytes_to_write > capacity_num_bytes() - consumer_num_bytes_) + return MOJO_RESULT_OUT_OF_RANGE; + + size_t num_bytes_to_write = + std::min(static_cast<size_t>(max_num_bytes_to_write), + capacity_num_bytes() - consumer_num_bytes_); + if (num_bytes_to_write == 0) + return MOJO_RESULT_SHOULD_WAIT; + + // The maximum amount of data to send per message (make it a multiple of the + // element size. + // TODO(vtl): Copied from |LocalDataPipeImpl::ConvertDataToMessages()|. + size_t max_message_num_bytes = GetConfiguration().max_message_num_bytes; + max_message_num_bytes -= max_message_num_bytes % element_num_bytes(); + DCHECK_GT(max_message_num_bytes, 0u); + + size_t offset = 0; + while (offset < num_bytes_to_write) { + size_t message_num_bytes = + std::min(max_message_num_bytes, num_bytes_to_write - offset); + scoped_ptr<MessageInTransit> message(new MessageInTransit( + MessageInTransit::kTypeEndpoint, MessageInTransit::kSubtypeEndpointData, + static_cast<uint32_t>(message_num_bytes), elements.At(offset))); + if (!channel_endpoint_->EnqueueMessage(message.Pass())) { + Disconnect(); + break; + } + + offset += message_num_bytes; + consumer_num_bytes_ += message_num_bytes; + } + + DCHECK_LE(consumer_num_bytes_, capacity_num_bytes()); + // TODO(vtl): We report |num_bytes_to_write|, instead of |offset|, even if we + // failed at some point. This is consistent with the idea that writes either + // "succeed" or "fail" (and since some bytes may have been sent, we opt for + // "succeed"). Think about this some more. + num_bytes.Put(static_cast<uint32_t>(num_bytes_to_write)); + return MOJO_RESULT_OK; +} + +MojoResult RemoteConsumerDataPipeImpl::ProducerBeginWriteData( + UserPointer<void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, + uint32_t min_num_bytes_to_write) { + DCHECK(consumer_open()); + DCHECK(channel_endpoint_); + + DCHECK_LE(consumer_num_bytes_, capacity_num_bytes()); + DCHECK_EQ(consumer_num_bytes_ % element_num_bytes(), 0u); + + size_t max_num_bytes_to_write = capacity_num_bytes() - consumer_num_bytes_; + if (min_num_bytes_to_write > max_num_bytes_to_write) { + // Don't return "should wait" since you can't wait for a specified amount + // of data. + return MOJO_RESULT_OUT_OF_RANGE; + } + + // Don't go into a two-phase write if there's no room. + if (max_num_bytes_to_write == 0) + return MOJO_RESULT_SHOULD_WAIT; + + EnsureBuffer(); + buffer.Put(buffer_.get()); + buffer_num_bytes.Put(static_cast<uint32_t>(max_num_bytes_to_write)); + set_producer_two_phase_max_num_bytes_written( + static_cast<uint32_t>(max_num_bytes_to_write)); + return MOJO_RESULT_OK; +} + +MojoResult RemoteConsumerDataPipeImpl::ProducerEndWriteData( + uint32_t num_bytes_written) { + DCHECK_LE(num_bytes_written, producer_two_phase_max_num_bytes_written()); + DCHECK_EQ(num_bytes_written % element_num_bytes(), 0u); + DCHECK_LE(num_bytes_written, capacity_num_bytes() - consumer_num_bytes_); + + // TODO(vtl): The following code is copied almost verbatim from + // |ProducerWriteData()| (it's touchy to factor it out since it uses a + // |UserPointer| while we have a plain pointer. + + // The maximum amount of data to send per message (make it a multiple of the + // element size. + // TODO(vtl): Copied from |LocalDataPipeImpl::ConvertDataToMessages()|. + size_t max_message_num_bytes = GetConfiguration().max_message_num_bytes; + max_message_num_bytes -= max_message_num_bytes % element_num_bytes(); + DCHECK_GT(max_message_num_bytes, 0u); + + size_t offset = 0; + while (offset < num_bytes_written) { + size_t message_num_bytes = + std::min(max_message_num_bytes, num_bytes_written - offset); + scoped_ptr<MessageInTransit> message(new MessageInTransit( + MessageInTransit::kTypeEndpoint, MessageInTransit::kSubtypeEndpointData, + static_cast<uint32_t>(message_num_bytes), buffer_.get() + offset)); + if (!channel_endpoint_->EnqueueMessage(message.Pass())) { + Disconnect(); + break; + } + + offset += message_num_bytes; + consumer_num_bytes_ += message_num_bytes; + } + + DCHECK_LE(consumer_num_bytes_, capacity_num_bytes()); + // TODO(vtl): (End of copied code.) + + set_producer_two_phase_max_num_bytes_written(0); + return MOJO_RESULT_OK; +} + +HandleSignalsState RemoteConsumerDataPipeImpl::ProducerGetHandleSignalsState() + const { + HandleSignalsState rv; + if (consumer_open()) { + if (consumer_num_bytes_ < capacity_num_bytes() && + !producer_in_two_phase_write()) + 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; +} + +void RemoteConsumerDataPipeImpl::ProducerStartSerialize( + Channel* channel, + size_t* max_size, + size_t* max_platform_handles) { + *max_size = sizeof(SerializedDataPipeProducerDispatcher) + + channel->GetSerializedEndpointSize(); + *max_platform_handles = 0; +} + +bool RemoteConsumerDataPipeImpl::ProducerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) { + SerializedDataPipeProducerDispatcher* s = + static_cast<SerializedDataPipeProducerDispatcher*>(destination); + s->validated_options = validated_options(); + void* destination_for_endpoint = static_cast<char*>(destination) + + sizeof(SerializedDataPipeProducerDispatcher); + + if (!consumer_open()) { + // Case 1: The consumer is closed. + s->consumer_num_bytes = static_cast<size_t>(-1); + *actual_size = sizeof(SerializedDataPipeProducerDispatcher); + return true; + } + + // Case 2: The consumer isn't closed. We pass |channel_endpoint| back to the + // |Channel|. There's no reason for us to continue to exist afterwards. + + s->consumer_num_bytes = consumer_num_bytes_; + // Note: We don't use |port|. + scoped_refptr<ChannelEndpoint> channel_endpoint; + channel_endpoint.swap(channel_endpoint_); + channel->SerializeEndpointWithRemotePeer(destination_for_endpoint, nullptr, + channel_endpoint); + owner()->SetConsumerClosedNoLock(); + + *actual_size = sizeof(SerializedDataPipeProducerDispatcher) + + channel->GetSerializedEndpointSize(); + return true; +} + +void RemoteConsumerDataPipeImpl::ConsumerClose() { + NOTREACHED(); +} + +MojoResult RemoteConsumerDataPipeImpl::ConsumerReadData( + UserPointer<void> /*elements*/, + UserPointer<uint32_t> /*num_bytes*/, + uint32_t /*max_num_bytes_to_read*/, + uint32_t /*min_num_bytes_to_read*/, + bool /*peek*/) { + NOTREACHED(); + return MOJO_RESULT_INTERNAL; +} + +MojoResult RemoteConsumerDataPipeImpl::ConsumerDiscardData( + UserPointer<uint32_t> /*num_bytes*/, + uint32_t /*max_num_bytes_to_discard*/, + uint32_t /*min_num_bytes_to_discard*/) { + NOTREACHED(); + return MOJO_RESULT_INTERNAL; +} + +MojoResult RemoteConsumerDataPipeImpl::ConsumerQueryData( + UserPointer<uint32_t> /*num_bytes*/) { + NOTREACHED(); + return MOJO_RESULT_INTERNAL; +} + +MojoResult RemoteConsumerDataPipeImpl::ConsumerBeginReadData( + UserPointer<const void*> /*buffer*/, + UserPointer<uint32_t> /*buffer_num_bytes*/, + uint32_t /*min_num_bytes_to_read*/) { + NOTREACHED(); + return MOJO_RESULT_INTERNAL; +} + +MojoResult RemoteConsumerDataPipeImpl::ConsumerEndReadData( + uint32_t /*num_bytes_read*/) { + NOTREACHED(); + return MOJO_RESULT_INTERNAL; +} + +HandleSignalsState RemoteConsumerDataPipeImpl::ConsumerGetHandleSignalsState() + const { + return HandleSignalsState(); +} + +void RemoteConsumerDataPipeImpl::ConsumerStartSerialize( + Channel* /*channel*/, + size_t* /*max_size*/, + size_t* /*max_platform_handles*/) { + NOTREACHED(); +} + +bool RemoteConsumerDataPipeImpl::ConsumerEndSerialize( + Channel* /*channel*/, + void* /*destination*/, + size_t* /*actual_size*/, + embedder::PlatformHandleVector* /*platform_handles*/) { + NOTREACHED(); + return false; +} + +bool RemoteConsumerDataPipeImpl::OnReadMessage(unsigned /*port*/, + MessageInTransit* message) { + // Always take ownership of the message. (This means that we should always + // return true.) + scoped_ptr<MessageInTransit> msg(message); + + if (!ValidateIncomingMessage(element_num_bytes(), capacity_num_bytes(), + consumer_num_bytes_, msg.get())) { + Disconnect(); + return true; + } + + const RemoteDataPipeAck* ack = + static_cast<const RemoteDataPipeAck*>(msg->bytes()); + size_t num_bytes_consumed = ack->num_bytes_consumed; + consumer_num_bytes_ -= num_bytes_consumed; + return true; +} + +void RemoteConsumerDataPipeImpl::OnDetachFromChannel(unsigned /*port*/) { + if (!consumer_open()) { + DCHECK(!channel_endpoint_); + return; + } + + Disconnect(); +} + +void RemoteConsumerDataPipeImpl::EnsureBuffer() { + DCHECK(producer_open()); + if (buffer_) + return; + buffer_.reset(static_cast<char*>( + base::AlignedAlloc(capacity_num_bytes(), + GetConfiguration().data_pipe_buffer_alignment_bytes))); +} + +void RemoteConsumerDataPipeImpl::DestroyBuffer() { +#ifndef NDEBUG + // Scribble on the buffer to help detect use-after-frees. (This also helps the + // unit test detect certain bugs without needing ASAN or similar.) + if (buffer_) + memset(buffer_.get(), 0xcd, capacity_num_bytes()); +#endif + buffer_.reset(); +} + +void RemoteConsumerDataPipeImpl::Disconnect() { + DCHECK(consumer_open()); + DCHECK(channel_endpoint_); + owner()->SetConsumerClosedNoLock(); + channel_endpoint_->DetachFromClient(); + channel_endpoint_ = nullptr; + DestroyBuffer(); +} + +} // namespace system +} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/remote_consumer_data_pipe_impl.h b/third_party/mojo/src/mojo/edk/system/remote_consumer_data_pipe_impl.h new file mode 100644 index 0000000..68e856c9 --- /dev/null +++ b/third_party/mojo/src/mojo/edk/system/remote_consumer_data_pipe_impl.h
@@ -0,0 +1,107 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_EDK_SYSTEM_REMOTE_CONSUMER_DATA_PIPE_IMPL_H_ +#define MOJO_EDK_SYSTEM_REMOTE_CONSUMER_DATA_PIPE_IMPL_H_ + +#include "base/macros.h" +#include "base/memory/aligned_memory.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/edk/system/channel_endpoint.h" +#include "mojo/edk/system/data_pipe_impl.h" +#include "mojo/edk/system/system_impl_export.h" + +namespace mojo { +namespace system { + +// |RemoteConsumerDataPipeImpl| is a subclass that "implements" |DataPipe| for +// data pipes whose producer is local and whose consumer is remote. See +// |DataPipeImpl| for more details. +class MOJO_SYSTEM_IMPL_EXPORT RemoteConsumerDataPipeImpl : public DataPipeImpl { + public: + RemoteConsumerDataPipeImpl(ChannelEndpoint* channel_endpoint, + size_t consumer_num_bytes); + ~RemoteConsumerDataPipeImpl() override; + + // Processes messages that were received and queued by an |IncomingEndpoint|. + // |*consumer_num_bytes| should be set to the value from the + // |SerializedDataPipeProducerDispatcher|. On success, returns true and + // updates |*consumer_num_bytes|. On failure, returns false (it may or may not + // modify |*consumer_num_bytes|). Always clears |*messages|. + static bool ProcessMessagesFromIncomingEndpoint( + const MojoCreateDataPipeOptions& validated_options, + size_t* consumer_num_bytes, + MessageInTransitQueue* messages); + + private: + // |DataPipeImpl| implementation: + // Note: None of the |Consumer...()| methods should be called, except + // |ConsumerGetHandleSignalsState()|. + void ProducerClose() override; + MojoResult ProducerWriteData(UserPointer<const void> elements, + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_write, + uint32_t min_num_bytes_to_write) override; + MojoResult ProducerBeginWriteData(UserPointer<void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, + uint32_t min_num_bytes_to_write) override; + MojoResult ProducerEndWriteData(uint32_t num_bytes_written) override; + HandleSignalsState ProducerGetHandleSignalsState() const override; + void ProducerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) override; + bool ProducerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) override; + void ConsumerClose() override; + MojoResult ConsumerReadData(UserPointer<void> elements, + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_read, + uint32_t min_num_bytes_to_read, + bool peek) override; + MojoResult ConsumerDiscardData(UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_discard, + uint32_t min_num_bytes_to_discard) override; + MojoResult ConsumerQueryData(UserPointer<uint32_t> num_bytes) override; + MojoResult ConsumerBeginReadData(UserPointer<const void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, + uint32_t min_num_bytes_to_read) override; + MojoResult ConsumerEndReadData(uint32_t num_bytes_read) override; + HandleSignalsState ConsumerGetHandleSignalsState() const override; + void ConsumerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) override; + bool ConsumerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) override; + bool OnReadMessage(unsigned port, MessageInTransit* message) override; + void OnDetachFromChannel(unsigned port) override; + + void EnsureBuffer(); + void DestroyBuffer(); + + void Disconnect(); + + // Should be valid if and only if |consumer_open()| returns true. + scoped_refptr<ChannelEndpoint> channel_endpoint_; + + // The number of bytes we've sent the consumer, but don't *know* have been + // consumed. + size_t consumer_num_bytes_; + + // Used for two-phase writes. + scoped_ptr<char, base::AlignedFreeDeleter> buffer_; + + DISALLOW_COPY_AND_ASSIGN(RemoteConsumerDataPipeImpl); +}; + +} // namespace system +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_REMOTE_CONSUMER_DATA_PIPE_IMPL_H_
diff --git a/third_party/mojo/src/mojo/edk/system/remote_data_pipe_ack.h b/third_party/mojo/src/mojo/edk/system/remote_data_pipe_ack.h new file mode 100644 index 0000000..5dce2ee --- /dev/null +++ b/third_party/mojo/src/mojo/edk/system/remote_data_pipe_ack.h
@@ -0,0 +1,21 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_EDK_SYSTEM_REMOTE_DATA_PIPE_ACK_H_ +#define MOJO_EDK_SYSTEM_REMOTE_DATA_PIPE_ACK_H_ + +#include <stdint.h> + +namespace mojo { +namespace system { + +// Data payload for |MessageInTransit::kSubtypeEndpointDataPipeAck| messages. +struct RemoteDataPipeAck { + uint32_t num_bytes_consumed; +}; + +} // namespace system +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_REMOTE_DATA_PIPE_ACK_H_
diff --git a/third_party/mojo/src/mojo/edk/system/remote_data_pipe_impl_unittest.cc b/third_party/mojo/src/mojo/edk/system/remote_data_pipe_impl_unittest.cc new file mode 100644 index 0000000..7efd40a8 --- /dev/null +++ b/third_party/mojo/src/mojo/edk/system/remote_data_pipe_impl_unittest.cc
@@ -0,0 +1,282 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file tests both |RemoteProducerDataPipeImpl| and +// |RemoteConsumerDataPipeImpl|. + +#include <stdint.h> + +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/test/test_io_thread.h" +#include "base/test/test_timeouts.h" +#include "mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/edk/embedder/simple_platform_support.h" +#include "mojo/edk/system/channel.h" +#include "mojo/edk/system/channel_endpoint.h" +#include "mojo/edk/system/data_pipe.h" +#include "mojo/edk/system/data_pipe_consumer_dispatcher.h" +#include "mojo/edk/system/data_pipe_producer_dispatcher.h" +#include "mojo/edk/system/memory.h" +#include "mojo/edk/system/message_pipe.h" +#include "mojo/edk/system/raw_channel.h" +#include "mojo/edk/system/test_utils.h" +#include "mojo/edk/system/waiter.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace system { +namespace { + +const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED; + +class RemoteDataPipeImplTest : public testing::Test { + public: + RemoteDataPipeImplTest() : io_thread_(base::TestIOThread::kAutoStart) {} + ~RemoteDataPipeImplTest() override {} + + void SetUp() override { + scoped_refptr<ChannelEndpoint> ep[2]; + message_pipes_[0] = MessagePipe::CreateLocalProxy(&ep[0]); + message_pipes_[1] = MessagePipe::CreateLocalProxy(&ep[1]); + + io_thread_.PostTaskAndWait( + FROM_HERE, base::Bind(&RemoteDataPipeImplTest::SetUpOnIOThread, + base::Unretained(this), ep[0], ep[1])); + } + + void TearDown() override { + EnsureMessagePipeClosed(0); + EnsureMessagePipeClosed(1); + io_thread_.PostTaskAndWait( + FROM_HERE, base::Bind(&RemoteDataPipeImplTest::TearDownOnIOThread, + base::Unretained(this))); + } + + protected: + static DataPipe* CreateLocal(size_t element_size, size_t num_elements) { + const MojoCreateDataPipeOptions options = { + static_cast<uint32_t>(sizeof(MojoCreateDataPipeOptions)), + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, + static_cast<uint32_t>(element_size), + static_cast<uint32_t>(num_elements * element_size)}; + MojoCreateDataPipeOptions validated_options = {}; + CHECK_EQ(DataPipe::ValidateCreateOptions(MakeUserPointer(&options), + &validated_options), + MOJO_RESULT_OK); + return DataPipe::CreateLocal(validated_options); + } + + scoped_refptr<MessagePipe> message_pipe(size_t i) { + return message_pipes_[i]; + } + + void EnsureMessagePipeClosed(size_t i) { + if (!message_pipes_[i]) + return; + message_pipes_[i]->Close(0); + message_pipes_[i] = nullptr; + } + + private: + void SetUpOnIOThread(scoped_refptr<ChannelEndpoint> ep0, + scoped_refptr<ChannelEndpoint> ep1) { + CHECK_EQ(base::MessageLoop::current(), io_thread_.message_loop()); + + embedder::PlatformChannelPair channel_pair; + channels_[0] = new Channel(&platform_support_); + channels_[0]->Init(RawChannel::Create(channel_pair.PassServerHandle())); + channels_[0]->SetBootstrapEndpoint(ep0); + channels_[1] = new Channel(&platform_support_); + channels_[1]->Init(RawChannel::Create(channel_pair.PassClientHandle())); + channels_[1]->SetBootstrapEndpoint(ep1); + } + + void TearDownOnIOThread() { + CHECK_EQ(base::MessageLoop::current(), io_thread_.message_loop()); + + if (channels_[0]) { + channels_[0]->Shutdown(); + channels_[0] = nullptr; + } + if (channels_[1]) { + channels_[1]->Shutdown(); + channels_[1] = nullptr; + } + } + + embedder::SimplePlatformSupport platform_support_; + base::TestIOThread io_thread_; + scoped_refptr<Channel> channels_[2]; + scoped_refptr<MessagePipe> message_pipes_[2]; + + DISALLOW_COPY_AND_ASSIGN(RemoteDataPipeImplTest); +}; + +// These tests are heavier-weight than ideal. They test remote data pipes by +// passing data pipe (producer/consumer) dispatchers over remote message pipes. +// Make sure that the test fixture works properly (i.e., that the message pipe +// works properly, and that things are shut down correctly). +// TODO(vtl): Make lighter-weight tests. Ideally, we'd have tests for remote +// data pipes which don't involve message pipes (or even data pipe dispatchers). +TEST_F(RemoteDataPipeImplTest, Sanity) { + static const char kHello[] = "hello"; + char read_buffer[100] = {}; + uint32_t read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); + Waiter waiter; + HandleSignalsState hss; + uint32_t context = 0; + + // Write on MP 0 (port 0). Wait and receive on MP 1 (port 0). (Add the waiter + // first, to avoid any handling the case where it's already readable.) + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + message_pipe(1)->AddAwakable( + 0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 123, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, + message_pipe(0)->WriteMessage(0, UserPointer<const void>(kHello), + sizeof(kHello), nullptr, + MOJO_WRITE_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context)); + EXPECT_EQ(123u, context); + hss = HandleSignalsState(); + message_pipe(1)->RemoveAwakable(0, &waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, + hss.satisfied_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); + EXPECT_EQ(MOJO_RESULT_OK, message_pipe(1)->ReadMessage( + 0, UserPointer<void>(read_buffer), + MakeUserPointer(&read_buffer_size), nullptr, + nullptr, MOJO_READ_MESSAGE_FLAG_NONE)); + EXPECT_EQ(sizeof(kHello), static_cast<size_t>(read_buffer_size)); + EXPECT_STREQ(kHello, read_buffer); +} + +// TODO(vtl): This test doesn't have an obvious analogue in +// |LocalDataPipeImplTest|. +TEST_F(RemoteDataPipeImplTest, SendConsumerWithClosedProducer) { + char read_buffer[100] = {}; + uint32_t read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); + DispatcherVector read_dispatchers; + uint32_t read_num_dispatchers = 10; // Maximum to get. + Waiter waiter; + HandleSignalsState hss; + uint32_t context = 0; + + scoped_refptr<DataPipe> dp(CreateLocal(sizeof(int32_t), 1000)); + // This is the consumer dispatcher we'll send. + scoped_refptr<DataPipeConsumerDispatcher> consumer = + new DataPipeConsumerDispatcher(); + consumer->Init(dp); + + // Write to the producer and close it, before sending the consumer. + int32_t elements[10] = {123}; + uint32_t num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerWriteData(UserPointer<const void>(elements), + MakeUserPointer(&num_bytes), false)); + EXPECT_EQ(1u * sizeof(elements[0]), num_bytes); + dp->ProducerClose(); + + // Write the consumer to MP 0 (port 0). Wait and receive on MP 1 (port 0). + // (Add the waiter first, to avoid any handling the case where it's already + // readable.) + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + message_pipe(1)->AddAwakable( + 0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 123, nullptr)); + { + DispatcherTransport transport( + test::DispatcherTryStartTransport(consumer.get())); + EXPECT_TRUE(transport.is_valid()); + + std::vector<DispatcherTransport> transports; + transports.push_back(transport); + EXPECT_EQ(MOJO_RESULT_OK, message_pipe(0)->WriteMessage( + 0, NullUserPointer(), 0, &transports, + MOJO_WRITE_MESSAGE_FLAG_NONE)); + transport.End(); + + // |consumer| should have been closed. This is |DCHECK()|ed when it is + // destroyed. + EXPECT_TRUE(consumer->HasOneRef()); + consumer = nullptr; + } + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context)); + EXPECT_EQ(123u, context); + hss = HandleSignalsState(); + message_pipe(1)->RemoveAwakable(0, &waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, + hss.satisfied_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); + EXPECT_EQ(MOJO_RESULT_OK, + message_pipe(1)->ReadMessage( + 0, UserPointer<void>(read_buffer), + MakeUserPointer(&read_buffer_size), &read_dispatchers, + &read_num_dispatchers, MOJO_READ_MESSAGE_FLAG_NONE)); + EXPECT_EQ(0u, static_cast<size_t>(read_buffer_size)); + EXPECT_EQ(1u, read_dispatchers.size()); + EXPECT_EQ(1u, read_num_dispatchers); + ASSERT_TRUE(read_dispatchers[0]); + EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); + + EXPECT_EQ(Dispatcher::kTypeDataPipeConsumer, read_dispatchers[0]->GetType()); + consumer = + static_cast<DataPipeConsumerDispatcher*>(read_dispatchers[0].get()); + read_dispatchers.clear(); + + waiter.Init(); + hss = HandleSignalsState(); + MojoResult result = + consumer->AddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 456, &hss); + if (result == MOJO_RESULT_OK) { + context = 0; + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context)); + EXPECT_EQ(456u, context); + consumer->RemoveAwakable(&waiter, &hss); + } else { + ASSERT_EQ(MOJO_RESULT_ALREADY_EXISTS, result); + } + // We don't know if the fact that the producer has been closed is known yet. + EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); + EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); + + // Read one element. + elements[0] = -1; + elements[1] = -1; + num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); + EXPECT_EQ(MOJO_RESULT_OK, consumer->ReadData(UserPointer<void>(elements), + MakeUserPointer(&num_bytes), + MOJO_READ_DATA_FLAG_NONE)); + EXPECT_EQ(1u * sizeof(elements[0]), num_bytes); + EXPECT_EQ(123, elements[0]); + EXPECT_EQ(-1, elements[1]); + + waiter.Init(); + hss = HandleSignalsState(); + result = + consumer->AddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 789, &hss); + if (result == MOJO_RESULT_OK) { + context = 0; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + waiter.Wait(test::ActionDeadline(), &context)); + EXPECT_EQ(789u, context); + consumer->RemoveAwakable(&waiter, &hss); + } else { + ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + } + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + consumer->Close(); +} + +} // namespace +} // namespace system +} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/remote_producer_data_pipe_impl.cc b/third_party/mojo/src/mojo/edk/system/remote_producer_data_pipe_impl.cc new file mode 100644 index 0000000..7cd2447f --- /dev/null +++ b/third_party/mojo/src/mojo/edk/system/remote_producer_data_pipe_impl.cc
@@ -0,0 +1,475 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/edk/system/remote_producer_data_pipe_impl.h" + +#include <string.h> + +#include <algorithm> + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/edk/system/channel.h" +#include "mojo/edk/system/channel_endpoint.h" +#include "mojo/edk/system/configuration.h" +#include "mojo/edk/system/data_pipe.h" +#include "mojo/edk/system/message_in_transit.h" +#include "mojo/edk/system/message_in_transit_queue.h" +#include "mojo/edk/system/remote_consumer_data_pipe_impl.h" +#include "mojo/edk/system/remote_data_pipe_ack.h" + +namespace mojo { +namespace system { + +namespace { + +bool ValidateIncomingMessage(size_t element_num_bytes, + size_t capacity_num_bytes, + size_t current_num_bytes, + const MessageInTransit* message) { + // We should only receive endpoint messages. + DCHECK_EQ(message->type(), MessageInTransit::kTypeEndpoint); + + // But we should check the subtype; only take data messages. + if (message->subtype() != MessageInTransit::kSubtypeEndpointData) { + LOG(WARNING) << "Received message of unexpected subtype: " + << message->subtype(); + return false; + } + + const size_t num_bytes = message->num_bytes(); + const size_t max_num_bytes = capacity_num_bytes - current_num_bytes; + if (num_bytes > max_num_bytes) { + LOG(WARNING) << "Received too much data: " << num_bytes + << " bytes (maximum: " << max_num_bytes << " bytes)"; + return false; + } + + if (num_bytes % element_num_bytes != 0) { + LOG(WARNING) << "Received data not a multiple of element size: " + << num_bytes << " bytes (element size: " << element_num_bytes + << " bytes)"; + return false; + } + + return true; +} + +} // namespace + +RemoteProducerDataPipeImpl::RemoteProducerDataPipeImpl( + ChannelEndpoint* channel_endpoint) + : channel_endpoint_(channel_endpoint), + start_index_(0), + current_num_bytes_(0) { + // Note: |buffer_| is lazily allocated. +} + +RemoteProducerDataPipeImpl::RemoteProducerDataPipeImpl( + ChannelEndpoint* channel_endpoint, + scoped_ptr<char, base::AlignedFreeDeleter> buffer, + size_t start_index, + size_t current_num_bytes) + : channel_endpoint_(channel_endpoint), + buffer_(buffer.Pass()), + start_index_(start_index), + current_num_bytes_(current_num_bytes) { + DCHECK(buffer_ || !current_num_bytes); +} + +// static +bool RemoteProducerDataPipeImpl::ProcessMessagesFromIncomingEndpoint( + const MojoCreateDataPipeOptions& validated_options, + MessageInTransitQueue* messages, + scoped_ptr<char, base::AlignedFreeDeleter>* buffer, + size_t* buffer_num_bytes) { + DCHECK(!*buffer); // Not wrong, but unlikely. + + const size_t element_num_bytes = validated_options.element_num_bytes; + const size_t capacity_num_bytes = validated_options.capacity_num_bytes; + + scoped_ptr<char, base::AlignedFreeDeleter> new_buffer(static_cast<char*>( + base::AlignedAlloc(capacity_num_bytes, + GetConfiguration().data_pipe_buffer_alignment_bytes))); + + size_t current_num_bytes = 0; + if (messages) { + while (!messages->IsEmpty()) { + scoped_ptr<MessageInTransit> message(messages->GetMessage()); + if (!ValidateIncomingMessage(element_num_bytes, capacity_num_bytes, + current_num_bytes, message.get())) { + messages->Clear(); + return false; + } + + memcpy(new_buffer.get() + current_num_bytes, message->bytes(), + message->num_bytes()); + current_num_bytes += message->num_bytes(); + } + } + + *buffer = new_buffer.Pass(); + *buffer_num_bytes = current_num_bytes; + return true; +} + +RemoteProducerDataPipeImpl::~RemoteProducerDataPipeImpl() { +} + +void RemoteProducerDataPipeImpl::ProducerClose() { + NOTREACHED(); +} + +MojoResult RemoteProducerDataPipeImpl::ProducerWriteData( + UserPointer<const void> /*elements*/, + UserPointer<uint32_t> /*num_bytes*/, + uint32_t /*max_num_bytes_to_write*/, + uint32_t /*min_num_bytes_to_write*/) { + NOTREACHED(); + return MOJO_RESULT_INTERNAL; +} + +MojoResult RemoteProducerDataPipeImpl::ProducerBeginWriteData( + UserPointer<void*> /*buffer*/, + UserPointer<uint32_t> /*buffer_num_bytes*/, + uint32_t /*min_num_bytes_to_write*/) { + NOTREACHED(); + return MOJO_RESULT_INTERNAL; +} + +MojoResult RemoteProducerDataPipeImpl::ProducerEndWriteData( + uint32_t /*num_bytes_written*/) { + NOTREACHED(); + return MOJO_RESULT_INTERNAL; +} + +HandleSignalsState RemoteProducerDataPipeImpl::ProducerGetHandleSignalsState() + const { + return HandleSignalsState(); +} + +void RemoteProducerDataPipeImpl::ProducerStartSerialize( + Channel* /*channel*/, + size_t* /*max_size*/, + size_t* /*max_platform_handles*/) { + NOTREACHED(); +} + +bool RemoteProducerDataPipeImpl::ProducerEndSerialize( + Channel* /*channel*/, + void* /*destination*/, + size_t* /*actual_size*/, + embedder::PlatformHandleVector* /*platform_handles*/) { + NOTREACHED(); + return false; +} + +void RemoteProducerDataPipeImpl::ConsumerClose() { + if (producer_open()) + Disconnect(); + DestroyBuffer(); + current_num_bytes_ = 0; +} + +MojoResult RemoteProducerDataPipeImpl::ConsumerReadData( + UserPointer<void> elements, + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_read, + uint32_t min_num_bytes_to_read, + bool peek) { + DCHECK_EQ(max_num_bytes_to_read % element_num_bytes(), 0u); + DCHECK_EQ(min_num_bytes_to_read % element_num_bytes(), 0u); + DCHECK_GT(max_num_bytes_to_read, 0u); + + if (min_num_bytes_to_read > current_num_bytes_) { + // Don't return "should wait" since you can't wait for a specified amount of + // data. + return producer_open() ? MOJO_RESULT_OUT_OF_RANGE + : MOJO_RESULT_FAILED_PRECONDITION; + } + + size_t num_bytes_to_read = + std::min(static_cast<size_t>(max_num_bytes_to_read), current_num_bytes_); + if (num_bytes_to_read == 0) { + return producer_open() ? MOJO_RESULT_SHOULD_WAIT + : MOJO_RESULT_FAILED_PRECONDITION; + } + + // The amount we can read in our first |memcpy()|. + size_t num_bytes_to_read_first = + std::min(num_bytes_to_read, GetMaxNumBytesToRead()); + elements.PutArray(buffer_.get() + start_index_, num_bytes_to_read_first); + + if (num_bytes_to_read_first < num_bytes_to_read) { + // The "second read index" is zero. + elements.At(num_bytes_to_read_first) + .PutArray(buffer_.get(), num_bytes_to_read - num_bytes_to_read_first); + } + + if (!peek) + MarkDataAsConsumed(num_bytes_to_read); + num_bytes.Put(static_cast<uint32_t>(num_bytes_to_read)); + return MOJO_RESULT_OK; +} + +MojoResult RemoteProducerDataPipeImpl::ConsumerDiscardData( + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_discard, + uint32_t min_num_bytes_to_discard) { + DCHECK_EQ(max_num_bytes_to_discard % element_num_bytes(), 0u); + DCHECK_EQ(min_num_bytes_to_discard % element_num_bytes(), 0u); + DCHECK_GT(max_num_bytes_to_discard, 0u); + + if (min_num_bytes_to_discard > current_num_bytes_) { + // Don't return "should wait" since you can't wait for a specified amount of + // data. + return producer_open() ? MOJO_RESULT_OUT_OF_RANGE + : MOJO_RESULT_FAILED_PRECONDITION; + } + + // Be consistent with other operations; error if no data available. + if (current_num_bytes_ == 0) { + return producer_open() ? MOJO_RESULT_SHOULD_WAIT + : MOJO_RESULT_FAILED_PRECONDITION; + } + + size_t num_bytes_to_discard = std::min( + static_cast<size_t>(max_num_bytes_to_discard), current_num_bytes_); + MarkDataAsConsumed(num_bytes_to_discard); + num_bytes.Put(static_cast<uint32_t>(num_bytes_to_discard)); + return MOJO_RESULT_OK; +} + +MojoResult RemoteProducerDataPipeImpl::ConsumerQueryData( + UserPointer<uint32_t> num_bytes) { + // Note: This cast is safe, since the capacity fits into a |uint32_t|. + num_bytes.Put(static_cast<uint32_t>(current_num_bytes_)); + return MOJO_RESULT_OK; +} + +MojoResult RemoteProducerDataPipeImpl::ConsumerBeginReadData( + UserPointer<const void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, + uint32_t min_num_bytes_to_read) { + size_t max_num_bytes_to_read = GetMaxNumBytesToRead(); + if (min_num_bytes_to_read > max_num_bytes_to_read) { + // Don't return "should wait" since you can't wait for a specified amount of + // data. + return producer_open() ? MOJO_RESULT_OUT_OF_RANGE + : MOJO_RESULT_FAILED_PRECONDITION; + } + + // Don't go into a two-phase read if there's no data. + if (max_num_bytes_to_read == 0) { + return producer_open() ? MOJO_RESULT_SHOULD_WAIT + : MOJO_RESULT_FAILED_PRECONDITION; + } + + buffer.Put(buffer_.get() + start_index_); + buffer_num_bytes.Put(static_cast<uint32_t>(max_num_bytes_to_read)); + set_consumer_two_phase_max_num_bytes_read( + static_cast<uint32_t>(max_num_bytes_to_read)); + return MOJO_RESULT_OK; +} + +MojoResult RemoteProducerDataPipeImpl::ConsumerEndReadData( + uint32_t num_bytes_read) { + DCHECK_LE(num_bytes_read, consumer_two_phase_max_num_bytes_read()); + DCHECK_EQ(num_bytes_read % element_num_bytes(), 0u); + DCHECK_LE(start_index_ + num_bytes_read, capacity_num_bytes()); + MarkDataAsConsumed(num_bytes_read); + set_consumer_two_phase_max_num_bytes_read(0); + return MOJO_RESULT_OK; +} + +HandleSignalsState RemoteProducerDataPipeImpl::ConsumerGetHandleSignalsState() + const { + HandleSignalsState rv; + if (current_num_bytes_ > 0) { + if (!consumer_in_two_phase_read()) + rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_READABLE; + rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; + } else if (producer_open()) { + rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; + } + if (!producer_open()) + rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; + rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; + return rv; +} + +void RemoteProducerDataPipeImpl::ConsumerStartSerialize( + Channel* channel, + size_t* max_size, + size_t* max_platform_handles) { + *max_size = sizeof(SerializedDataPipeConsumerDispatcher) + + channel->GetSerializedEndpointSize(); + *max_platform_handles = 0; +} + +bool RemoteProducerDataPipeImpl::ConsumerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) { + SerializedDataPipeConsumerDispatcher* s = + static_cast<SerializedDataPipeConsumerDispatcher*>(destination); + s->validated_options = validated_options(); + void* destination_for_endpoint = static_cast<char*>(destination) + + sizeof(SerializedDataPipeConsumerDispatcher); + + MessageInTransitQueue message_queue; + ConvertDataToMessages(buffer_.get(), &start_index_, ¤t_num_bytes_, + &message_queue); + + if (!producer_open()) { + // Case 1: The producer is closed. + channel->SerializeEndpointWithClosedPeer(destination_for_endpoint, + &message_queue); + *actual_size = sizeof(SerializedDataPipeConsumerDispatcher) + + channel->GetSerializedEndpointSize(); + return true; + } + + // Case 2: The producer isn't closed. We pass |channel_endpoint| back to the + // |Channel|. There's no reason for us to continue to exist afterwards. + + // Note: We don't use |port|. + scoped_refptr<ChannelEndpoint> channel_endpoint; + channel_endpoint.swap(channel_endpoint_); + channel->SerializeEndpointWithRemotePeer(destination_for_endpoint, + &message_queue, channel_endpoint); + owner()->SetProducerClosedNoLock(); + + *actual_size = sizeof(SerializedDataPipeConsumerDispatcher) + + channel->GetSerializedEndpointSize(); + return true; +} + +bool RemoteProducerDataPipeImpl::OnReadMessage(unsigned /*port*/, + MessageInTransit* message) { + // Always take ownership of the message. (This means that we should always + // return true.) + scoped_ptr<MessageInTransit> msg(message); + + if (!producer_open()) { + DCHECK(!channel_endpoint_); + return true; + } + + if (!ValidateIncomingMessage(element_num_bytes(), capacity_num_bytes(), + current_num_bytes_, msg.get())) { + Disconnect(); + return true; + } + + size_t num_bytes = msg->num_bytes(); + // The amount we can write in our first copy. + size_t num_bytes_to_copy_first = std::min(num_bytes, GetMaxNumBytesToWrite()); + // Do the first (and possibly only) copy. + size_t first_write_index = + (start_index_ + current_num_bytes_) % capacity_num_bytes(); + EnsureBuffer(); + memcpy(buffer_.get() + first_write_index, msg->bytes(), + num_bytes_to_copy_first); + + if (num_bytes_to_copy_first < num_bytes) { + // The "second write index" is zero. + memcpy(buffer_.get(), + static_cast<const char*>(msg->bytes()) + num_bytes_to_copy_first, + num_bytes - num_bytes_to_copy_first); + } + + current_num_bytes_ += num_bytes; + DCHECK_LE(current_num_bytes_, capacity_num_bytes()); + return true; +} + +void RemoteProducerDataPipeImpl::OnDetachFromChannel(unsigned /*port*/) { + if (!producer_open()) { + DCHECK(!channel_endpoint_); + return; + } + + Disconnect(); +} + +void RemoteProducerDataPipeImpl::EnsureBuffer() { + DCHECK(producer_open()); + if (buffer_) + return; + buffer_.reset(static_cast<char*>( + base::AlignedAlloc(capacity_num_bytes(), + GetConfiguration().data_pipe_buffer_alignment_bytes))); +} + +void RemoteProducerDataPipeImpl::DestroyBuffer() { +#ifndef NDEBUG + // Scribble on the buffer to help detect use-after-frees. (This also helps the + // unit test detect certain bugs without needing ASAN or similar.) + if (buffer_) + memset(buffer_.get(), 0xcd, capacity_num_bytes()); +#endif + buffer_.reset(); +} + +size_t RemoteProducerDataPipeImpl::GetMaxNumBytesToWrite() { + size_t next_index = start_index_ + current_num_bytes_; + if (next_index >= capacity_num_bytes()) { + next_index %= capacity_num_bytes(); + DCHECK_GE(start_index_, next_index); + DCHECK_EQ(start_index_ - next_index, + capacity_num_bytes() - current_num_bytes_); + return start_index_ - next_index; + } + return capacity_num_bytes() - next_index; +} + +size_t RemoteProducerDataPipeImpl::GetMaxNumBytesToRead() { + if (start_index_ + current_num_bytes_ > capacity_num_bytes()) + return capacity_num_bytes() - start_index_; + return current_num_bytes_; +} + +void RemoteProducerDataPipeImpl::MarkDataAsConsumed(size_t num_bytes) { + DCHECK_LE(num_bytes, current_num_bytes_); + start_index_ += num_bytes; + start_index_ %= capacity_num_bytes(); + current_num_bytes_ -= num_bytes; + + if (!producer_open()) { + DCHECK(!channel_endpoint_); + return; + } + + RemoteDataPipeAck ack_data = {}; + ack_data.num_bytes_consumed = static_cast<uint32_t>(num_bytes); + scoped_ptr<MessageInTransit> message( + new MessageInTransit(MessageInTransit::kTypeEndpoint, + MessageInTransit::kSubtypeEndpointDataPipeAck, + static_cast<uint32_t>(sizeof(ack_data)), &ack_data)); + if (!channel_endpoint_->EnqueueMessage(message.Pass())) + Disconnect(); +} + +void RemoteProducerDataPipeImpl::Disconnect() { + DCHECK(producer_open()); + DCHECK(channel_endpoint_); + owner()->SetProducerClosedNoLock(); + channel_endpoint_->DetachFromClient(); + channel_endpoint_ = nullptr; + // If the consumer is still open and we still have data, we have to keep the + // buffer around. Currently, we won't free it even if it empties later. (We + // could do this -- requiring a check on every read -- but that seems to be + // optimizing for the uncommon case.) + if (!consumer_open() || !current_num_bytes_) { + // Note: There can only be a two-phase *read* (by the consumer) if we still + // have data. + DCHECK(!consumer_in_two_phase_read()); + DestroyBuffer(); + } +} + +} // namespace system +} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/remote_producer_data_pipe_impl.h b/third_party/mojo/src/mojo/edk/system/remote_producer_data_pipe_impl.h new file mode 100644 index 0000000..77117c58 --- /dev/null +++ b/third_party/mojo/src/mojo/edk/system/remote_producer_data_pipe_impl.h
@@ -0,0 +1,120 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_EDK_SYSTEM_REMOTE_PRODUCER_DATA_PIPE_IMPL_H_ +#define MOJO_EDK_SYSTEM_REMOTE_PRODUCER_DATA_PIPE_IMPL_H_ + +#include "base/macros.h" +#include "base/memory/aligned_memory.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/edk/system/channel_endpoint.h" +#include "mojo/edk/system/data_pipe_impl.h" +#include "mojo/edk/system/system_impl_export.h" + +namespace mojo { +namespace system { + +class MessageInTransitQueue; + +// |RemoteProducerDataPipeImpl| is a subclass that "implements" |DataPipe| for +// data pipes whose producer is remote and whose consumer is local. See +// |DataPipeImpl| for more details. +class MOJO_SYSTEM_IMPL_EXPORT RemoteProducerDataPipeImpl : public DataPipeImpl { + public: + explicit RemoteProducerDataPipeImpl(ChannelEndpoint* channel_endpoint); + RemoteProducerDataPipeImpl(ChannelEndpoint* channel_endpoint, + scoped_ptr<char, base::AlignedFreeDeleter> buffer, + size_t start_index, + size_t current_num_bytes); + ~RemoteProducerDataPipeImpl() override; + + // Processes messages that were received and queued by an |IncomingEndpoint|. + // On success, returns true and sets |*buffer| (to a buffer of size + // |validated_options.capacity_num_bytes|) and |*buffer_num_bytes|. On + // failure, returns false. Always clears |*messages|. + static bool ProcessMessagesFromIncomingEndpoint( + const MojoCreateDataPipeOptions& validated_options, + MessageInTransitQueue* messages, + scoped_ptr<char, base::AlignedFreeDeleter>* buffer, + size_t* buffer_num_bytes); + + private: + // |DataPipeImpl| implementation: + // Note: None of the |Producer...()| methods should be called, except + // |ProducerGetHandleSignalsState()|. + void ProducerClose() override; + MojoResult ProducerWriteData(UserPointer<const void> elements, + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_write, + uint32_t min_num_bytes_to_write) override; + MojoResult ProducerBeginWriteData(UserPointer<void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, + uint32_t min_num_bytes_to_write) override; + MojoResult ProducerEndWriteData(uint32_t num_bytes_written) override; + HandleSignalsState ProducerGetHandleSignalsState() const override; + void ProducerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) override; + bool ProducerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) override; + void ConsumerClose() override; + MojoResult ConsumerReadData(UserPointer<void> elements, + UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_read, + uint32_t min_num_bytes_to_read, + bool peek) override; + MojoResult ConsumerDiscardData(UserPointer<uint32_t> num_bytes, + uint32_t max_num_bytes_to_discard, + uint32_t min_num_bytes_to_discard) override; + MojoResult ConsumerQueryData(UserPointer<uint32_t> num_bytes) override; + MojoResult ConsumerBeginReadData(UserPointer<const void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, + uint32_t min_num_bytes_to_read) override; + MojoResult ConsumerEndReadData(uint32_t num_bytes_read) override; + HandleSignalsState ConsumerGetHandleSignalsState() const override; + void ConsumerStartSerialize(Channel* channel, + size_t* max_size, + size_t* max_platform_handles) override; + bool ConsumerEndSerialize( + Channel* channel, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) override; + bool OnReadMessage(unsigned port, MessageInTransit* message) override; + void OnDetachFromChannel(unsigned port) override; + + void EnsureBuffer(); + void DestroyBuffer(); + + // Get the maximum (single) write/read size right now (in number of elements); + // result fits in a |uint32_t|. + size_t GetMaxNumBytesToWrite(); + size_t GetMaxNumBytesToRead(); + + // Marks the given number of bytes as consumed/discarded. This will send a + // message to the remote producer. |num_bytes| must be no greater than + // |current_num_bytes_|. + void MarkDataAsConsumed(size_t num_bytes); + + void Disconnect(); + + // Should be valid if and only if |producer_open()| returns true. + scoped_refptr<ChannelEndpoint> channel_endpoint_; + + scoped_ptr<char, base::AlignedFreeDeleter> buffer_; + // Circular buffer. + size_t start_index_; + size_t current_num_bytes_; + + DISALLOW_COPY_AND_ASSIGN(RemoteProducerDataPipeImpl); +}; + +} // namespace system +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_REMOTE_PRODUCER_DATA_PIPE_IMPL_H_
diff --git a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc index de8d17f..5ff8e56d 100644 --- a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc +++ b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc
@@ -48,7 +48,6 @@ DCHECK(!private_thread_.message_loop()); delegate_thread_task_runner_ = delegate_thread_task_runner; - AssertOnDelegateThread(); slave_process_delegate_ = slave_process_delegate; CHECK(private_thread_.StartWithOptions( base::Thread::Options(base::MessageLoop::TYPE_IO, 0))); @@ -60,7 +59,7 @@ } void SlaveConnectionManager::Shutdown() { - AssertOnDelegateThread(); + AssertNotOnPrivateThread(); DCHECK(slave_process_delegate_); DCHECK(private_thread_.message_loop()); @@ -294,12 +293,6 @@ base::Unretained(slave_process_delegate_))); } -void SlaveConnectionManager::AssertOnDelegateThread() const { - DCHECK(base::MessageLoop::current()); - DCHECK_EQ(base::MessageLoop::current()->task_runner(), - delegate_thread_task_runner_); -} - void SlaveConnectionManager::AssertNotOnPrivateThread() const { // This should only be called after |Init()| and before |Shutdown()|. (If not, // the subsequent |DCHECK_NE()| is invalid, since the current thread may not
diff --git a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h index 731d9db..3a1bf2e9 100644 --- a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h +++ b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h
@@ -31,10 +31,10 @@ // The |ConnectionManager| implementation for slave processes. // -// Objects of this class may be created and destroyed on any thread. However, -// |Init()| and |Shutdown()| must be called on the "delegate thread". Otherwise, -// its public methods are thread-safe (except that they may not be called from -// its internal, private thread). +// This class is thread-safe (except that no public methods may be called from +// its internal, private thread), with condition that |Init()| be called before +// anything else and |Shutdown()| be called before destruction (and no other +// public methods may be called during/after |Shutdown()|). class MOJO_SYSTEM_IMPL_EXPORT SlaveConnectionManager : public ConnectionManager, public RawChannel::Delegate { @@ -52,10 +52,8 @@ embedder::SlaveProcessDelegate* slave_process_delegate, embedder::ScopedPlatformHandle platform_handle); - // No other methods may be called after this is (or while it is being) called. - void Shutdown(); - // |ConnectionManager| methods: + void Shutdown() override; bool AllowConnect(const ConnectionIdentifier& connection_id) override; bool CancelConnect(const ConnectionIdentifier& connection_id) override; bool Connect(const ConnectionIdentifier& connection_id, @@ -81,11 +79,6 @@ embedder::ScopedPlatformHandleVectorPtr platform_handles) override; void OnError(Error error) override; - // Asserts that the current thread is the delegate thread. (This actually - // checks the current message loop.) - // TODO(vtl): Probably we should actually check the thread. - void AssertOnDelegateThread() const; - // Asserts that the current thread is *not* |private_thread_| (no-op if // DCHECKs are not enabled). This should only be called while // |private_thread_| is alive (i.e., after |Init()| but before |Shutdown()|).
diff --git a/third_party/mojo/src/mojo/edk/system/test_utils.cc b/third_party/mojo/src/mojo/edk/system/test_utils.cc index d43a818..d794781 100644 --- a/third_party/mojo/src/mojo/edk/system/test_utils.cc +++ b/third_party/mojo/src/mojo/edk/system/test_utils.cc
@@ -27,6 +27,16 @@ #endif } +MojoDeadline TinyDeadline() { + return static_cast<MojoDeadline>( + TestTimeouts::tiny_timeout().InMicroseconds()); +} + +MojoDeadline ActionDeadline() { + return static_cast<MojoDeadline>( + TestTimeouts::action_timeout().InMicroseconds()); +} + } // namespace test } // namespace system } // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/test_utils.h b/third_party/mojo/src/mojo/edk/system/test_utils.h index b16c516..fba9c68 100644 --- a/third_party/mojo/src/mojo/edk/system/test_utils.h +++ b/third_party/mojo/src/mojo/edk/system/test_utils.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/time/time.h" +#include "mojo/public/c/system/types.h" namespace mojo { namespace system { @@ -18,6 +19,14 @@ // as possible without causing too much flakiness. base::TimeDelta EpsilonTimeout(); +// |TestTimeouts::tiny_timeout()|, as a |MojoDeadline|. (Expect this to be on +// the order of 100 ms.) +MojoDeadline TinyDeadline(); + +// |TestTimeouts::action_timeout()|, as a |MojoDeadline|.(Expect this to be on +// the order of 10 s.) +MojoDeadline ActionDeadline(); + // Stopwatch ------------------------------------------------------------------- // A simple "stopwatch" for measuring time elapsed from a given starting point.
diff --git a/third_party/mojo/src/mojo/edk/system/unique_identifier.cc b/third_party/mojo/src/mojo/edk/system/unique_identifier.cc index e851e2b0..11e482b 100644 --- a/third_party/mojo/src/mojo/edk/system/unique_identifier.cc +++ b/third_party/mojo/src/mojo/edk/system/unique_identifier.cc
@@ -7,7 +7,7 @@ #include <ostream> #include "base/strings/string_number_conversions.h" -#include "crypto/random.h" +#include "mojo/edk/embedder/platform_support.h" namespace mojo { namespace system { @@ -19,9 +19,10 @@ } // static -UniqueIdentifier UniqueIdentifier::Generate() { +UniqueIdentifier UniqueIdentifier::Generate( + embedder::PlatformSupport* platform_support) { UniqueIdentifier rv; - crypto::RandBytes(rv.data_, sizeof(rv.data_)); + platform_support->GetCryptoRandomBytes(rv.data_, sizeof(rv.data_)); return rv; }
diff --git a/third_party/mojo/src/mojo/edk/system/unique_identifier.h b/third_party/mojo/src/mojo/edk/system/unique_identifier.h index a7f68ba..c9cba88 100644 --- a/third_party/mojo/src/mojo/edk/system/unique_identifier.h +++ b/third_party/mojo/src/mojo/edk/system/unique_identifier.h
@@ -31,6 +31,13 @@ } // BASE_HASH_NAMESPACE namespace mojo { + +namespace embedder { + +class PlatformSupport; + +} // namespace embedder + namespace system { // Declare this before |UniqueIdentifier|, so that it can be friended. @@ -44,7 +51,7 @@ public: // This generates a new identifier. Uniqueness is "guaranteed" (i.e., // probabilistically) for identifiers. - static UniqueIdentifier Generate(); + static UniqueIdentifier Generate(embedder::PlatformSupport* platform_support); bool operator==(const UniqueIdentifier& other) const { return memcmp(data_, other.data_, sizeof(data_)) == 0; @@ -58,7 +65,9 @@ private: friend BASE_HASH_NAMESPACE::hash<mojo::system::UniqueIdentifier>; - friend std::ostream& operator<<(std::ostream&, const UniqueIdentifier&); + friend MOJO_SYSTEM_IMPL_EXPORT std::ostream& operator<<( + std::ostream&, + const UniqueIdentifier&); explicit UniqueIdentifier() {}
diff --git a/third_party/mojo/src/mojo/edk/system/unique_identifier_unittest.cc b/third_party/mojo/src/mojo/edk/system/unique_identifier_unittest.cc index 2be4f6e..5241293 100644 --- a/third_party/mojo/src/mojo/edk/system/unique_identifier_unittest.cc +++ b/third_party/mojo/src/mojo/edk/system/unique_identifier_unittest.cc
@@ -8,21 +8,36 @@ #include <sstream> #include "base/containers/hash_tables.h" +#include "base/macros.h" +#include "mojo/edk/embedder/simple_platform_support.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { namespace system { namespace { -TEST(UniqueIdentifierTest, Basic) { +class UniqueIdentifierTest : public testing::Test { + public: + UniqueIdentifierTest() {} + ~UniqueIdentifierTest() override {} + + embedder::PlatformSupport* platform_support() { return &platform_support_; } + + private: + embedder::SimplePlatformSupport platform_support_; + + DISALLOW_COPY_AND_ASSIGN(UniqueIdentifierTest); +}; + +TEST_F(UniqueIdentifierTest, Basic) { // (This also checks copy constructibility.) - UniqueIdentifier id1 = UniqueIdentifier::Generate(); + UniqueIdentifier id1 = UniqueIdentifier::Generate(platform_support()); EXPECT_EQ(id1, id1); EXPECT_FALSE(id1 != id1); EXPECT_FALSE(id1 < id1); - UniqueIdentifier id2 = UniqueIdentifier::Generate(); + UniqueIdentifier id2 = UniqueIdentifier::Generate(platform_support()); EXPECT_FALSE(id2 == id1); EXPECT_NE(id2, id1); @@ -32,14 +47,14 @@ id2 = id1; } -TEST(UniqueIdentifierTest, Logging) { +TEST_F(UniqueIdentifierTest, Logging) { std::ostringstream oss1; - UniqueIdentifier id1 = UniqueIdentifier::Generate(); + UniqueIdentifier id1 = UniqueIdentifier::Generate(platform_support()); oss1 << id1; EXPECT_FALSE(oss1.str().empty()); std::ostringstream oss2; - UniqueIdentifier id2 = UniqueIdentifier::Generate(); + UniqueIdentifier id2 = UniqueIdentifier::Generate(platform_support()); oss2 << id2; EXPECT_FALSE(oss2.str().empty()); @@ -47,17 +62,17 @@ EXPECT_NE(oss1.str(), oss2.str()); } -TEST(UniqueIdentifierTest, StdSet) { +TEST_F(UniqueIdentifierTest, StdSet) { std::set<UniqueIdentifier> s; EXPECT_TRUE(s.empty()); - UniqueIdentifier id1 = UniqueIdentifier::Generate(); + UniqueIdentifier id1 = UniqueIdentifier::Generate(platform_support()); EXPECT_TRUE(s.find(id1) == s.end()); s.insert(id1); EXPECT_TRUE(s.find(id1) != s.end()); EXPECT_FALSE(s.empty()); - UniqueIdentifier id2 = UniqueIdentifier::Generate(); + UniqueIdentifier id2 = UniqueIdentifier::Generate(platform_support()); EXPECT_TRUE(s.find(id2) == s.end()); s.insert(id2); EXPECT_TRUE(s.find(id2) != s.end()); @@ -74,17 +89,17 @@ EXPECT_TRUE(s.empty()); } -TEST(UniqueIdentifierTest, HashSet) { +TEST_F(UniqueIdentifierTest, HashSet) { base::hash_set<UniqueIdentifier> s; EXPECT_TRUE(s.empty()); - UniqueIdentifier id1 = UniqueIdentifier::Generate(); + UniqueIdentifier id1 = UniqueIdentifier::Generate(platform_support()); EXPECT_TRUE(s.find(id1) == s.end()); s.insert(id1); EXPECT_TRUE(s.find(id1) != s.end()); EXPECT_FALSE(s.empty()); - UniqueIdentifier id2 = UniqueIdentifier::Generate(); + UniqueIdentifier id2 = UniqueIdentifier::Generate(platform_support()); EXPECT_TRUE(s.find(id2) == s.end()); s.insert(id2); EXPECT_TRUE(s.find(id2) != s.end());
diff --git a/third_party/mojo/src/mojo/edk/test/BUILD.gn b/third_party/mojo/src/mojo/edk/test/BUILD.gn index 3a15663..e8f55ad 100644 --- a/third_party/mojo/src/mojo/edk/test/BUILD.gn +++ b/third_party/mojo/src/mojo/edk/test/BUILD.gn
@@ -10,6 +10,8 @@ sources = [ "multiprocess_test_helper.cc", "multiprocess_test_helper.h", + "scoped_ipc_support.cc", + "scoped_ipc_support.h", "test_utils.h", "test_utils_posix.cc", "test_utils_win.cc",
diff --git a/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.cc b/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.cc new file mode 100644 index 0000000..9f3b97d7 --- /dev/null +++ b/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.cc
@@ -0,0 +1,38 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/edk/test/scoped_ipc_support.h" + +#include "base/message_loop/message_loop.h" +#include "mojo/edk/embedder/embedder.h" + +namespace mojo { +namespace test { + +ScopedIPCSupport::ScopedIPCSupport( + scoped_refptr<base::TaskRunner> io_thread_task_runner) + : io_thread_task_runner_(io_thread_task_runner), + event_(true, false) { // Manual reset. + // Note: Run delegate methods on the I/O thread. + embedder::InitIPCSupport(embedder::ProcessType::NONE, io_thread_task_runner, + this, io_thread_task_runner, + embedder::ScopedPlatformHandle()); +} + +ScopedIPCSupport::~ScopedIPCSupport() { + if (base::MessageLoop::current() && + base::MessageLoop::current()->task_runner() == io_thread_task_runner_) { + embedder::ShutdownIPCSupportOnIOThread(); + } else { + embedder::ShutdownIPCSupport(); + event_.Wait(); + } +} + +void ScopedIPCSupport::OnShutdownComplete() { + event_.Signal(); +} + +} // namespace test +} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.h b/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.h new file mode 100644 index 0000000..2569c4e --- /dev/null +++ b/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.h
@@ -0,0 +1,43 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_EDK_TEST_SCOPED_IPC_SUPPORT_H_ +#define MOJO_EDK_TEST_SCOPED_IPC_SUPPORT_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/synchronization/waitable_event.h" +#include "base/task_runner.h" +#include "mojo/edk/embedder/process_delegate.h" + +namespace mojo { +namespace test { + +// A simple class that calls |mojo::embedder::InitIPCSupport()| (with +// |ProcessType::NONE|) on construction and |ShutdownIPCSupport()| on +// destruction (or |ShutdownIPCSupportOnIOThread()| if destroyed on the I/O +// thread). +// TODO(vtl): Need master/slave versions. +class ScopedIPCSupport : public embedder::ProcessDelegate { + public: + ScopedIPCSupport(scoped_refptr<base::TaskRunner> io_thread_task_runner); + ~ScopedIPCSupport() override; + + private: + // ProcessDelegate| implementation: + // Note: Executed on the I/O thread. + void OnShutdownComplete() override; + + scoped_refptr<base::TaskRunner> io_thread_task_runner_; + + // Set after shut down. + base::WaitableEvent event_; + + DISALLOW_COPY_AND_ASSIGN(ScopedIPCSupport); +}; + +} // namespace test +} // namespace mojo + +#endif // MOJO_EDK_TEST_SCOPED_IPC_SUPPORT_H_
diff --git a/third_party/mojo/src/mojo/public/.gitignore b/third_party/mojo/src/mojo/public/.gitignore new file mode 100644 index 0000000..8fb6a7d --- /dev/null +++ b/third_party/mojo/src/mojo/public/.gitignore
@@ -0,0 +1,2 @@ +*.pyc +/tools/prebuilt/
diff --git a/third_party/mojo/src/mojo/public/BUILD.gn b/third_party/mojo/src/mojo/public/BUILD.gn index 33e05c62..ab80674 100644 --- a/third_party/mojo/src/mojo/public/BUILD.gn +++ b/third_party/mojo/src/mojo/public/BUILD.gn
@@ -24,6 +24,7 @@ if (is_android) { deps += [ + "java:application", "java:system", "java:bindings", ]
diff --git a/third_party/mojo/src/mojo/public/LICENSE b/third_party/mojo/src/mojo/public/LICENSE new file mode 100644 index 0000000..972bb2e --- /dev/null +++ b/third_party/mojo/src/mojo/public/LICENSE
@@ -0,0 +1,27 @@ +// Copyright 2014 The Chromium Authors. 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.
diff --git a/third_party/mojo/src/mojo/public/VERSION b/third_party/mojo/src/mojo/public/VERSION index c755f39..cbf7230 100644 --- a/third_party/mojo/src/mojo/public/VERSION +++ b/third_party/mojo/src/mojo/public/VERSION
@@ -1 +1 @@ -1027d24a1f68c6d10b7539b32114f1272b2cc9f1 \ No newline at end of file +f68e697e389943cd9bf9652397312280e96b127a \ No newline at end of file
diff --git a/third_party/mojo/src/mojo/public/c/system/data_pipe.h b/third_party/mojo/src/mojo/public/c/system/data_pipe.h index 86126c1..54cfea8 100644 --- a/third_party/mojo/src/mojo/public/c/system/data_pipe.h +++ b/third_party/mojo/src/mojo/public/c/system/data_pipe.h
@@ -20,9 +20,6 @@ // |MojoCreateDataPipeOptionsFlags flags|: Used to specify different modes of // operation. // |MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE|: No flags; default mode. -// |MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD|: May discard data for -// whatever reason; best-effort delivery. In particular, if the capacity -// is reached, old data may be discard to make room for new data. // |uint32_t element_num_bytes|: The size of an element, in bytes. All // transactions and buffers will consist of an integral number of // elements. Must be nonzero. @@ -37,13 +34,9 @@ #ifdef __cplusplus const MojoCreateDataPipeOptionsFlags MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE = 0; -const MojoCreateDataPipeOptionsFlags - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD = 1 << 0; #else #define MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE \ ((MojoCreateDataPipeOptionsFlags)0) -#define MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD \ - ((MojoCreateDataPipeOptionsFlags)1 << 0) #endif MOJO_STATIC_ASSERT(MOJO_ALIGNOF(int64_t) == 8, "int64_t has weird alignment");
diff --git a/third_party/mojo/src/mojo/public/c/system/tests/core_perftest.cc b/third_party/mojo/src/mojo/public/c/system/tests/core_perftest.cc index 23fd92bc..3ee3015 100644 --- a/third_party/mojo/src/mojo/public/c/system/tests/core_perftest.cc +++ b/third_party/mojo/src/mojo/public/c/system/tests/core_perftest.cc
@@ -7,7 +7,6 @@ #include "mojo/public/c/system/core.h" #include <assert.h> -#include <stddef.h> #include <stdint.h> #include <stdio.h> @@ -37,8 +36,8 @@ // TODO(vtl): Should I throttle somehow? for (;;) { - MojoResult result = MojoWriteMessage( - handle_, buffer, num_bytes_, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE); + MojoResult result = MojoWriteMessage(handle_, buffer, num_bytes_, nullptr, + 0, MOJO_WRITE_MESSAGE_FLAG_NONE); if (result == MOJO_RESULT_OK) { num_writes_++; continue; @@ -74,8 +73,8 @@ for (;;) { uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer)); - MojoResult result = MojoReadMessage( - handle_, buffer, &num_bytes, NULL, NULL, MOJO_READ_MESSAGE_FLAG_NONE); + MojoResult result = MojoReadMessage(handle_, buffer, &num_bytes, nullptr, + nullptr, MOJO_READ_MESSAGE_FLAG_NONE); if (result == MOJO_RESULT_OK) { num_reads_++; continue; @@ -111,14 +110,14 @@ class CorePerftest : public testing::Test { public: - CorePerftest() : buffer_(NULL), num_bytes_(0) {} + CorePerftest() : buffer_(nullptr), num_bytes_(0) {} ~CorePerftest() override {} static void NoOp(void* /*closure*/) {} static void MessagePipe_CreateAndClose(void* closure) { CorePerftest* self = static_cast<CorePerftest*>(closure); - MojoResult result = MojoCreateMessagePipe(NULL, &self->h0_, &self->h1_); + MojoResult result = MojoCreateMessagePipe(nullptr, &self->h0_, &self->h1_); MOJO_ALLOW_UNUSED_LOCAL(result); assert(result == MOJO_RESULT_OK); result = MojoClose(self->h0_); @@ -129,21 +128,22 @@ static void MessagePipe_WriteAndRead(void* closure) { CorePerftest* self = static_cast<CorePerftest*>(closure); - MojoResult result = MojoWriteMessage(self->h0_, self->buffer_, - self->num_bytes_, NULL, 0, - MOJO_WRITE_MESSAGE_FLAG_NONE); + MojoResult result = + MojoWriteMessage(self->h0_, self->buffer_, self->num_bytes_, nullptr, 0, + MOJO_WRITE_MESSAGE_FLAG_NONE); MOJO_ALLOW_UNUSED_LOCAL(result); assert(result == MOJO_RESULT_OK); uint32_t read_bytes = self->num_bytes_; - result = MojoReadMessage(self->h1_, self->buffer_, &read_bytes, NULL, NULL, - MOJO_READ_MESSAGE_FLAG_NONE); + result = MojoReadMessage(self->h1_, self->buffer_, &read_bytes, nullptr, + nullptr, MOJO_READ_MESSAGE_FLAG_NONE); assert(result == MOJO_RESULT_OK); } static void MessagePipe_EmptyRead(void* closure) { CorePerftest* self = static_cast<CorePerftest*>(closure); - MojoResult result = MojoReadMessage(self->h0_, NULL, NULL, NULL, NULL, - MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); + MojoResult result = + MojoReadMessage(self->h0_, nullptr, nullptr, nullptr, nullptr, + MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); MOJO_ALLOW_UNUSED_LOCAL(result); assert(result == MOJO_RESULT_SHOULD_WAIT); } @@ -158,7 +158,7 @@ assert(num_writers > 0); assert(num_readers > 0); - MojoResult result = MojoCreateMessagePipe(NULL, &h0_, &h1_); + MojoResult result = MojoCreateMessagePipe(nullptr, &h0_, &h1_); MOJO_ALLOW_UNUSED_LOCAL(result); assert(result == MOJO_RESULT_OK); @@ -239,7 +239,7 @@ static_cast<time_t>(microseconds / 1000000), // Seconds. static_cast<long>(microseconds % 1000000) * 1000L // Nanoseconds. }; - int rv = nanosleep(&req, NULL); + int rv = nanosleep(&req, nullptr); MOJO_ALLOW_UNUSED_LOCAL(rv); assert(rv == 0); } @@ -261,7 +261,7 @@ } TEST_F(CorePerftest, MessagePipe_WriteAndRead) { - MojoResult result = MojoCreateMessagePipe(NULL, &h0_, &h1_); + MojoResult result = MojoCreateMessagePipe(nullptr, &h0_, &h1_); MOJO_ALLOW_UNUSED_LOCAL(result); assert(result == MOJO_RESULT_OK); char buffer[10000] = {0}; @@ -289,7 +289,7 @@ } TEST_F(CorePerftest, MessagePipe_EmptyRead) { - MojoResult result = MojoCreateMessagePipe(NULL, &h0_, &h1_); + MojoResult result = MojoCreateMessagePipe(nullptr, &h0_, &h1_); MOJO_ALLOW_UNUSED_LOCAL(result); assert(result == MOJO_RESULT_OK); mojo::test::IterateAndReportPerf("MessagePipe_EmptyRead", nullptr,
diff --git a/third_party/mojo/src/mojo/public/c/system/tests/core_unittest.cc b/third_party/mojo/src/mojo/public/c/system/tests/core_unittest.cc index 71e61f4..de59a70f 100644 --- a/third_party/mojo/src/mojo/public/c/system/tests/core_unittest.cc +++ b/third_party/mojo/src/mojo/public/c/system/tests/core_unittest.cc
@@ -40,29 +40,30 @@ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(MOJO_HANDLE_INVALID)); // Wait: - EXPECT_EQ( - MOJO_RESULT_INVALID_ARGUMENT, - MojoWait(MOJO_HANDLE_INVALID, ~MOJO_HANDLE_SIGNAL_NONE, 1000000, NULL)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoWait(MOJO_HANDLE_INVALID, ~MOJO_HANDLE_SIGNAL_NONE, 1000000, + nullptr)); h0 = MOJO_HANDLE_INVALID; sig = ~MOJO_HANDLE_SIGNAL_NONE; - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoWaitMany(&h0, &sig, 1, MOJO_DEADLINE_INDEFINITE, NULL, NULL)); - - // Message pipe: EXPECT_EQ( MOJO_RESULT_INVALID_ARGUMENT, - MojoWriteMessage(h0, buffer, 3, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); + MojoWaitMany(&h0, &sig, 1, MOJO_DEADLINE_INDEFINITE, nullptr, nullptr)); + + // Message pipe: + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoWriteMessage(h0, buffer, 3, nullptr, 0, + MOJO_WRITE_MESSAGE_FLAG_NONE)); buffer_size = static_cast<uint32_t>(sizeof(buffer)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoReadMessage(h0, buffer, &buffer_size, NULL, NULL, + MojoReadMessage(h0, buffer, &buffer_size, nullptr, nullptr, MOJO_READ_MESSAGE_FLAG_NONE)); // Data pipe: buffer_size = static_cast<uint32_t>(sizeof(buffer)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoWriteData(h0, buffer, &buffer_size, MOJO_WRITE_DATA_FLAG_NONE)); - write_pointer = NULL; + write_pointer = nullptr; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoBeginWriteData(h0, &write_pointer, &buffer_size, MOJO_WRITE_DATA_FLAG_NONE)); @@ -70,7 +71,7 @@ buffer_size = static_cast<uint32_t>(sizeof(buffer)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoReadData(h0, buffer, &buffer_size, MOJO_READ_DATA_FLAG_NONE)); - read_pointer = NULL; + read_pointer = nullptr; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoBeginReadData(h0, &read_pointer, &buffer_size, MOJO_READ_DATA_FLAG_NONE)); @@ -79,7 +80,7 @@ // Shared buffer: h1 = MOJO_HANDLE_INVALID; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoDuplicateBufferHandle(h0, NULL, &h1)); + MojoDuplicateBufferHandle(h0, nullptr, &h1)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoMapBuffer(h0, 0, 1, &write_pointer, MOJO_MAP_BUFFER_FLAG_NONE)); } @@ -92,7 +93,7 @@ h0 = MOJO_HANDLE_INVALID; h1 = MOJO_HANDLE_INVALID; - EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(NULL, &h0, &h1)); + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &h0, &h1)); EXPECT_NE(h0, MOJO_HANDLE_INVALID); EXPECT_NE(h1, MOJO_HANDLE_INVALID); @@ -110,19 +111,20 @@ EXPECT_EQ(kSignalAll, state.satisfiable_signals); // Last parameter is optional. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(h0, MOJO_HANDLE_SIGNAL_WRITABLE, 0, NULL)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWait(h0, MOJO_HANDLE_SIGNAL_WRITABLE, 0, nullptr)); // Try to read. buffer_size = static_cast<uint32_t>(sizeof(buffer)); EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, - MojoReadMessage(h0, buffer, &buffer_size, NULL, NULL, + MojoReadMessage(h0, buffer, &buffer_size, nullptr, nullptr, MOJO_READ_MESSAGE_FLAG_NONE)); // Write to |h1|. static const char kHello[] = "hello"; buffer_size = static_cast<uint32_t>(sizeof(kHello)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWriteMessage(h1, kHello, buffer_size, NULL, 0, - MOJO_WRITE_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWriteMessage(h1, kHello, buffer_size, nullptr, + 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); // |h0| should be readable. uint32_t result_index = 1; @@ -137,8 +139,9 @@ // Read from |h0|. buffer_size = static_cast<uint32_t>(sizeof(buffer)); - EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(h0, buffer, &buffer_size, NULL, - NULL, MOJO_READ_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoReadMessage(h0, buffer, &buffer_size, nullptr, nullptr, + MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(static_cast<uint32_t>(sizeof(kHello)), buffer_size); EXPECT_STREQ(kHello, buffer); @@ -183,7 +186,7 @@ hp = MOJO_HANDLE_INVALID; hc = MOJO_HANDLE_INVALID; - EXPECT_EQ(MOJO_RESULT_OK, MojoCreateDataPipe(NULL, &hp, &hc)); + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateDataPipe(nullptr, &hp, &hc)); EXPECT_NE(hp, MOJO_HANDLE_INVALID); EXPECT_NE(hc, MOJO_HANDLE_INVALID); @@ -210,7 +213,7 @@ MojoReadData(hc, buffer, &buffer_size, MOJO_READ_DATA_FLAG_NONE)); // Try to begin a two-phase read from |hc|. - read_pointer = NULL; + read_pointer = nullptr; EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, MojoBeginReadData(hc, &read_pointer, &buffer_size, MOJO_READ_DATA_FLAG_NONE)); @@ -263,7 +266,7 @@ state.satisfiable_signals); // Do a two-phase read from |hc|. - read_pointer = NULL; + read_pointer = nullptr; EXPECT_EQ(MOJO_RESULT_OK, MojoBeginReadData(hc, &read_pointer, &buffer_size, MOJO_READ_DATA_FLAG_NONE)); ASSERT_LE(buffer_size, sizeof(buffer) - 1); @@ -290,11 +293,11 @@ // Create a shared buffer (|h0|). h0 = MOJO_HANDLE_INVALID; - EXPECT_EQ(MOJO_RESULT_OK, MojoCreateSharedBuffer(NULL, 100, &h0)); + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateSharedBuffer(nullptr, 100, &h0)); EXPECT_NE(h0, MOJO_HANDLE_INVALID); // Map everything. - pointer = NULL; + pointer = nullptr; EXPECT_EQ(MOJO_RESULT_OK, MojoMapBuffer(h0, 0, 100, &pointer, MOJO_MAP_BUFFER_FLAG_NONE)); ASSERT_TRUE(pointer); @@ -302,7 +305,7 @@ // Duplicate |h0| to |h1|. h1 = MOJO_HANDLE_INVALID; - EXPECT_EQ(MOJO_RESULT_OK, MojoDuplicateBufferHandle(h0, NULL, &h1)); + EXPECT_EQ(MOJO_RESULT_OK, MojoDuplicateBufferHandle(h0, nullptr, &h1)); EXPECT_NE(h1, MOJO_HANDLE_INVALID); // Close |h0|. @@ -315,7 +318,7 @@ EXPECT_EQ(MOJO_RESULT_OK, MojoUnmapBuffer(pointer)); // Map half of |h1|. - pointer = NULL; + pointer = nullptr; EXPECT_EQ(MOJO_RESULT_OK, MojoMapBuffer(h1, 50, 50, &pointer, MOJO_MAP_BUFFER_FLAG_NONE)); ASSERT_TRUE(pointer); @@ -336,7 +339,7 @@ // This checks that things actually work in C (not C++). TEST(CoreTest, MinimalCTest) { const char* failure = MinimalCTest(); - EXPECT_TRUE(failure == NULL) << failure; + EXPECT_FALSE(failure) << failure; } // TODO(vtl): Add multi-threaded tests.
diff --git a/third_party/mojo/src/mojo/public/c/system/tests/core_unittest_pure_c.c b/third_party/mojo/src/mojo/public/c/system/tests/core_unittest_pure_c.c index fd4d9e9..d5978a9 100644 --- a/third_party/mojo/src/mojo/public/c/system/tests/core_unittest_pure_c.c +++ b/third_party/mojo/src/mojo/public/c/system/tests/core_unittest_pure_c.c
@@ -53,10 +53,9 @@ handle0 = MOJO_HANDLE_INVALID; EXPECT_NE(MOJO_RESULT_OK, MojoClose(handle0)); - EXPECT_EQ( - MOJO_RESULT_INVALID_ARGUMENT, - MojoWait(handle0, ~MOJO_HANDLE_SIGNAL_NONE, MOJO_DEADLINE_INDEFINITE, - NULL)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoWait(handle0, ~MOJO_HANDLE_SIGNAL_NONE, + MOJO_DEADLINE_INDEFINITE, NULL)); handle1 = MOJO_HANDLE_INVALID; EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(NULL, &handle0, &handle1)); @@ -72,37 +71,26 @@ EXPECT_EQ(123u, result_index); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, states[0].satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE | - MOJO_HANDLE_SIGNAL_PEER_CLOSED, + MOJO_HANDLE_SIGNAL_PEER_CLOSED, states[0].satisfiable_signals); EXPECT_EQ(MOJO_RESULT_OK, - MojoWriteMessage(handle0, - kHello, - (uint32_t)sizeof(kHello), - NULL, - 0u, - MOJO_WRITE_DATA_FLAG_NONE)); + MojoWriteMessage(handle0, kHello, (uint32_t)sizeof(kHello), NULL, + 0u, MOJO_WRITE_DATA_FLAG_NONE)); struct MojoHandleSignalsState state; - EXPECT_EQ( - MOJO_RESULT_OK, - MojoWait(handle1, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, &state)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWait(handle1, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE | - MOJO_HANDLE_SIGNAL_PEER_CLOSED, + MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals); num_bytes = (uint32_t)sizeof(buffer); - EXPECT_EQ(MOJO_RESULT_OK, - MojoReadMessage(handle1, - buffer, - &num_bytes, - NULL, - NULL, - MOJO_READ_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(handle1, buffer, &num_bytes, NULL, + NULL, MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ((uint32_t)sizeof(kHello), num_bytes); EXPECT_EQ(0, memcmp(buffer, kHello, sizeof(kHello)));
diff --git a/third_party/mojo/src/mojo/public/cpp/application/BUILD.gn b/third_party/mojo/src/mojo/public/cpp/application/BUILD.gn index d60e99b0..05708c7 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/BUILD.gn +++ b/third_party/mojo/src/mojo/public/cpp/application/BUILD.gn
@@ -11,17 +11,17 @@ "application_delegate.h", "application_impl.h", "connect.h", + "service_provider_impl.h", "interface_factory.h", "interface_factory_impl.h", "lib/application_connection.cc", "lib/application_delegate.cc", "lib/application_impl.cc", + "lib/service_provider_impl.cc", "lib/service_connector.cc", "lib/service_connector.h", - "lib/service_provider_impl.cc", "lib/service_registry.cc", "lib/service_registry.h", - "service_provider_impl.h", ] mojo_sdk_deps = [
diff --git a/third_party/mojo/src/mojo/public/cpp/application/application_connection.h b/third_party/mojo/src/mojo/public/cpp/application/application_connection.h index e461e6c9..8406235 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/application_connection.h +++ b/third_party/mojo/src/mojo/public/cpp/application/application_connection.h
@@ -12,39 +12,40 @@ namespace mojo { -// An instance of this class is passed to -// ApplicationDelegate's ConfigureIncomingConnection() method each time a -// connection is made to this app, and to ApplicationDelegate's -// ConfigureOutgoingConnection() method when the app connects to -// another. +// Represents a connection to another application. An instance of this class is +// passed to ApplicationDelegate's ConfigureIncomingConnection() method each +// time a connection is made to this app, and to ApplicationDelegate's +// ConfigureOutgoingConnection() method when the app connects to another. // -// To use define a class that implements your specific service api, e.g. FooImpl -// to implement a service named Foo. -// That class must subclass an InterfaceImpl specialization. +// To use, define a class that implements your specific service API (e.g., +// FooImpl to implement a service named Foo). Then implement an +// InterfaceFactory<Foo> that binds instances of FooImpl to +// InterfaceRequest<Foo>s and register that on the connection like this: // -// Then implement an InterfaceFactory<Foo> that binds instances of FooImpl to -// InterfaceRequest<Foo>s and register that on the connection. +// connection->AddService(&factory); // -// connection->AddService(&factory); -// -// Or if you have multiple factories implemented by the same type, explicitly +// Or, if you have multiple factories implemented by the same type, explicitly // specify the interface to register the factory for: // -// connection->AddService<Foo>(&my_foo_and_bar_factory_); -// connection->AddService<Bar>(&my_foo_and_bar_factory_); +// connection->AddService<Foo>(&my_foo_and_bar_factory_); +// connection->AddService<Bar>(&my_foo_and_bar_factory_); // // The InterfaceFactory must outlive the ApplicationConnection. class ApplicationConnection { public: virtual ~ApplicationConnection(); + // Makes Interface available as a service to the remote application. + // |factory| will create implementations of Interface on demand. template <typename Interface> void AddService(InterfaceFactory<Interface>* factory) { AddServiceConnector( new internal::InterfaceFactoryConnector<Interface>(factory)); } - // Connect to the service implementing |Interface|. + // Binds |ptr| to an implemention of Interface in the remote application. + // |ptr| can immediately be used to start sending requests to the remote + // service. template <typename Interface> void ConnectToService(InterfacePtr<Interface>* ptr) { if (ServiceProvider* sp = GetServiceProvider()) { @@ -54,10 +55,24 @@ } } - // The url identifying the application on the other end of this connection. + // Returns the URL that was used by the source application to establish a + // connection to the destination application. + // + // When ApplicationConnection is representing an incoming connection this can + // be different than the URL the application was initially loaded from, if the + // application handles multiple URLs. Note that this is the URL after all + // URL rewriting and HTTP redirects have been performed. + // + // When ApplicationConnection is representing and outgoing connection, this + // will be the same as the value returned by GetRemoveApplicationURL(). + virtual const std::string& GetConnectionURL() = 0; + + // Returns the URL identifying the remote application on this connection. virtual const std::string& GetRemoteApplicationURL() = 0; - // Raw ServiceProvider interface to remote application. + // Returns the raw proxy to the remote application's ServiceProvider + // interface. Most applications will just use ConnectToService() instead. + // Caller does not take ownership. virtual ServiceProvider* GetServiceProvider() = 0; private:
diff --git a/third_party/mojo/src/mojo/public/cpp/application/application_delegate.h b/third_party/mojo/src/mojo/public/cpp/application/application_delegate.h index b0f2916..5519f6cd 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/application_delegate.h +++ b/third_party/mojo/src/mojo/public/cpp/application/application_delegate.h
@@ -14,23 +14,30 @@ class ApplicationConnection; class ApplicationImpl; +// An abstract class that the application may subclass to control various +// behaviors of ApplicationImpl. class ApplicationDelegate { public: ApplicationDelegate(); virtual ~ApplicationDelegate(); + // Called exactly once before any other method. virtual void Initialize(ApplicationImpl* app); // Override this method to configure what services a connection supports when // being connected to from an app. - // return false to reject the connection entirely. + // Return false to reject the connection entirely. virtual bool ConfigureIncomingConnection(ApplicationConnection* connection); // Override this method to configure what services a connection supports when // connecting to another app. - // return false to reject the connection entirely. + // Return false to reject the connection entirely. virtual bool ConfigureOutgoingConnection(ApplicationConnection* connection); + // Called before ApplicationImpl::Terminate(). After returning from this call + // the delegate can no longer rely on the main run loop still running. + virtual void Quit(); + private: MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationDelegate); };
diff --git a/third_party/mojo/src/mojo/public/cpp/application/application_impl.h b/third_party/mojo/src/mojo/public/cpp/application/application_impl.h index 46d368d..af85d3e 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/application_impl.h +++ b/third_party/mojo/src/mojo/public/cpp/application/application_impl.h
@@ -7,6 +7,7 @@ #include <vector> #include "mojo/public/cpp/application/application_connection.h" +#include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/application/lib/service_connector.h" #include "mojo/public/cpp/application/lib/service_registry.h" #include "mojo/public/cpp/system/core.h" @@ -15,8 +16,6 @@ namespace mojo { -class ApplicationDelegate; - // Utility class for communicating with the Shell, and providing Services // to clients. // @@ -52,17 +51,28 @@ // class ApplicationImpl : public Application { public: + // Does not take ownership of |delegate|, which must remain valid for the + // lifetime of ApplicationImpl. ApplicationImpl(ApplicationDelegate* delegate, InterfaceRequest<Application> request); ~ApplicationImpl() override; + // The Mojo shell. This will return a valid pointer after Initialize() has + // been invoked. It will remain valid until UnbindConnections() is invoked or + // the ApplicationImpl is destroyed. Shell* shell() const { return shell_.get(); } + const std::string& url() const { return url_; } + // Returns any initial configuration arguments, passed by the Shell. const std::vector<std::string>& args() const { return args_; } bool HasArg(const std::string& arg) const; - // Establishes a new connection to an application. Caller does not own. + // Requests a new connection to an application. Returns a pointer to the + // connection if the connection is permitted by this application's delegate, + // or nullptr otherwise. Caller does not take ownership. The pointer remains + // valid until an error occurs on the connection with the Shell, or until the + // ApplicationImpl is destroyed, whichever occurs first. ApplicationConnection* ConnectToApplication(const String& application_url); // Connect to application identified by |application_url| and connect to the @@ -74,7 +84,9 @@ } // Application implementation. - void Initialize(ShellPtr shell, Array<String> args) override; + void Initialize(ShellPtr shell, + Array<String> args, + const mojo::String& url) override; // Block until the Application is initialized, if it is not already. void WaitForInitialize(); @@ -94,6 +106,7 @@ void ClearConnections(); void OnShellError() { + delegate_->Quit(); ClearConnections(); Terminate(); } @@ -101,7 +114,8 @@ // Application implementation. void AcceptConnection(const String& requestor_url, InterfaceRequest<ServiceProvider> services, - ServiceProviderPtr exposed_services) override; + ServiceProviderPtr exposed_services, + const String& url) override; void RequestQuit() override; @@ -113,6 +127,7 @@ Binding<Application> binding_; ShellPtr shell_; ShellPtrWatcher* shell_watch_; + std::string url_; std::vector<std::string> args_; MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationImpl);
diff --git a/third_party/mojo/src/mojo/public/cpp/application/connect.h b/third_party/mojo/src/mojo/public/cpp/application/connect.h index a41c028..79762e2 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/connect.h +++ b/third_party/mojo/src/mojo/public/cpp/application/connect.h
@@ -9,6 +9,7 @@ namespace mojo { +// Binds |ptr| to a remote implementation of Interface from |service_provider|. template <typename Interface> inline void ConnectToService(ServiceProvider* service_provider, InterfacePtr<Interface>* ptr) {
diff --git a/third_party/mojo/src/mojo/public/cpp/application/lazy_interface_ptr.h b/third_party/mojo/src/mojo/public/cpp/application/lazy_interface_ptr.h index a9b57db..2d58db1 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/lazy_interface_ptr.h +++ b/third_party/mojo/src/mojo/public/cpp/application/lazy_interface_ptr.h
@@ -10,6 +10,8 @@ namespace mojo { +// An InterfacePtr that will request an implementation from a specified +// ServiceProvider when it is first accessed with the get() method. template <typename Interface> class LazyInterfacePtr : public InterfacePtr<Interface> { public:
diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/application_delegate.cc b/third_party/mojo/src/mojo/public/cpp/application/lib/application_delegate.cc index bd6aebd..f1c14af 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/lib/application_delegate.cc +++ b/third_party/mojo/src/mojo/public/cpp/application/lib/application_delegate.cc
@@ -24,4 +24,7 @@ return true; } +void ApplicationDelegate::Quit() { +} + } // namespace mojo
diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc b/third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc index c66dbb5..17678ce 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc +++ b/third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc
@@ -62,7 +62,8 @@ shell_->ConnectToApplication(application_url, GetProxy(&remote_services), local_services.Pass()); internal::ServiceRegistry* registry = new internal::ServiceRegistry( - this, application_url, remote_services.Pass(), local_request.Pass()); + this, application_url, application_url, remote_services.Pass(), + local_request.Pass()); if (!delegate_->ConfigureOutgoingConnection(registry)) { delete registry; return nullptr; @@ -71,10 +72,13 @@ return registry; } -void ApplicationImpl::Initialize(ShellPtr shell, Array<String> args) { +void ApplicationImpl::Initialize(ShellPtr shell, + Array<String> args, + const mojo::String& url) { shell_ = shell.Pass(); shell_watch_ = new ShellPtrWatcher(this); shell_.set_error_handler(shell_watch_); + url_ = url; args_ = args.To<std::vector<std::string>>(); delegate_->Initialize(this); } @@ -94,9 +98,10 @@ void ApplicationImpl::AcceptConnection( const String& requestor_url, InterfaceRequest<ServiceProvider> services, - ServiceProviderPtr exposed_services) { + ServiceProviderPtr exposed_services, + const String& url) { internal::ServiceRegistry* registry = new internal::ServiceRegistry( - this, requestor_url, exposed_services.Pass(), services.Pass()); + this, url, requestor_url, exposed_services.Pass(), services.Pass()); if (!delegate_->ConfigureIncomingConnection(registry)) { delete registry; return; @@ -105,6 +110,7 @@ } void ApplicationImpl::RequestQuit() { + delegate_->Quit(); Terminate(); }
diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc b/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc index ba6dd3f..406c826d 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc +++ b/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc
@@ -47,7 +47,9 @@ private: // Application implementation. - void Initialize(ShellPtr shell, Array<String> args) override { + void Initialize(ShellPtr shell, + Array<String> args, + const mojo::String& url) override { *args_ = args.Pass(); g_application_request = binding_.Unbind(); g_shell = shell.Pass(); @@ -55,7 +57,8 @@ void AcceptConnection(const String& requestor_url, InterfaceRequest<ServiceProvider> services, - ServiceProviderPtr exposed_services) override { + ServiceProviderPtr exposed_services, + const String& url) override { MOJO_CHECK(false); } @@ -137,7 +140,7 @@ g_application_request.Pass()); // Fake application initialization with the given command line arguments. - application_impl_->Initialize(g_shell.Pass(), g_args.Clone()); + application_impl_->Initialize(g_shell.Pass(), g_args.Clone(), ""); } void ApplicationTestBase::TearDown() {
diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/service_provider_impl.cc b/third_party/mojo/src/mojo/public/cpp/application/lib/service_provider_impl.cc index db55710..693169a 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/lib/service_provider_impl.cc +++ b/third_party/mojo/src/mojo/public/cpp/application/lib/service_provider_impl.cc
@@ -24,6 +24,11 @@ binding_.Bind(request.Pass()); } +void ServiceProviderImpl::Close() { + if (binding_.is_bound()) + binding_.Close(); +} + void ServiceProviderImpl::ConnectToService( const String& service_name, ScopedMessagePipeHandle client_handle) {
diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/service_registry.cc b/third_party/mojo/src/mojo/public/cpp/application/lib/service_registry.cc index e0a7d285..337d8e08 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/lib/service_registry.cc +++ b/third_party/mojo/src/mojo/public/cpp/application/lib/service_registry.cc
@@ -13,11 +13,13 @@ ServiceRegistry::ServiceRegistry( ApplicationImpl* application_impl, - const std::string& url, + const std::string& connection_url, + const std::string& remote_url, ServiceProviderPtr remote_services, InterfaceRequest<ServiceProvider> local_services) : application_impl_(application_impl), - url_(url), + connection_url_(connection_url), + remote_url_(remote_url), local_binding_(this), remote_service_provider_(remote_services.Pass()) { if (local_services.is_pending()) @@ -63,8 +65,12 @@ return true; } +const std::string& ServiceRegistry::GetConnectionURL() { + return connection_url_; +} + const std::string& ServiceRegistry::GetRemoteApplicationURL() { - return url_; + return remote_url_; } ServiceProvider* ServiceRegistry::GetServiceProvider() {
diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/service_registry.h b/third_party/mojo/src/mojo/public/cpp/application/lib/service_registry.h index e50c6fc9..6126c104 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/lib/service_registry.h +++ b/third_party/mojo/src/mojo/public/cpp/application/lib/service_registry.h
@@ -24,13 +24,15 @@ public: ServiceRegistry(); ServiceRegistry(ApplicationImpl* application_impl, - const std::string& url, + const std::string& connection_url, + const std::string& remote_url, ServiceProviderPtr remote_services, InterfaceRequest<ServiceProvider> local_services); ~ServiceRegistry() override; // ApplicationConnection overrides. void AddServiceConnector(ServiceConnectorBase* service_connector) override; + const std::string& GetConnectionURL() override; const std::string& GetRemoteApplicationURL() override; ServiceProvider* GetServiceProvider() override; @@ -42,7 +44,8 @@ ScopedMessagePipeHandle client_handle) override; ApplicationImpl* application_impl_; - const std::string url_; + const std::string connection_url_; + const std::string remote_url_; private: bool RemoveServiceConnectorInternal(ServiceConnectorBase* service_connector);
diff --git a/third_party/mojo/src/mojo/public/cpp/application/service_provider_impl.h b/third_party/mojo/src/mojo/public/cpp/application/service_provider_impl.h index a449124f..5ef5854 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/service_provider_impl.h +++ b/third_party/mojo/src/mojo/public/cpp/application/service_provider_impl.h
@@ -22,6 +22,9 @@ ~ServiceProviderImpl() override; void Bind(InterfaceRequest<ServiceProvider> request); + // Disconnect this service provider and put it in a state where it can be + // rebound to a new request. + void Close(); template <typename Interface> void AddService(InterfaceFactory<Interface>* factory) {
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/BUILD.gn b/third_party/mojo/src/mojo/public/cpp/bindings/BUILD.gn index 7a3691a..2dac828 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/BUILD.gn +++ b/third_party/mojo/src/mojo/public/cpp/bindings/BUILD.gn
@@ -9,7 +9,16 @@ "array.h", "binding.h", "error_handler.h", + "interface_ptr_info.h", "interface_ptr.h", + "map.h", + "message.h", + "message_filter.h", + "no_interface.h", + "strong_binding.h", + "string.h", + "struct_ptr.h", + "type_converter.h", "lib/array_internal.cc", "lib/array_internal.h", "lib/array_serialization.h", @@ -46,14 +55,6 @@ "lib/validate_params.h", "lib/validation_errors.cc", "lib/validation_errors.h", - "map.h", - "message.h", - "message_filter.h", - "no_interface.h", - "string.h", - "strong_binding.h", - "struct_ptr.h", - "type_converter.h", ] deps = [ @@ -70,9 +71,9 @@ sources = [ "callback.h", "lib/callback_internal.h", + "lib/template_util.h", "lib/shared_data.h", "lib/shared_ptr.h", - "lib/template_util.h", ] mojo_sdk_deps = [ "mojo/public/cpp/system" ]
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/binding.h b/third_party/mojo/src/mojo/public/cpp/bindings/binding.h index 7b663c43..db5e96d 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/binding.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/binding.h
@@ -58,8 +58,6 @@ template <typename Interface> class Binding : public ErrorHandler { public: - using Client = typename Interface::Client; - // Constructs an incomplete binding that will use the implementation |impl|. // The binding may be completed with a subsequent call to the |Bind| method. // Does not take ownership of |impl|, which must outlive the binding. @@ -102,10 +100,8 @@ // Tears down the binding, closing the message pipe and leaving the interface // implementation unbound. ~Binding() override { - delete proxy_; if (internal_router_) { - internal_router_->set_error_handler(nullptr); - delete internal_router_; + DestroyRouter(); } } @@ -115,17 +111,15 @@ void Bind( ScopedMessagePipeHandle handle, const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + MOJO_DCHECK(!internal_router_); internal::FilterChain filters; filters.Append<internal::MessageHeaderValidator>(); filters.Append<typename Interface::RequestValidator_>(); - filters.Append<typename Client::ResponseValidator_>(); internal_router_ = new internal::Router(handle.Pass(), filters.Pass(), waiter); internal_router_->set_incoming_receiver(&stub_); internal_router_->set_error_handler(this); - - proxy_ = new typename Client::Proxy_(internal_router_); } // Completes a binding that was constructed with only an interface @@ -159,17 +153,23 @@ return internal_router_->WaitForIncomingMessage(); } - // Closes the message pipe that was previously bound. + // Closes the message pipe that was previously bound. Put this object into a + // state where it can be rebound to a new pipe. void Close() { MOJO_DCHECK(internal_router_); internal_router_->CloseMessagePipe(); + DestroyRouter(); } // Unbinds the underlying pipe from this binding and returns it so it can be // used in another context, such as on another thread or with a different - // implementation. + // implementation. Put this object into a state where it can be rebound to a + // new pipe. InterfaceRequest<Interface> Unbind() { - return MakeRequest<Interface>(internal_router_->PassMessagePipe()); + InterfaceRequest<Interface> request = + MakeRequest<Interface>(internal_router_->PassMessagePipe()); + DestroyRouter(); + return request.Pass(); } // Sets an error handler that will be called if a connection error occurs on @@ -188,9 +188,6 @@ // does not take ownership. Interface* impl() { return impl_; } - // Returns the client's interface. - Client* client() { return proxy_; } - // Indicates whether the binding has been completed (i.e., whether a message // pipe has been bound to the implementation). bool is_bound() const { return !!internal_router_; } @@ -199,8 +196,13 @@ internal::Router* internal_router() { return internal_router_; } private: + void DestroyRouter() { + internal_router_->set_error_handler(nullptr); + delete internal_router_; + internal_router_ = nullptr; + } + internal::Router* internal_router_ = nullptr; - typename Client::Proxy_* proxy_ = nullptr; typename Interface::Stub_ stub_; Interface* impl_; ErrorHandler* error_handler_ = nullptr;
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/callback.h b/third_party/mojo/src/mojo/public/cpp/bindings/callback.h index c2ed9557..17d1caf 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/callback.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/callback.h
@@ -38,7 +38,7 @@ // As above, but can take an object that isn't derived from Runnable, so long // as it has a compatible operator() or Run() method. operator() will be - // prefered if the type has both. + // preferred if the type has both. template <typename Sink> Callback(const Sink& sink) { using sink_type = typename internal::Conditional<
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/interface_impl.h b/third_party/mojo/src/mojo/public/cpp/bindings/interface_impl.h index 5663cc3..b5191ef 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/interface_impl.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/interface_impl.h
@@ -21,7 +21,6 @@ class InterfaceImpl : public Interface, public ErrorHandler { public: using ImplementedInterface = Interface; - using Client = typename Interface::Client; InterfaceImpl() : binding_(this), error_handler_impl_(this) { binding_.set_error_handler(&error_handler_impl_); @@ -38,15 +37,12 @@ return binding_.WaitForIncomingMethodCall(); } - Client* client() { return binding_.client(); } internal::Router* internal_router() { return binding_.internal_router(); } // Implements ErrorHandler. // - // Called when the client is no longer connected to this instance. NOTE: The - // client() method continues to return a non-null pointer after this method - // is called. After this method is called, any method calls made on client() - // will be silently ignored. + // Called when the underlying pipe is closed. After this point no more + // calls will be made on Interface and all responses will be silently ignored. void OnConnectionError() override {} void set_delete_on_error(bool delete_on_error) { @@ -159,9 +155,6 @@ // The instance is also bound to the current thread. Its methods will only be // called on the current thread, and if the current thread exits, then it will // also be deleted, and along with it, its end point of the pipe will be closed. -// -// Before returning, the instance will receive a SetClient call, providing it -// with a proxy to the client on the other end of the pipe. template <typename Impl, typename Interface> Impl* BindToRequest( Impl* instance,
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h b/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h index b7f1a4e9..00f1cce 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h
@@ -8,6 +8,7 @@ #include <algorithm> #include "mojo/public/cpp/bindings/error_handler.h" +#include "mojo/public/cpp/bindings/interface_ptr_info.h" #include "mojo/public/cpp/bindings/lib/interface_ptr_internal.h" #include "mojo/public/cpp/environment/environment.h" #include "mojo/public/cpp/system/macros.h" @@ -20,11 +21,6 @@ // closes the pipe and deletes the proxy on destruction. The pointer must be // bound to a message pipe before the interface methods can be called. // -// Can also route incoming calls to a local implementation of the -// Interface::Client interface. To enable this, call the set_client() method. -// Calls to the client interface will originate from the same thread that owns -// this InterfacePtr. -// // This class is thread hostile, as is the local proxy it manages. All calls to // this class or the proxy should be from the same thread that created it. If // you need to move the proxy to a different thread, extract the message pipe @@ -61,15 +57,30 @@ // Closes the bound message pipe (if any) on destruction. ~InterfacePtr() {} - // Binds the InterfacePtr to a message pipe that is connected to a remote - // implementation of Interface. The |waiter| is used for receiving - // notifications when there is data to read from the message pipe. For most - // callers, the default |waiter| will be sufficient. + // Binds the InterfacePtr to a remote implementation of Interface. The + // |waiter| is used for receiving notifications when there is data to read + // from the message pipe. For most callers, the default |waiter| will be + // sufficient. + // + // Calling with an invalid |info| (containing an invalid message pipe handle) + // has the same effect as reset(). In this case, the InterfacePtr is not + // considered as bound. + void Bind( + InterfacePtrInfo<Interface> info, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + reset(); + if (info.is_valid()) + internal_state_.Bind(info.Pass(), waiter); + } + + // Similar to the previous method, but takes a message pipe handle as input. + // + // TODO(yzshen): Remove this method and change call sites to use the other + // Bind(). void Bind( ScopedMessagePipeHandle handle, const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { - reset(); - internal_state_.Bind(handle.Pass(), waiter); + Bind(InterfacePtrInfo<Interface>(handle.Pass(), 0u), waiter); } // Returns a raw pointer to the local proxy. Caller does not take ownership. @@ -80,6 +91,9 @@ Interface* operator->() const { return get(); } Interface& operator*() const { return *get(); } + // Returns the version number of the interface that the remote side supports. + uint32_t version() const { return internal_state_->version(); } + // Closes the bound message pipe (if any) and returns the pointer to the // unbound state. void reset() { @@ -87,23 +101,18 @@ internal_state_.Swap(&doomed); } - // Blocks the current thread until the next incoming call to a client method - // or callback arrives, or until an error occurs. Returns |true| if a call - // arrived, or |false| in case of error. + // Blocks the current thread until the next incoming response callback arrives + // or an error occurs. Returns |true| if a response arrived, or |false| in + // case of error. // // This method may only be called after the InterfacePtr has been bound to a // message pipe. + // + // TODO(jamesr): Rename to WaitForIncomingResponse(). bool WaitForIncomingMethodCall() { return internal_state_.WaitForIncomingMethodCall(); } - // Enables routing of incoming method calls to a local implementation of the - // Interface::Client interface. Calls to |client| will come from the thread - // that owns this InterfacePtr. - void set_client(typename Interface::Client* client) { - internal_state_.set_client(client); - } - // Indicates whether the message pipe has encountered an error. If true, // method calls made on this interface will be dropped (and may already have // been dropped). @@ -118,13 +127,23 @@ internal_state_.set_error_handler(error_handler); } - // Unbinds the InterfacePtr and return the previously bound message pipe (if - // any). This method may be used to move the proxy to a different thread (see - // class comments for details). - ScopedMessagePipeHandle PassMessagePipe() { + // Unbinds the InterfacePtr and returns the information which could be used + // to setup an InterfacePtr again. This method may be used to move the proxy + // to a different thread (see class comments for details). + InterfacePtrInfo<Interface> PassInterface() { State state; internal_state_.Swap(&state); - return state.PassMessagePipe(); + + return state.PassInterface(); + } + + // Similar to the previous method but returns the previously bound message + // pipe (if any). + // + // TODO(yzshen): Remove this method and change call sites to use + // PassInterface(). + ScopedMessagePipeHandle PassMessagePipe() { + return PassInterface().PassHandle(); } // DO NOT USE. Exposed only for internal use and for testing. @@ -151,6 +170,9 @@ // If the specified message pipe handle is valid, returns an InterfacePtr bound // to it. Otherwise, returns an unbound InterfacePtr. The specified |waiter| // will be used as in the InterfacePtr::Bind() method. +// +// TODO(yzshen): Either remove it or change to use InterfacePtrInfo as the first +// parameter. template <typename Interface> InterfacePtr<Interface> MakeProxy( ScopedMessagePipeHandle handle,
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr_info.h b/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr_info.h new file mode 100644 index 0000000..4f61915f --- /dev/null +++ b/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr_info.h
@@ -0,0 +1,58 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_INFO_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_INFO_H_ + +#include "mojo/public/cpp/system/macros.h" +#include "mojo/public/cpp/system/message_pipe.h" + +namespace mojo { + +// InterfacePtrInfo stores necessary information to communicate with a remote +// interface implementation, which could be used to construct an InterfacePtr. +template <typename Interface> +class InterfacePtrInfo { + MOJO_MOVE_ONLY_TYPE(InterfacePtrInfo); + + public: + InterfacePtrInfo() : version_(0u) {} + + InterfacePtrInfo(ScopedMessagePipeHandle handle, uint32_t version) + : handle_(handle.Pass()), version_(version) {} + + InterfacePtrInfo(InterfacePtrInfo&& other) + : handle_(other.handle_.Pass()), version_(other.version_) { + other.version_ = 0u; + } + + ~InterfacePtrInfo() {} + + InterfacePtrInfo& operator=(InterfacePtrInfo&& other) { + if (this != &other) { + handle_ = other.handle_.Pass(); + version_ = other.version_; + other.version_ = 0u; + } + + return *this; + } + + bool is_valid() const { return handle_.is_valid(); } + + ScopedMessagePipeHandle PassHandle() { return handle_.Pass(); } + const ScopedMessagePipeHandle& handle() const { return handle_; } + void set_handle(ScopedMessagePipeHandle handle) { handle_ = handle.Pass(); } + + uint32_t version() const { return version_; } + void set_version(uint32_t version) { version_ = version; } + + private: + ScopedMessagePipeHandle handle_; + uint32_t version_; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_INFO_H_
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/TODO b/third_party/mojo/src/mojo/public/cpp/bindings/lib/TODO index 21bcb6f..ea4ce81 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/TODO +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/TODO
@@ -1,6 +1,4 @@ TODOs: - - Ensure validation checks are solid - - Add tests of validation logic - Optimize Buffer classes? - Add compile-time asserts to verify object packing and padding. - Investigate making arrays of objects not be arrays of pointers.
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_internal.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_internal.h index ec70d37..a8f95b2 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_internal.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_internal.h
@@ -26,7 +26,7 @@ struct StructHeader { uint32_t num_bytes; - uint32_t num_fields; + uint32_t version; }; static_assert(sizeof(StructHeader) == 8, "Bad sizeof(StructHeader)");
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.cc b/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.cc index 936d0ca..6332090 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.cc
@@ -79,12 +79,8 @@ *handle = FetchAndReset(&handles->at(handle->value())); } -bool ValidateStructHeader(const void* data, - uint32_t min_num_bytes, - uint32_t min_num_fields, - BoundsChecker* bounds_checker) { - MOJO_DCHECK(min_num_bytes >= sizeof(StructHeader)); - +bool ValidateStructHeaderAndClaimMemory(const void* data, + BoundsChecker* bounds_checker) { if (!IsAligned(data)) { ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT); return false; @@ -96,11 +92,7 @@ const StructHeader* header = static_cast<const StructHeader*>(data); - // TODO(yzshen): Currently our binding code cannot handle structs of smaller - // size or with fewer fields than the version that it sees. That needs to be - // changed in order to provide backward compatibility. - if (header->num_bytes < min_num_bytes || - header->num_fields < min_num_fields) { + if (header->num_bytes < sizeof(StructHeader)) { ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); return false; }
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.h index 6bebf90b..ceb213d3 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.h
@@ -69,13 +69,15 @@ obj->ptr->DecodePointersAndHandles(handles); } -// If returns true, this function also claims the memory range of the size -// specified in the struct header, starting from |data|. -// Note: |min_num_bytes| must be no less than sizeof(StructHeader). -bool ValidateStructHeader(const void* data, - uint32_t min_num_bytes, - uint32_t min_num_fields, - BoundsChecker* bounds_checker); +// Validates that |data| contains a valid struct header, in terms of alignment +// and size (i.e., the |num_bytes| field of the header is sufficient for storing +// the header itself). Besides, it checks that the memory range +// [data, data + num_bytes) is not marked as occupied by other objects in +// |bounds_checker|. On success, the memory range is marked as occupied. +// Note: Does not verify |version| or that |num_bytes| is correct for the +// claimed version. +bool ValidateStructHeaderAndClaimMemory(const void* data, + BoundsChecker* bounds_checker); } // namespace internal } // namespace mojo
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/interface_ptr_internal.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/interface_ptr_internal.h index a38baf7..a3ed7940 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/interface_ptr_internal.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/interface_ptr_internal.h
@@ -7,6 +7,7 @@ #include <algorithm> // For |std::swap()|. +#include "mojo/public/cpp/bindings/interface_ptr_info.h" #include "mojo/public/cpp/bindings/lib/filter_chain.h" #include "mojo/public/cpp/bindings/lib/message_header_validator.h" #include "mojo/public/cpp/bindings/lib/router.h" @@ -20,12 +21,13 @@ template <typename Interface> class InterfacePtrState { public: - InterfacePtrState() : proxy_(nullptr), router_(nullptr), waiter_(nullptr) {} + InterfacePtrState() + : proxy_(nullptr), router_(nullptr), waiter_(nullptr), version_(0u) {} ~InterfacePtrState() { // Destruction order matters here. We delete |proxy_| first, even though - // |router_| may have a reference to it, so that |~Interface| may have a - // shot at generating new outbound messages (ie, invoking client methods). + // |router_| may have a reference to it, so that destructors for any request + // callbacks still pending can interact with the InterfacePtr. delete proxy_; delete router_; } @@ -37,21 +39,28 @@ return proxy_; } + uint32_t version() const { return version_; } + void Swap(InterfacePtrState* other) { - std::swap(other->proxy_, proxy_); - std::swap(other->router_, router_); + using std::swap; + swap(other->proxy_, proxy_); + swap(other->router_, router_); handle_.swap(other->handle_); - std::swap(other->waiter_, waiter_); + swap(other->waiter_, waiter_); + swap(other->version_, version_); } - void Bind(ScopedMessagePipeHandle handle, const MojoAsyncWaiter* waiter) { + void Bind(InterfacePtrInfo<Interface> info, const MojoAsyncWaiter* waiter) { MOJO_DCHECK(!proxy_); MOJO_DCHECK(!router_); MOJO_DCHECK(!handle_.is_valid()); MOJO_DCHECK(!waiter_); + MOJO_DCHECK(version_ == 0u); + MOJO_DCHECK(info.is_valid()); - handle_ = handle.Pass(); + handle_ = info.PassHandle(); waiter_ = waiter; + version_ = info.version(); } bool WaitForIncomingMethodCall() { @@ -61,23 +70,15 @@ return router_->WaitForIncomingMessage(); } - ScopedMessagePipeHandle PassMessagePipe() { - if (router_) - return router_->PassMessagePipe(); - - waiter_ = nullptr; - return handle_.Pass(); + // After this method is called, the object is in an invalid state and + // shouldn't be reused. + InterfacePtrInfo<Interface> PassInterface() { + return InterfacePtrInfo<Interface>( + router_ ? router_->PassMessagePipe() : handle_.Pass(), version_); } bool is_bound() const { return handle_.is_valid() || router_; } - void set_client(typename Interface::Client* client) { - ConfigureProxyIfNecessary(); - - MOJO_DCHECK(proxy_); - proxy_->stub.set_sink(client); - } - bool encountered_error() const { return router_ ? router_->encountered_error() : false; } @@ -95,15 +96,7 @@ } private: - class ProxyWithStub : public Interface::Proxy_ { - public: - explicit ProxyWithStub(MessageReceiverWithResponder* receiver) - : Interface::Proxy_(receiver) {} - typename Interface::Client::Stub_ stub; - - private: - MOJO_DISALLOW_COPY_AND_ASSIGN(ProxyWithStub); - }; + using Proxy = typename Interface::Proxy_; void ConfigureProxyIfNecessary() { // The proxy has been configured. @@ -119,27 +112,25 @@ FilterChain filters; filters.Append<MessageHeaderValidator>(); - filters.Append<typename Interface::Client::RequestValidator_>(); filters.Append<typename Interface::ResponseValidator_>(); router_ = new Router(handle_.Pass(), filters.Pass(), waiter_); waiter_ = nullptr; - ProxyWithStub* proxy = new ProxyWithStub(router_); - router_->set_incoming_receiver(&proxy->stub); - - proxy_ = proxy; + proxy_ = new Proxy(router_); } - ProxyWithStub* proxy_; + Proxy* proxy_; Router* router_; // |proxy_| and |router_| are not initialized until read/write with the - // message pipe handle is needed. Before that, |handle_| and |waiter_| store - // the arguments of Bind(). + // message pipe handle is needed. |handle_| and |waiter_| are valid between + // the Bind() call and the initialization of |proxy_| and |router_|. ScopedMessagePipeHandle handle_; const MojoAsyncWaiter* waiter_; + uint32_t version_; + MOJO_DISALLOW_COPY_AND_ASSIGN(InterfacePtrState); };
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_data_internal.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_data_internal.h index 7787714..16f6b08 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_data_internal.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_data_internal.h
@@ -44,10 +44,18 @@ if (!data) return true; - if (!ValidateStructHeader(data, sizeof(Map_Data), 2, bounds_checker)) + if (!ValidateStructHeaderAndClaimMemory(data, bounds_checker)) return false; const Map_Data* object = static_cast<const Map_Data*>(data); + // TODO(yzshen): In order to work with other bindings which still interprets + // the |version| field as |num_fields|, |version| is set to 2. + if (object->header_.num_bytes != sizeof(Map_Data) || + object->header_.version != 2) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + if (!ValidateEncodedPointer(&object->keys.offset)) { ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER); return false; @@ -106,7 +114,9 @@ private: Map_Data() { header_.num_bytes = sizeof(*this); - header_.num_fields = 2; + // TODO(yzshen): In order to work with other bindings which still interprets + // the |version| field as |num_fields|, set it to version 2 for now. + header_.version = 2; } ~Map_Data() = delete; };
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_internal.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_internal.h index 8afc18c1..84f927c 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_internal.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_internal.h
@@ -21,7 +21,7 @@ struct MapTraits<Key, Value, false> { // Map keys can't be move only types. static_assert(!internal::IsMoveOnlyType<Key>::value, - "Map keys can not be move only types."); + "Map keys cannot be move only types."); typedef Key KeyStorageType; typedef Key& KeyRefType; @@ -111,7 +111,7 @@ struct MapTraits<Key, Value, true> { // Map keys can't be move only types. static_assert(!internal::IsMoveOnlyType<Key>::value, - "Map keys can not be move only types."); + "Map keys cannot be move only types."); typedef Key KeyStorageType; typedef Key& KeyRefType;
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/message_builder.cc b/third_party/mojo/src/mojo/public/cpp/bindings/lib/message_builder.cc index cc914e8..837ac81 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/message_builder.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/message_builder.cc
@@ -19,7 +19,9 @@ : buf_(sizeof(MessageHeader) + payload_size) { MessageHeader* header; Allocate(&buf_, &header); - header->num_fields = 2; + // TODO(yzshen): In order to work with other bindings which still interprets + // the |version| field as |num_fields|, set it to version 2 for now. + header->version = 2; header->name = name; } @@ -41,7 +43,9 @@ : MessageBuilder(sizeof(MessageHeaderWithRequestID) + payload_size) { MessageHeaderWithRequestID* header; Allocate(&buf_, &header); - header->num_fields = 3; + // TODO(yzshen): In order to work with other bindings which still interprets + // the |version| field as |num_fields|, set it to version 3 for now. + header->version = 3; header->name = name; header->flags = flags; header->request_id = request_id;
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/message_header_validator.cc b/third_party/mojo/src/mojo/public/cpp/bindings/lib/message_header_validator.cc index 9d28ecc0..fdcc365a 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/message_header_validator.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/message_header_validator.cc
@@ -17,17 +17,21 @@ // header. If we encounter fields we do not understand, we must ignore them. // Extra validation of the struct header: - if (header->num_fields == 2) { + if (header->version < 2) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + if (header->version == 2) { if (header->num_bytes != sizeof(MessageHeader)) { ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); return false; } - } else if (header->num_fields == 3) { + } else if (header->version == 3) { if (header->num_bytes != sizeof(MessageHeaderWithRequestID)) { ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); return false; } - } else if (header->num_fields > 3) { + } else if (header->version > 3) { if (header->num_bytes < sizeof(MessageHeaderWithRequestID)) { ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); return false; @@ -37,8 +41,8 @@ // Validate flags (allow unknown bits): // These flags require a RequestID. - if (header->num_fields < 3 && ((header->flags & kMessageExpectsResponse) || - (header->flags & kMessageIsResponse))) { + if (header->version < 3 && ((header->flags & kMessageExpectsResponse) || + (header->flags & kMessageIsResponse))) { ReportValidationError(VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID); return false; } @@ -65,10 +69,8 @@ // if |message| contains handles. BoundsChecker bounds_checker(message->data(), message->data_num_bytes(), 0); - if (!ValidateStructHeader( - message->data(), sizeof(MessageHeader), 2, &bounds_checker)) { + if (!ValidateStructHeaderAndClaimMemory(message->data(), &bounds_checker)) return false; - } if (!IsValidMessageHeader(message->header())) return false;
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_errors.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_errors.h index 4facf6e..fbba6b3 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_errors.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_errors.h
@@ -19,11 +19,11 @@ // objects. VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE, // A struct header doesn't make sense, for example: - // - |num_bytes| is smaller than the size of the oldest version that we - // support. - // - |num_fields| is smaller than the field number of the oldest version that - // we support. - // - |num_bytes| and |num_fields| don't match. + // - |num_bytes| is smaller than the size of the struct header. + // - |num_bytes| and |version| don't match. + // TODO(yzshen): Consider splitting it into two different error codes. Because + // the former indicates someone is misbehaving badly whereas the latter could + // be due to an inappropriately-modified .mojom file. VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER, // An array header doesn't make sense, for example: // - |num_bytes| is smaller than the size of the header plus the size required
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/map.h b/third_party/mojo/src/mojo/public/cpp/bindings/map.h index 8ac183f3..09ca4ad9 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/map.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/map.h
@@ -25,9 +25,9 @@ MOJO_MOVE_ONLY_TYPE(Map) public: - // Map keys can not be move only classes. + // Map keys cannot be move only classes. static_assert(!internal::IsMoveOnlyType<Key>::value, - "Map keys can not be move only types."); + "Map keys cannot be move only types."); typedef internal::MapTraits<Key, Value,
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/message.h b/third_party/mojo/src/mojo/public/cpp/bindings/message.h index 5cab4ea..80cd6d52 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/message.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/message.h
@@ -43,7 +43,7 @@ bool has_flag(uint32_t flag) const { return !!(data_->header.flags & flag); } // Access the request_id field (if present). - bool has_request_id() const { return data_->header.num_fields >= 3; } + bool has_request_id() const { return data_->header.version >= 3; } uint64_t request_id() const { MOJO_DCHECK(has_request_id()); return static_cast<const internal::MessageHeaderWithRequestID*>(
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/no_interface.h b/third_party/mojo/src/mojo/public/cpp/bindings/no_interface.h index 4c35789..d8915cdf 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/no_interface.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/no_interface.h
@@ -12,7 +12,7 @@ namespace mojo { // NoInterface is for use in cases when a non-existent or empty interface is -// needed (e.g., when the Mojom "Peer" attribute is not present). +// needed. class NoInterfaceProxy; class NoInterfaceStub; @@ -24,7 +24,6 @@ typedef NoInterfaceStub Stub_; typedef PassThroughFilter RequestValidator_; typedef PassThroughFilter ResponseValidator_; - typedef NoInterface Client; virtual ~NoInterface() {} };
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h b/third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h index 7caf54a..c891a21f 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h
@@ -108,7 +108,6 @@ } Interface* impl() { return binding_.impl(); } - typename Interface::Client* client() { return binding_.client(); } // Exposed for testing, should not generally be used. internal::Router* internal_router() { return binding_.internal_router(); }
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc b/third_party/mojo/src/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc index 5667f64d..f936361 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/environment/environment.h" #include "mojo/public/cpp/test_support/test_utils.h" #include "mojo/public/cpp/utility/run_loop.h" @@ -24,20 +26,26 @@ std::string* buf_; }; -class ImportedInterfaceImpl - : public InterfaceImpl<imported::ImportedInterface> { +class ImportedInterfaceImpl : public imported::ImportedInterface { public: + explicit ImportedInterfaceImpl( + InterfaceRequest<imported::ImportedInterface> request) + : binding_(this, request.Pass()) {} + void DoSomething() override { do_something_count_++; } static int do_something_count() { return do_something_count_; } private: static int do_something_count_; + Binding<ImportedInterface> binding_; }; int ImportedInterfaceImpl::do_something_count_ = 0; -class SampleNamedObjectImpl : public InterfaceImpl<sample::NamedObject> { +class SampleNamedObjectImpl : public sample::NamedObject { public: + explicit SampleNamedObjectImpl(InterfaceRequest<sample::NamedObject> request) + : binding_(this, request.Pass()) {} void SetName(const mojo::String& name) override { name_ = name; } void GetName(const mojo::Callback<void(mojo::String)>& callback) override { @@ -46,12 +54,17 @@ private: std::string name_; + StrongBinding<sample::NamedObject> binding_; }; -class SampleFactoryImpl : public InterfaceImpl<sample::Factory> { +class SampleFactoryImpl : public sample::Factory { public: + explicit SampleFactoryImpl(InterfaceRequest<sample::Factory> request) + : binding_(this, request.Pass()) {} + void DoStuff(sample::RequestPtr request, - ScopedMessagePipeHandle pipe) override { + ScopedMessagePipeHandle pipe, + const DoStuffCallback& callback) override { std::string text1; if (pipe.is_valid()) EXPECT_TRUE(ReadTextMessage(pipe.get(), &text1)); @@ -73,13 +86,14 @@ sample::ResponsePtr response(sample::Response::New()); response->x = 2; response->pipe = pipe0.Pass(); - client()->DidStuff(response.Pass(), text1); + callback.Run(response.Pass(), text1); if (request->obj) request->obj->DoSomething(); } - void DoStuff2(ScopedDataPipeConsumerHandle pipe) override { + void DoStuff2(ScopedDataPipeConsumerHandle pipe, + const DoStuff2Callback& callback) override { // Read the data from the pipe, writing the response (as a string) to // DidStuff2(). ASSERT_TRUE(pipe.is_valid()); @@ -95,13 +109,13 @@ ReadDataRaw( pipe.get(), data, &data_size, MOJO_READ_DATA_FLAG_ALL_OR_NONE)); - client()->DidStuff2(data); + callback.Run(data); } void CreateNamedObject( InterfaceRequest<sample::NamedObject> object_request) override { EXPECT_TRUE(object_request.is_pending()); - BindToRequest(new SampleNamedObjectImpl(), &object_request); + new SampleNamedObjectImpl(object_request.Pass()); } // These aren't called or implemented, but exist here to test that the @@ -118,21 +132,26 @@ private: ScopedMessagePipeHandle pipe1_; + Binding<sample::Factory> binding_; }; -class SampleFactoryClientImpl : public sample::FactoryClient { +class HandlePassingTest : public testing::Test { public: - SampleFactoryClientImpl() : got_response_(false) {} + void TearDown() override { PumpMessages(); } - void set_expected_text_reply(const std::string& expected_text_reply) { - expected_text_reply_ = expected_text_reply; - } + void PumpMessages() { loop_.RunUntilIdle(); } - bool got_response() const { return got_response_; } + private: + Environment env_; + RunLoop loop_; +}; - void DidStuff(sample::ResponsePtr response, - const String& text_reply) override { - EXPECT_EQ(expected_text_reply_, text_reply); +struct DoStuffCallback { + DoStuffCallback(bool* got_response, std::string* got_text_reply) + : got_response(got_response), got_text_reply(got_text_reply) {} + + void Run(sample::ResponsePtr response, const String& text_reply) const { + *got_text_reply = text_reply; if (response->pipe.is_valid()) { std::string text2; @@ -149,40 +168,16 @@ EXPECT_FALSE(response->pipe.is_valid()); } - got_response_ = true; + *got_response = true; } - void DidStuff2(const String& text_reply) override { - got_response_ = true; - EXPECT_EQ(expected_text_reply_, text_reply); - } - - private: - ScopedMessagePipeHandle pipe1_; - ScopedMessagePipeHandle pipe3_; - std::string expected_text_reply_; - bool got_response_; -}; - -class HandlePassingTest : public testing::Test { - public: - void TearDown() override { PumpMessages(); } - - void PumpMessages() { loop_.RunUntilIdle(); } - - private: - Environment env_; - RunLoop loop_; + bool* got_response; + std::string* got_text_reply; }; TEST_F(HandlePassingTest, Basic) { sample::FactoryPtr factory; - BindToProxy(new SampleFactoryImpl(), &factory); - - SampleFactoryClientImpl factory_client; - factory_client.set_expected_text_reply(kText1); - - factory.set_client(&factory_client); + SampleFactoryImpl factory_impl(GetProxy(&factory)); MessagePipe pipe0; EXPECT_TRUE(WriteTextMessage(pipe0.handle1.get(), kText1)); @@ -191,48 +186,62 @@ EXPECT_TRUE(WriteTextMessage(pipe1.handle1.get(), kText2)); imported::ImportedInterfacePtr imported; - BindToProxy(new ImportedInterfaceImpl(), &imported); + ImportedInterfaceImpl imported_impl(GetProxy(&imported)); sample::RequestPtr request(sample::Request::New()); request->x = 1; request->pipe = pipe1.handle0.Pass(); request->obj = imported.Pass(); - factory->DoStuff(request.Pass(), pipe0.handle0.Pass()); + bool got_response = false; + std::string got_text_reply; + DoStuffCallback cb(&got_response, &got_text_reply); + factory->DoStuff(request.Pass(), pipe0.handle0.Pass(), cb); - EXPECT_FALSE(factory_client.got_response()); + EXPECT_FALSE(*cb.got_response); int count_before = ImportedInterfaceImpl::do_something_count(); PumpMessages(); - EXPECT_TRUE(factory_client.got_response()); + EXPECT_TRUE(*cb.got_response); + EXPECT_EQ(kText1, *cb.got_text_reply); EXPECT_EQ(1, ImportedInterfaceImpl::do_something_count() - count_before); } TEST_F(HandlePassingTest, PassInvalid) { sample::FactoryPtr factory; - BindToProxy(new SampleFactoryImpl(), &factory); - - SampleFactoryClientImpl factory_client; - factory.set_client(&factory_client); + SampleFactoryImpl factory_impl(GetProxy(&factory)); sample::RequestPtr request(sample::Request::New()); request->x = 1; - factory->DoStuff(request.Pass(), ScopedMessagePipeHandle().Pass()); + bool got_response = false; + std::string got_text_reply; + DoStuffCallback cb(&got_response, &got_text_reply); + factory->DoStuff(request.Pass(), ScopedMessagePipeHandle().Pass(), cb); - EXPECT_FALSE(factory_client.got_response()); + EXPECT_FALSE(*cb.got_response); PumpMessages(); - EXPECT_TRUE(factory_client.got_response()); + EXPECT_TRUE(*cb.got_response); } +struct DoStuff2Callback { + DoStuff2Callback(bool* got_response, std::string* got_text_reply) + : got_response(got_response), got_text_reply(got_text_reply) {} + + void Run(const String& text_reply) const { + *got_response = true; + *got_text_reply = text_reply; + } + + bool* got_response; + std::string* got_text_reply; +}; + // Verifies DataPipeConsumer can be passed and read from. TEST_F(HandlePassingTest, DataPipe) { sample::FactoryPtr factory; - BindToProxy(new SampleFactoryImpl(), &factory); - - SampleFactoryClientImpl factory_client; - factory.set_client(&factory_client); + SampleFactoryImpl factory_impl(GetProxy(&factory)); // Writes a string to a data pipe and passes the data pipe (consumer) to the // factory. @@ -245,7 +254,6 @@ ASSERT_EQ(MOJO_RESULT_OK, CreateDataPipe(&options, &producer_handle, &consumer_handle)); std::string expected_text_reply = "got it"; - factory_client.set_expected_text_reply(expected_text_reply); // +1 for \0. uint32_t data_size = static_cast<uint32_t>(expected_text_reply.size() + 1); ASSERT_EQ(MOJO_RESULT_OK, @@ -254,21 +262,22 @@ &data_size, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)); - factory->DoStuff2(consumer_handle.Pass()); + bool got_response = false; + std::string got_text_reply; + DoStuff2Callback cb(&got_response, &got_text_reply); + factory->DoStuff2(consumer_handle.Pass(), cb); - EXPECT_FALSE(factory_client.got_response()); + EXPECT_FALSE(*cb.got_response); PumpMessages(); - EXPECT_TRUE(factory_client.got_response()); + EXPECT_TRUE(*cb.got_response); + EXPECT_EQ(expected_text_reply, *cb.got_text_reply); } TEST_F(HandlePassingTest, PipesAreClosed) { sample::FactoryPtr factory; - BindToProxy(new SampleFactoryImpl(), &factory); - - SampleFactoryClientImpl factory_client; - factory.set_client(&factory_client); + SampleFactoryImpl factory_impl(GetProxy(&factory)); MessagePipe extra_pipe; @@ -283,7 +292,8 @@ sample::RequestPtr request(sample::Request::New()); request->more_pipes = pipes.Pass(); - factory->DoStuff(request.Pass(), ScopedMessagePipeHandle()); + factory->DoStuff(request.Pass(), ScopedMessagePipeHandle(), + sample::Factory::DoStuffCallback()); } // We expect the pipes to have been closed. @@ -308,7 +318,7 @@ TEST_F(HandlePassingTest, CreateNamedObject) { sample::FactoryPtr factory; - BindToProxy(new SampleFactoryImpl(), &factory); + SampleFactoryImpl factory_impl(GetProxy(&factory)); sample::NamedObjectPtr object1; EXPECT_FALSE(object1);
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc b/third_party/mojo/src/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc index ded5888..524b07c 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
@@ -49,11 +49,15 @@ typedef mojo::Callback<void(double)> CalcCallback; -class MathCalculatorImpl : public InterfaceImpl<math::Calculator> { +class MathCalculatorImpl : public math::Calculator { public: + explicit MathCalculatorImpl(InterfaceRequest<math::Calculator> request) + : total_(0.0), binding_(this, request.Pass()) {} ~MathCalculatorImpl() override {} - MathCalculatorImpl() : total_(0.0) {} + void CloseMessagePipe() { binding_.Close(); } + + void WaitForIncomingMethodCall() { binding_.WaitForIncomingMethodCall(); } void Clear(const CalcCallback& callback) override { total_ = 0.0; @@ -72,6 +76,7 @@ private: double total_; + Binding<math::Calculator> binding_; }; class MathCalculatorUI { @@ -142,22 +147,25 @@ // static int SelfDestructingMathCalculatorUI::num_instances_ = 0; -class ReentrantServiceImpl : public InterfaceImpl<sample::Service> { +class ReentrantServiceImpl : public sample::Service { public: ~ReentrantServiceImpl() override {} - ReentrantServiceImpl() : call_depth_(0), max_call_depth_(0) {} + explicit ReentrantServiceImpl(InterfaceRequest<sample::Service> request) + : call_depth_(0), max_call_depth_(0), binding_(this, request.Pass()) {} int max_call_depth() { return max_call_depth_; } void Frobinate(sample::FooPtr foo, sample::Service::BazOptions baz, - sample::PortPtr port) override { + sample::PortPtr port, + const sample::Service::FrobinateCallback& callback) override { max_call_depth_ = std::max(++call_depth_, max_call_depth_); if (call_depth_ == 1) { - EXPECT_TRUE(WaitForIncomingMethodCall()); + EXPECT_TRUE(binding_.WaitForIncomingMethodCall()); } call_depth_--; + callback.Run(5); } void GetPort(mojo::InterfaceRequest<sample::Port> port) override {} @@ -165,6 +173,7 @@ private: int call_depth_; int max_call_depth_; + Binding<sample::Service> binding_; }; class InterfacePtrTest : public testing::Test { @@ -180,7 +189,7 @@ TEST_F(InterfacePtrTest, EndToEnd) { math::CalculatorPtr calc; - BindToProxy(new MathCalculatorImpl(), &calc); + MathCalculatorImpl calc_impl(GetProxy(&calc)); // Suppose this is instantiated in a process that has pipe1_. MathCalculatorUI calculator_ui(calc.Pass()); @@ -195,7 +204,7 @@ TEST_F(InterfacePtrTest, EndToEnd_Synchronous) { math::CalculatorPtr calc; - MathCalculatorImpl* impl = BindToProxy(new MathCalculatorImpl(), &calc); + MathCalculatorImpl calc_impl(GetProxy(&calc)); // Suppose this is instantiated in a process that has pipe1_. MathCalculatorUI calculator_ui(calc.Pass()); @@ -204,13 +213,13 @@ calculator_ui.Add(2.0); EXPECT_EQ(0.0, calculator_ui.GetOutput()); - impl->WaitForIncomingMethodCall(); + calc_impl.WaitForIncomingMethodCall(); calculator_ui.WaitForIncomingMethodCall(); EXPECT_EQ(2.0, calculator_ui.GetOutput()); calculator_ui.Multiply(5.0); EXPECT_EQ(2.0, calculator_ui.GetOutput()); - impl->WaitForIncomingMethodCall(); + calc_impl.WaitForIncomingMethodCall(); calculator_ui.WaitForIncomingMethodCall(); EXPECT_EQ(10.0, calculator_ui.GetOutput()); } @@ -218,7 +227,7 @@ TEST_F(InterfacePtrTest, Movable) { math::CalculatorPtr a; math::CalculatorPtr b; - BindToProxy(new MathCalculatorImpl(), &b); + MathCalculatorImpl calc_impl(GetProxy(&b)); EXPECT_TRUE(!a); EXPECT_FALSE(!b); @@ -252,9 +261,19 @@ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, CloseRaw(handle)); } +TEST_F(InterfacePtrTest, BindInvalidHandle) { + math::CalculatorPtr ptr; + EXPECT_FALSE(ptr.get()); + EXPECT_FALSE(ptr); + + ptr.Bind(ScopedMessagePipeHandle()); + EXPECT_FALSE(ptr.get()); + EXPECT_FALSE(ptr); +} + TEST_F(InterfacePtrTest, EncounteredError) { math::CalculatorPtr proxy; - MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy); + MathCalculatorImpl calc_impl(GetProxy(&proxy)); MathCalculatorUI calculator_ui(proxy.Pass()); @@ -267,7 +286,7 @@ EXPECT_FALSE(calculator_ui.encountered_error()); // Close the server. - server->internal_router()->CloseMessagePipe(); + calc_impl.CloseMessagePipe(); // The state change isn't picked up locally yet. EXPECT_FALSE(calculator_ui.encountered_error()); @@ -280,7 +299,7 @@ TEST_F(InterfacePtrTest, EncounteredErrorCallback) { math::CalculatorPtr proxy; - MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy); + MathCalculatorImpl calc_impl(GetProxy(&proxy)); ErrorObserver error_observer; proxy.set_error_handler(&error_observer); @@ -296,7 +315,7 @@ EXPECT_FALSE(calculator_ui.encountered_error()); // Close the server. - server->internal_router()->CloseMessagePipe(); + calc_impl.CloseMessagePipe(); // The state change isn't picked up locally yet. EXPECT_FALSE(calculator_ui.encountered_error()); @@ -311,17 +330,9 @@ EXPECT_TRUE(error_observer.encountered_error()); } -TEST_F(InterfacePtrTest, NoClientAttribute) { - // This is a test to ensure the following compiles. The sample::Port interface - // does not have an explicit Client attribute. - sample::PortPtr port; - MessagePipe pipe; - port.Bind(pipe.handle0.Pass()); -} - -TEST_F(InterfacePtrTest, DestroyInterfacePtrOnClientMethod) { +TEST_F(InterfacePtrTest, DestroyInterfacePtrOnMethodResponse) { math::CalculatorPtr proxy; - BindToProxy(new MathCalculatorImpl(), &proxy); + MathCalculatorImpl calc_impl(GetProxy(&proxy)); EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances()); @@ -334,9 +345,9 @@ EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances()); } -TEST_F(InterfacePtrTest, NestedDestroyInterfacePtrOnClientMethod) { +TEST_F(InterfacePtrTest, NestedDestroyInterfacePtrOnMethodResponse) { math::CalculatorPtr proxy; - BindToProxy(new MathCalculatorImpl(), &proxy); + MathCalculatorImpl calc_impl(GetProxy(&proxy)); EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances()); @@ -351,14 +362,16 @@ TEST_F(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) { sample::ServicePtr proxy; - ReentrantServiceImpl* impl = BindToProxy(new ReentrantServiceImpl(), &proxy); + ReentrantServiceImpl impl(GetProxy(&proxy)); - proxy->Frobinate(nullptr, sample::Service::BAZ_OPTIONS_REGULAR, nullptr); - proxy->Frobinate(nullptr, sample::Service::BAZ_OPTIONS_REGULAR, nullptr); + proxy->Frobinate(nullptr, sample::Service::BAZ_OPTIONS_REGULAR, nullptr, + sample::Service::FrobinateCallback()); + proxy->Frobinate(nullptr, sample::Service::BAZ_OPTIONS_REGULAR, nullptr, + sample::Service::FrobinateCallback()); PumpMessages(); - EXPECT_EQ(2, impl->max_call_depth()); + EXPECT_EQ(2, impl.max_call_depth()); } class StrongMathCalculatorImpl : public math::Calculator, public ErrorHandler {
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/request_response_unittest.cc b/third_party/mojo/src/mojo/public/cpp/bindings/tests/request_response_unittest.cc index 4864e35..a1fe8e64 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/request_response_unittest.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/request_response_unittest.cc
@@ -13,8 +13,11 @@ namespace test { namespace { -class ProviderImpl : public InterfaceImpl<sample::Provider> { +class ProviderImpl : public sample::Provider { public: + explicit ProviderImpl(InterfaceRequest<sample::Provider> request) + : binding_(this, request.Pass()) {} + void EchoString(const String& a, const Callback<void(String)>& callback) override { Callback<void(String)> callback_copy; @@ -39,6 +42,8 @@ const Callback<void(sample::Enum)>& callback) override { callback.Run(a); } + + Binding<sample::Provider> binding_; }; class StringRecorder { @@ -86,7 +91,7 @@ TEST_F(RequestResponseTest, EchoString) { sample::ProviderPtr provider; - BindToProxy(new ProviderImpl(), &provider); + ProviderImpl provider_impl(GetProxy(&provider)); std::string buf; provider->EchoString(String::From("hello"), StringRecorder(&buf)); @@ -98,7 +103,7 @@ TEST_F(RequestResponseTest, EchoStrings) { sample::ProviderPtr provider; - BindToProxy(new ProviderImpl(), &provider); + ProviderImpl provider_impl(GetProxy(&provider)); std::string buf; provider->EchoStrings( @@ -111,7 +116,7 @@ TEST_F(RequestResponseTest, EchoMessagePipeHandle) { sample::ProviderPtr provider; - BindToProxy(new ProviderImpl(), &provider); + ProviderImpl provider_impl(GetProxy(&provider)); MessagePipe pipe2; provider->EchoMessagePipeHandle(pipe2.handle1.Pass(), @@ -127,7 +132,7 @@ TEST_F(RequestResponseTest, EchoEnum) { sample::ProviderPtr provider; - BindToProxy(new ProviderImpl(), &provider); + ProviderImpl provider_impl(GetProxy(&provider)); sample::Enum value; provider->EchoEnum(sample::ENUM_VALUE, EnumRecorder(&value));
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/sample_service_unittest.cc b/third_party/mojo/src/mojo/public/cpp/bindings/tests/sample_service_unittest.cc index ff047cb..5d1617f 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/sample_service_unittest.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/sample_service_unittest.cc
@@ -256,7 +256,10 @@ class ServiceImpl : public Service { public: - void Frobinate(FooPtr foo, BazOptions baz, PortPtr port) override { + void Frobinate(FooPtr foo, + BazOptions baz, + PortPtr port, + const Service::FrobinateCallback& callback) override { // Users code goes here to handle the incoming Frobinate message. // We mainly check that we're given the expected arguments. @@ -273,6 +276,7 @@ Print(depth, "baz", baz); Print(depth, "port", port.get()); } + callback.Run(5); } void GetPort(mojo::InterfaceRequest<Port> port_request) override {} @@ -336,7 +340,8 @@ CheckFoo(*foo); PortPtr port; - service->Frobinate(foo.Pass(), Service::BAZ_OPTIONS_EXTRA, port.Pass()); + service->Frobinate(foo.Pass(), Service::BAZ_OPTIONS_EXTRA, port.Pass(), + Service::FrobinateCallback()); delete service; }
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/struct_unittest.cc b/third_party/mojo/src/mojo/public/cpp/bindings/tests/struct_unittest.cc index 52d1313..7f5a376 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/struct_unittest.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/struct_unittest.cc
@@ -2,8 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <string.h> + #include "mojo/public/cpp/bindings/lib/fixed_buffer.h" #include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/message_pipe.h" #include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h" #include "testing/gtest/include/gtest/gtest.h" @@ -27,6 +30,48 @@ EXPECT_EQ(20 * factor, rect.height); } +MultiVersionStructPtr MakeMultiVersionStruct() { + MultiVersionStructPtr output(MultiVersionStruct::New()); + output->f_int32 = 123; + output->f_rect = MakeRect(5); + output->f_string = "hello"; + output->f_array = Array<int8_t>(3); + output->f_array[0] = 10; + output->f_array[1] = 9; + output->f_array[2] = 8; + MessagePipe pipe; + output->f_message_pipe = pipe.handle0.Pass(); + output->f_int16 = 42; + + return output.Pass(); +} + +template <typename U, typename T> +U SerializeAndDeserialize(T input) { + typedef typename mojo::internal::WrapperTraits<T>::DataType InputDataType; + typedef typename mojo::internal::WrapperTraits<U>::DataType OutputDataType; + + size_t size = GetSerializedSize_(input); + mojo::internal::FixedBuffer buf(size + 32); + InputDataType data; + Serialize_(input.Pass(), &buf, &data); + + std::vector<Handle> handles; + data->EncodePointersAndHandles(&handles); + + // Set the subsequent area to a special value, so that we can find out if we + // mistakenly access the area. + void* subsequent_area = buf.Allocate(32); + memset(subsequent_area, 0xAA, 32); + + OutputDataType output_data = reinterpret_cast<OutputDataType>(data); + output_data->DecodePointersAndHandles(&handles); + + U output; + Deserialize_(output_data, &output); + return output.Pass(); +} + class StructTest : public testing::Test { public: ~StructTest() override {} @@ -197,5 +242,182 @@ EXPECT_TRUE(region2->rects.is_null()); } +// Tests deserializing structs as a newer version. +TEST_F(StructTest, Versioning_OldToNew) { + { + MultiVersionStructV0Ptr input(MultiVersionStructV0::New()); + input->f_int32 = 123; + MultiVersionStructPtr expected_output(MultiVersionStruct::New()); + expected_output->f_int32 = 123; + + MultiVersionStructPtr output = + SerializeAndDeserialize<MultiVersionStructPtr>(input.Pass()); + EXPECT_TRUE(output); + EXPECT_TRUE(output->Equals(*expected_output)); + } + + { + MultiVersionStructV1Ptr input(MultiVersionStructV1::New()); + input->f_int32 = 123; + input->f_rect = MakeRect(5); + MultiVersionStructPtr expected_output(MultiVersionStruct::New()); + expected_output->f_int32 = 123; + expected_output->f_rect = MakeRect(5); + + MultiVersionStructPtr output = + SerializeAndDeserialize<MultiVersionStructPtr>(input.Pass()); + EXPECT_TRUE(output); + EXPECT_TRUE(output->Equals(*expected_output)); + } + + { + MultiVersionStructV3Ptr input(MultiVersionStructV3::New()); + input->f_int32 = 123; + input->f_rect = MakeRect(5); + input->f_string = "hello"; + MultiVersionStructPtr expected_output(MultiVersionStruct::New()); + expected_output->f_int32 = 123; + expected_output->f_rect = MakeRect(5); + expected_output->f_string = "hello"; + + MultiVersionStructPtr output = + SerializeAndDeserialize<MultiVersionStructPtr>(input.Pass()); + EXPECT_TRUE(output); + EXPECT_TRUE(output->Equals(*expected_output)); + } + + { + MultiVersionStructV5Ptr input(MultiVersionStructV5::New()); + input->f_int32 = 123; + input->f_rect = MakeRect(5); + input->f_string = "hello"; + input->f_array = Array<int8_t>(3); + input->f_array[0] = 10; + input->f_array[1] = 9; + input->f_array[2] = 8; + MultiVersionStructPtr expected_output(MultiVersionStruct::New()); + expected_output->f_int32 = 123; + expected_output->f_rect = MakeRect(5); + expected_output->f_string = "hello"; + expected_output->f_array = Array<int8_t>(3); + expected_output->f_array[0] = 10; + expected_output->f_array[1] = 9; + expected_output->f_array[2] = 8; + + MultiVersionStructPtr output = + SerializeAndDeserialize<MultiVersionStructPtr>(input.Pass()); + EXPECT_TRUE(output); + EXPECT_TRUE(output->Equals(*expected_output)); + } + + { + MultiVersionStructV7Ptr input(MultiVersionStructV7::New()); + input->f_int32 = 123; + input->f_rect = MakeRect(5); + input->f_string = "hello"; + input->f_array = Array<int8_t>(3); + input->f_array[0] = 10; + input->f_array[1] = 9; + input->f_array[2] = 8; + MessagePipe pipe; + input->f_message_pipe = pipe.handle0.Pass(); + + MultiVersionStructPtr expected_output(MultiVersionStruct::New()); + expected_output->f_int32 = 123; + expected_output->f_rect = MakeRect(5); + expected_output->f_string = "hello"; + expected_output->f_array = Array<int8_t>(3); + expected_output->f_array[0] = 10; + expected_output->f_array[1] = 9; + expected_output->f_array[2] = 8; + // Save the raw handle value separately so that we can compare later. + MojoHandle expected_handle = input->f_message_pipe.get().value(); + + MultiVersionStructPtr output = + SerializeAndDeserialize<MultiVersionStructPtr>(input.Pass()); + EXPECT_TRUE(output); + EXPECT_EQ(expected_handle, output->f_message_pipe.get().value()); + output->f_message_pipe.reset(); + EXPECT_TRUE(output->Equals(*expected_output)); + } +} + +// Tests deserializing structs as an older version. +TEST_F(StructTest, Versioning_NewToOld) { + { + MultiVersionStructPtr input = MakeMultiVersionStruct(); + MultiVersionStructV7Ptr expected_output(MultiVersionStructV7::New()); + expected_output->f_int32 = 123; + expected_output->f_rect = MakeRect(5); + expected_output->f_string = "hello"; + expected_output->f_array = Array<int8_t>(3); + expected_output->f_array[0] = 10; + expected_output->f_array[1] = 9; + expected_output->f_array[2] = 8; + // Save the raw handle value separately so that we can compare later. + MojoHandle expected_handle = input->f_message_pipe.get().value(); + + MultiVersionStructV7Ptr output = + SerializeAndDeserialize<MultiVersionStructV7Ptr>(input.Pass()); + EXPECT_TRUE(output); + EXPECT_EQ(expected_handle, output->f_message_pipe.get().value()); + output->f_message_pipe.reset(); + EXPECT_TRUE(output->Equals(*expected_output)); + } + + { + MultiVersionStructPtr input = MakeMultiVersionStruct(); + MultiVersionStructV5Ptr expected_output(MultiVersionStructV5::New()); + expected_output->f_int32 = 123; + expected_output->f_rect = MakeRect(5); + expected_output->f_string = "hello"; + expected_output->f_array = Array<int8_t>(3); + expected_output->f_array[0] = 10; + expected_output->f_array[1] = 9; + expected_output->f_array[2] = 8; + + MultiVersionStructV5Ptr output = + SerializeAndDeserialize<MultiVersionStructV5Ptr>(input.Pass()); + EXPECT_TRUE(output); + EXPECT_TRUE(output->Equals(*expected_output)); + } + + { + MultiVersionStructPtr input = MakeMultiVersionStruct(); + MultiVersionStructV3Ptr expected_output(MultiVersionStructV3::New()); + expected_output->f_int32 = 123; + expected_output->f_rect = MakeRect(5); + expected_output->f_string = "hello"; + + MultiVersionStructV3Ptr output = + SerializeAndDeserialize<MultiVersionStructV3Ptr>(input.Pass()); + EXPECT_TRUE(output); + EXPECT_TRUE(output->Equals(*expected_output)); + } + + { + MultiVersionStructPtr input = MakeMultiVersionStruct(); + MultiVersionStructV1Ptr expected_output(MultiVersionStructV1::New()); + expected_output->f_int32 = 123; + expected_output->f_rect = MakeRect(5); + + MultiVersionStructV1Ptr output = + SerializeAndDeserialize<MultiVersionStructV1Ptr>(input.Pass()); + EXPECT_TRUE(output); + EXPECT_TRUE(output->Equals(*expected_output)); + } + + { + MultiVersionStructPtr input = MakeMultiVersionStruct(); + MultiVersionStructV0Ptr expected_output(MultiVersionStructV0::New()); + expected_output->f_int32 = 123; + + MultiVersionStructV0Ptr output = + SerializeAndDeserialize<MultiVersionStructV0Ptr>(input.Pass()); + EXPECT_TRUE(output); + EXPECT_TRUE(output->Equals(*expected_output)); + } +} + } // namespace test } // namespace mojo
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/union_unittest.cc b/third_party/mojo/src/mojo/public/cpp/bindings/tests/union_unittest.cc index f811a22..aba7faa6 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/union_unittest.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/union_unittest.cc
@@ -130,7 +130,8 @@ internal::PodUnion_Data* data; Serialize_(pod.Pass(), &buf, &data); void* raw_buf = buf.Leak(); - mojo::internal::BoundsChecker bounds_checker(data, size, 0); + mojo::internal::BoundsChecker bounds_checker(data, + static_cast<uint32_t>(size), 0); EXPECT_TRUE(internal::PodUnion_Data::Validate(raw_buf, &bounds_checker)); free(raw_buf); } @@ -151,7 +152,8 @@ internal::PodUnion_Data* data = reinterpret_cast<internal::PodUnion_Data*>(buf); - mojo::internal::BoundsChecker bounds_checker(data, size, 0); + mojo::internal::BoundsChecker bounds_checker(data, + static_cast<uint32_t>(size), 0); EXPECT_FALSE(internal::PodUnion_Data::Validate(buf, &bounds_checker)); free(raw_buf); } @@ -161,7 +163,8 @@ size_t size = sizeof(internal::PodUnion_Data) - 1; mojo::internal::FixedBuffer buf(size); internal::PodUnion_Data* data = internal::PodUnion_Data::New(&buf); - mojo::internal::BoundsChecker bounds_checker(data, size, 0); + mojo::internal::BoundsChecker bounds_checker(data, + static_cast<uint32_t>(size), 0); void* raw_buf = buf.Leak(); EXPECT_FALSE(internal::PodUnion_Data::Validate(raw_buf, &bounds_checker)); free(raw_buf); @@ -173,7 +176,8 @@ mojo::internal::FixedBuffer buf(size); internal::PodUnion_Data* data = internal::PodUnion_Data::New(&buf); data->tag = static_cast<internal::PodUnion_Data::PodUnion_Tag>(0xFFFFFF); - mojo::internal::BoundsChecker bounds_checker(data, size, 0); + mojo::internal::BoundsChecker bounds_checker(data, + static_cast<uint32_t>(size), 0); void* raw_buf = buf.Leak(); EXPECT_FALSE(internal::PodUnion_Data::Validate(raw_buf, &bounds_checker)); free(raw_buf); @@ -237,7 +241,8 @@ internal::ObjectUnion_Data* data = internal::ObjectUnion_Data::New(&buf); data->tag = internal::ObjectUnion_Data::ObjectUnion_Tag::F_STRING; data->data.unknown = 0x0; - mojo::internal::BoundsChecker bounds_checker(data, size, 0); + mojo::internal::BoundsChecker bounds_checker(data, + static_cast<uint32_t>(size), 0); void* raw_buf = buf.Leak(); EXPECT_FALSE(internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker)); free(raw_buf); @@ -250,7 +255,8 @@ internal::ObjectUnion_Data* data = internal::ObjectUnion_Data::New(&buf); data->tag = internal::ObjectUnion_Data::ObjectUnion_Tag::F_STRING; data->data.unknown = 0xFFFFFFFFFFFFFFFF; - mojo::internal::BoundsChecker bounds_checker(data, size, 0); + mojo::internal::BoundsChecker bounds_checker(data, + static_cast<uint32_t>(size), 0); void* raw_buf = buf.Leak(); EXPECT_FALSE(internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker)); free(raw_buf);
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/validation_test_input_parser.h b/third_party/mojo/src/mojo/public/cpp/bindings/tests/validation_test_input_parser.h index c8821cda..d5f8c81 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/validation_test_input_parser.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/validation_test_input_parser.h
@@ -82,7 +82,7 @@ // The following describes a valid message whose payload is a Foo struct: // // message header // [dist4]message_header // num_bytes -// [u4]3 // num_fields +// [u4]3 // version // [u4]0 // type // [u4]1 // flags // [u8]1234 // request_id @@ -90,7 +90,7 @@ // // // payload // [dist4]foo // num_bytes -// [u4]2 // num_fields +// [u4]2 // version // [dist8]bar_ptr // x // [u4]0xABCD // y // [u4]0 // padding @@ -98,7 +98,7 @@ // // [anchr]bar_ptr // [dist4]bar // num_bytes -// [u4]3 // num_fields +// [u4]3 // version // [s4]-1 // a // [b]00000010 // b and c // 0 0 0 // padding
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/validation_unittest.cc b/third_party/mojo/src/mojo/public/cpp/bindings/tests/validation_unittest.cc index 6507f21..8139fe4 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/validation_unittest.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/validation_unittest.cc
@@ -225,7 +225,9 @@ public: TestMessageReceiver(ValidationIntegrationTest* owner, ScopedMessagePipeHandle handle) - : owner_(owner), connector_(handle.Pass()) {} + : owner_(owner), connector_(handle.Pass()) { + connector_.set_enforce_errors_from_incoming_receiver(false); + } ~TestMessageReceiver() override {} bool Accept(Message* message) override { @@ -246,19 +248,14 @@ ScopedMessagePipeHandle testee_endpoint_; }; -class IntegrationTestInterface1Client : public IntegrationTestInterface1 { +class IntegrationTestInterfaceImpl : public IntegrationTestInterface { public: - ~IntegrationTestInterface1Client() override {} + ~IntegrationTestInterfaceImpl() override {} - void Method0(BasicStructPtr param0) override {} -}; - -class IntegrationTestInterface1Impl - : public InterfaceImpl<IntegrationTestInterface1> { - public: - ~IntegrationTestInterface1Impl() override {} - - void Method0(BasicStructPtr param0) override {} + void Method0(BasicStructPtr param0, + const Method0Callback& callback) override { + callback.Run(Array<uint8_t>::New(0u)); + } }; TEST_F(ValidationTest, InputParser) { @@ -374,44 +371,32 @@ RunValidationTests("conformance_", validators.GetHead()); } -TEST_F(ValidationTest, NotImplemented) { - DummyMessageReceiver dummy_receiver; - mojo::internal::FilterChain validators(&dummy_receiver); - validators.Append<mojo::internal::MessageHeaderValidator>(); - validators.Append<ConformanceTestInterface::RequestValidator_>(); - - RunValidationTests("not_implemented_", validators.GetHead()); -} - +// Test that InterfacePtr<X> applies the correct validators and they don't +// conflict with each other: +// - MessageHeaderValidator +// - X::ResponseValidator_ TEST_F(ValidationIntegrationTest, InterfacePtr) { - // Test that InterfacePtr<X> applies the correct validators and they don't - // conflict with each other: - // - MessageHeaderValidator - // - X::Client::RequestValidator_ - // - X::ResponseValidator_ + IntegrationTestInterfacePtr interface_ptr = + MakeProxy<IntegrationTestInterface>(testee_endpoint().Pass()); + interface_ptr.internal_state()->router_for_testing()->EnableTestingMode(); - IntegrationTestInterface1Client interface1_client; - IntegrationTestInterface2Ptr interface2_ptr = - MakeProxy<IntegrationTestInterface2>(testee_endpoint().Pass()); - interface2_ptr.set_client(&interface1_client); - interface2_ptr.internal_state()->router_for_testing()->EnableTestingMode(); - - RunValidationTests("integration_", test_message_receiver()); + RunValidationTests("integration_intf_resp", test_message_receiver()); + RunValidationTests("integration_msghdr", test_message_receiver()); } -TEST_F(ValidationIntegrationTest, InterfaceImpl) { - // Test that InterfaceImpl<X> applies the correct validators and they don't - // conflict with each other: - // - MessageHeaderValidator - // - X::RequestValidator_ - // - X::Client::ResponseValidator_ +// Test that Binding<X> applies the correct validators and they don't +// conflict with each other: +// - MessageHeaderValidator +// - X::RequestValidator_ +TEST_F(ValidationIntegrationTest, Binding) { + IntegrationTestInterfaceImpl interface_impl; + Binding<IntegrationTestInterface> binding( + &interface_impl, + MakeRequest<IntegrationTestInterface>(testee_endpoint().Pass())); + binding.internal_router()->EnableTestingMode(); - // |interface1_impl| will delete itself when the pipe is closed. - IntegrationTestInterface1Impl* interface1_impl = - BindToPipe(new IntegrationTestInterface1Impl(), testee_endpoint().Pass()); - interface1_impl->internal_router()->EnableTestingMode(); - - RunValidationTests("integration_", test_message_receiver()); + RunValidationTests("integration_intf_rqst", test_message_receiver()); + RunValidationTests("integration_msghdr", test_message_receiver()); } } // namespace
diff --git a/third_party/mojo/src/mojo/public/cpp/environment/BUILD.gn b/third_party/mojo/src/mojo/public/cpp/environment/BUILD.gn index 9b192f1..87f24ff 100644 --- a/third_party/mojo/src/mojo/public/cpp/environment/BUILD.gn +++ b/third_party/mojo/src/mojo/public/cpp/environment/BUILD.gn
@@ -7,8 +7,8 @@ mojo_sdk_source_set("environment") { sources = [ "async_waiter.h", - "environment.h", "logging.h", + "environment.h", ] mojo_sdk_public_deps = [ "mojo/public/c/environment" ]
diff --git a/third_party/mojo/src/mojo/public/cpp/utility/BUILD.gn b/third_party/mojo/src/mojo/public/cpp/utility/BUILD.gn index 96c1d11..9660a07 100644 --- a/third_party/mojo/src/mojo/public/cpp/utility/BUILD.gn +++ b/third_party/mojo/src/mojo/public/cpp/utility/BUILD.gn
@@ -6,16 +6,16 @@ mojo_sdk_source_set("utility") { sources = [ + "mutex.h", + "run_loop.h", + "run_loop_handler.h", + "thread.h", "lib/mutex.cc", "lib/run_loop.cc", "lib/thread.cc", "lib/thread_local.h", "lib/thread_local_posix.cc", "lib/thread_local_win.cc", - "mutex.h", - "run_loop.h", - "run_loop_handler.h", - "thread.h", ] mojo_sdk_deps = [ @@ -26,10 +26,10 @@ if (is_win) { # See crbug.com/342893: sources -= [ - "lib/mutex.cc", - "lib/thread.cc", "mutex.h", "thread.h", + "lib/mutex.cc", + "lib/thread.cc", ] } }
diff --git a/third_party/mojo/src/mojo/public/dart/application.dart b/third_party/mojo/src/mojo/public/dart/application.dart index 80cc144c..8dd3ecf 100644 --- a/third_party/mojo/src/mojo/public/dart/application.dart +++ b/third_party/mojo/src/mojo/public/dart/application.dart
@@ -6,13 +6,13 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:mojo_bindings' as bindings; -import 'dart:mojo_core' as core; import 'dart:typed_data'; +import 'mojo:bindings' as bindings; +import 'mojo:core' as core; import 'package:mojo/public/interfaces/application/application.mojom.dart' as application_mojom; -import 'package:mojo/public/interfaces/application/service_provider.mojom.dart' as service_provider; +import 'package:mojo/public/interfaces/application/service_provider.mojom.dart'; import 'package:mojo/public/interfaces/application/shell.mojom.dart' as shell_mojom; part 'src/application.dart'; -part 'src/service_provider.dart'; +part 'src/application_connection.dart';
diff --git a/third_party/mojo/src/mojo/public/dart/bindings.dart b/third_party/mojo/src/mojo/public/dart/bindings.dart index ef481a1d..38318f58 100644 --- a/third_party/mojo/src/mojo/public/dart/bindings.dart +++ b/third_party/mojo/src/mojo/public/dart/bindings.dart
@@ -6,8 +6,8 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:mojo_core' as core; import 'dart:typed_data'; +import 'mojo:core' as core; part 'src/codec.dart'; part 'src/message.dart';
diff --git a/third_party/mojo/src/mojo/public/dart/rules.gni b/third_party/mojo/src/mojo/public/dart/rules.gni index aea59e3..e8d7c72 100644 --- a/third_party/mojo/src/mojo/public/dart/rules.gni +++ b/third_party/mojo/src/mojo/public/dart/rules.gni
@@ -54,6 +54,7 @@ # dart_package targets. template("dart_packaged_application") { package_name = "${target_name}_package" + package_analyze_sources = "${target_name}_analyze" package_output = "$target_out_dir/$package_name.dartzip" if (defined(invoker.output_name)) { @@ -62,6 +63,39 @@ mojo_output = "$root_out_dir/" + target_name + ".mojo" } + action_foreach(package_analyze_sources) { + sources = invoker.sources + + script = rebase_path("mojo/public/tools/dart_analyze.py", ".", mojo_root) + + args = [ + rebase_path(root_gen_dir), + rebase_path("$target_gen_dir/{{source_name_part}}.stamp"), + "{{source}}", + "--no-hints", + "--url-mapping=mojo:application,/" + + rebase_path("mojo/public/dart/application.dart", "/", mojo_root), + "--url-mapping=mojo:bindings,/" + + rebase_path("mojo/public/dart/bindings.dart", "/", mojo_root), + "--url-mapping=mojo:builtin,/" + + rebase_path("mojo/dart/embedder/builtin.dart", "/", mojo_root), + "--url-mapping=mojo:core,/" + + rebase_path("mojo/public/dart/core.dart", "/", mojo_root), + ] + + if (defined(invoker.deps)) { + deps = invoker.deps + } + + if (defined(invoker.datadeps)) { + datadeps = invoker.datadeps + } + + outputs = [ + "$target_gen_dir/{{source_name_part}}.stamp", + ] + } + dart_package(package_name) { sources = invoker.sources if (defined(invoker.deps)) { @@ -89,6 +123,9 @@ ] deps = [ + # TODO(erg): When dartanalyze runs at an acceptable speed, add + # ":$package_analyze_sources" as a dependency here and remove the + # manual group("check") in the toplevel build file. ":$package_name", ] if (defined(invoker.deps)) { @@ -101,12 +138,17 @@ datadeps = invoker.datadeps } + line = "#!mojo mojo:dart_content_handler" + if (is_debug || (defined(invoker.strict) && invoker.strict == true)) { + line = "#!mojo mojo:dart_content_handler?strict=true" + } + 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 mojo:dart_content_handler", + "--line=$line", ] } }
diff --git a/third_party/mojo/src/mojo/public/dart/src/application.dart b/third_party/mojo/src/mojo/public/dart/src/application.dart index e5b9d4b7..3ae900b 100644 --- a/third_party/mojo/src/mojo/public/dart/src/application.dart +++ b/third_party/mojo/src/mojo/public/dart/src/application.dart
@@ -4,31 +4,35 @@ part of application; -class _ApplicationImpl extends application_mojom.Application { +class _ApplicationImpl implements application_mojom.Application { + application_mojom.ApplicationStub _stub; shell_mojom.ShellProxy shell; Application _application; - _ApplicationImpl( - Application application, core.MojoMessagePipeEndpoint endpoint) - : _application = application, super(endpoint) { - super.delegate = this; + _ApplicationImpl(Application application, + core.MojoMessagePipeEndpoint endpoint) { + _application = application; + _stub = new application_mojom.ApplicationStub.fromEndpoint(endpoint) + ..delegate = this + ..listen(); } - _ApplicationImpl.fromHandle(Application application, core.MojoHandle handle) - : _application = application, super.fromHandle(handle) { - super.delegate = this; + _ApplicationImpl.fromHandle(Application application, core.MojoHandle handle) { + _application = application; + _stub = new application_mojom.ApplicationStub.fromHandle(handle) + ..delegate = this + ..listen(); } - void initialize(shell_mojom.ShellProxy shellProxy, List<String> args) { + void initialize(bindings.ProxyBase shellProxy, List<String> args, + String url) { assert(shell == null); shell = shellProxy; - _application.initialize(args); + _application.initialize(args, url); } - void acceptConnection( - String requestorUrl, - service_provider.ServiceProviderStub services, - service_provider.ServiceProviderProxy exposedServices) => + void acceptConnection(String requestorUrl, ServiceProviderStub services, + bindings.ProxyBase exposedServices, String requested_url) => _application._acceptConnection(requestorUrl, services, exposedServices); void requestQuit() => _application._requestQuitAndClose(); @@ -36,78 +40,49 @@ void close({bool nodefer: false}) => shell.close(); } -// ApplicationConnection represents a single outgoing connection to another app. -class ApplicationConnection { - // ServiceProvider used to obtain services from the remote application. - service_provider.ServiceProviderProxy serviceProvider; - - ApplicationConnection(this.serviceProvider); - - // Obtains a service from the remote application. - void connectToService(bindings.Proxy proxy) { - assert(!proxy.isBound); - var applicationPipe = new core.MojoMessagePipe(); - var proxyEndpoint = applicationPipe.endpoints[0]; - var applicationEndpoint = applicationPipe.endpoints[1]; - proxy.bind(proxyEndpoint); - serviceProvider.connectToService(proxy.name, applicationEndpoint); - } -} - // TODO(zra): Better documentation and examples. // To implement, do the following: +// - Optionally override initialize() to process command-line args. // - Optionally override acceptConnection() if services are to be provided. -// The override should assign a factory function to the passed in -// ServiceProvider's |factory| field, and then call listen on the -// ServiceProvider. The factory function should take a MojoMessagePipeEndpoint -// and return an object that implements the requested interface. -// - Optionally override initialize() where needed. -// - Optionally override requestClose() to clean up state specific to your -// application. -// To use an Application: -// - Call listen() on a newly created Application to begin providing services. -// - Call connectToService() to request services from the Shell. -// - Call close() to close connections to any requested ServiceProviders and the -// Shell. +// - Optionally override close() to clean up application resources. abstract class Application { _ApplicationImpl _applicationImpl; List<ApplicationConnection> _applicationConnections; - List<ServiceProvider> _serviceProviders; Application(core.MojoMessagePipeEndpoint endpoint) { _applicationConnections = []; - _serviceProviders = []; _applicationImpl = new _ApplicationImpl(this, endpoint); } Application.fromHandle(core.MojoHandle appHandle) { _applicationConnections = []; - _serviceProviders = []; _applicationImpl = new _ApplicationImpl.fromHandle(this, appHandle); } - void initialize(List<String> args) {} + void initialize(List<String> args, String url) {} - // Establishes a connection to the app at |url|. + // TODO(skydart): This is a temporary fix to allow sky application to consume + // mojo services. Do not use for any other purpose. + void initializeFromShellProxy(shell_mojom.ShellProxy shellProxy, + List<String> args, String url) => + _applicationImpl.initialize(shellProxy, args, url); + + // Returns a connection to the app at |url|. ApplicationConnection connectToApplication(String url) { - var serviceProviderProxy = - new service_provider.ServiceProviderProxy.unbound(); - // TODO: Need to expose ServiceProvider for local services. - _applicationImpl.shell.connectToApplication( - url, serviceProviderProxy, null); - var applicationConnection = new ApplicationConnection(serviceProviderProxy); - _applicationConnections.add(applicationConnection); - return applicationConnection; + var proxy = new ServiceProviderProxy.unbound(); + var stub = new ServiceProviderStub.unbound(); + _applicationImpl.shell.ptr.connectToApplication(url, proxy, stub); + var connection = new ApplicationConnection(stub, proxy); + _applicationConnections.add(connection); + return connection; } - void connectToService(String url, bindings.Proxy proxy) { - connectToApplication(url).connectToService(proxy); + void connectToService(String url, bindings.ProxyBase proxy) { + connectToApplication(url).requestService(proxy); } void requestQuit() {} - listen() => _applicationImpl.listen(); - void _requestQuitAndClose() { requestQuit(); close(); @@ -115,21 +90,21 @@ void close() { assert(_applicationImpl != null); - _applicationConnections.forEach((c) => c.serviceProvider.close()); + _applicationConnections.forEach((c) => c.close()); _applicationConnections.clear(); - _serviceProviders.forEach((sp) => sp.close()); - _serviceProviders.clear(); _applicationImpl.close(); } - void _acceptConnection( - String requestorUrl, - service_provider.ServiceProviderStub services, - service_provider.ServiceProviderProxy exposedServices) { - var serviceProvider = new ServiceProvider(services, exposedServices); - _serviceProviders.add(serviceProvider); - acceptConnection(requestorUrl, serviceProvider); + void _acceptConnection(String requestorUrl, ServiceProviderStub services, + ServiceProviderProxy exposedServices) { + var connection = new ApplicationConnection(services, exposedServices); + _applicationConnections.add(connection); + acceptConnection(requestorUrl, connection); } - void acceptConnection(String requestorUrl, ServiceProvider serviceProvider) {} + // Override this method to provide services on |connection|. + // If you provide at least one service or set fallbackServiceProvider, + // then you must invoke connection.listen(). + void acceptConnection(String requestorUrl, ApplicationConnection connection) { + } }
diff --git a/third_party/mojo/src/mojo/public/dart/src/application_connection.dart b/third_party/mojo/src/mojo/public/dart/src/application_connection.dart new file mode 100644 index 0000000..4f0b6c8e --- /dev/null +++ b/third_party/mojo/src/mojo/public/dart/src/application_connection.dart
@@ -0,0 +1,111 @@ +// 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. + +part of application; + +typedef Object ServiceFactory(core.MojoMessagePipeEndpoint endpoint); +typedef void FallbackServiceFactory(String interfaceName, + core.MojoMessagePipeEndpoint endpoint); + + +class LocalServiceProvider implements ServiceProvider { + final ApplicationConnection connection; + ServiceProviderStub _stub; + + LocalServiceProvider(this.connection, this._stub) { + _stub.delegate = this; + } + + listen() => _stub.listen(); + + void close({bool nodefer : false}) => _stub.close(nodefer: nodefer); + + void connectToService(String interfaceName, + core.MojoMessagePipeEndpoint pipe) { + if (connection._nameToServiceFactory.containsKey(interfaceName)) { + connection._nameToServiceFactory[interfaceName](pipe); + return; + } + if (connection.fallbackServiceFactory != null) { + connection.fallbackServiceFactory(interfaceName, pipe); + return; + } + // The specified interface isn't provided. Close the pipe so the + // remote endpoint sees that we don't support this interface. + pipe.handle.close(); + } +} + +// Encapsulates a pair of ServiceProviders that enable services (interface +// implementations) to be provided to a remote application as well as exposing +// services provided by a remote application. ApplicationConnection +// objects are returned by the Application ConnectToApplication() method +// and they're passed to the Application AcceptConnection() method. +// +// To request a service from the remote application: +// var proxy = applicationConnection.requestService(ViewManagerClientName); +// +// To provide a service to the remote application, specify a function that +// returns a service. For example: +// applicationConnection.provideService(ViewManagerClientName, (pipe) => +// new ViewManagerClientImpl(pipe)); +// +// To handle requests for any interface, set fallbackServiceFactory to a +// function that takes ownership of the incoming message pipe endpoint. If the +// fallbackServiceFactory function doesn't bind the pipe, it should close it. +// +// The fallbackServiceFactory is only used if a service wasn't specified +// with provideService(). + +class ApplicationConnection { + ServiceProviderProxy remoteServiceProvider; + LocalServiceProvider _localServiceProvider; + final _nameToServiceFactory = new Map<String, ServiceFactory>(); + FallbackServiceFactory _fallbackServiceFactory; + + ApplicationConnection(ServiceProviderStub stub, ServiceProviderProxy proxy) + : remoteServiceProvider = proxy { + if (stub != null) _localServiceProvider = + new LocalServiceProvider(this, stub); + } + + FallbackServiceFactory get fallbackServiceFactory => _fallbackServiceFactory; + set fallbackServiceFactory(FallbackServiceFactory f) { + assert(_localServiceProvider != null); + _fallbackServiceFactory = f; + } + + bindings.ProxyBase requestService(bindings.ProxyBase proxy) { + assert(!proxy.impl.isBound && + (remoteServiceProvider != null) && + remoteServiceProvider.impl.isBound); + var pipe = new core.MojoMessagePipe(); + proxy.impl.bind(pipe.endpoints[0]); + remoteServiceProvider.ptr.connectToService( + proxy.name, pipe.endpoints[1]); + return proxy; + } + + void provideService(String interfaceName, ServiceFactory factory) { + assert(_localServiceProvider != null); + _nameToServiceFactory[interfaceName] = factory; + } + + void listen() { + assert(_localServiceProvider != null); + _localServiceProvider.listen(); + } + + void close({bool nodefer: false}) { + if (remoteServiceProvider != null) { + remoteServiceProvider.close(); + remoteServiceProvider = null; + } + if (_localServiceProvider != null) { + _localServiceProvider.close(nodefer: nodefer); + _localServiceProvider = null; + } + + } +}
diff --git a/third_party/mojo/src/mojo/public/dart/src/codec.dart b/third_party/mojo/src/mojo/public/dart/src/codec.dart index 268daee..81c2523b 100644 --- a/third_party/mojo/src/mojo/public/dart/src/codec.dart +++ b/third_party/mojo/src/mojo/public/dart/src/codec.dart
@@ -9,7 +9,9 @@ const int kAlignment = 8; const int kSerializedHandleSize = 4; const int kPointerSize = 8; -const DataHeader kMapStructHeader = const DataHeader(24, 2); +// TODO(yzshen): In order to work with other bindings which still interprets +// the |version| field as |num_fields|, set it to version 2 for now. +const StructDataHeader kMapStructHeader = const StructDataHeader(24, 2); const int kUnspecifiedArrayLength = -1; const int kNothingNullable = 0; const int kArrayNullable = (1 << 0); @@ -18,6 +20,30 @@ bool isArrayNullable(int nullability) => (nullability & kArrayNullable) > 0; bool isElementNullable(int nullability) => (nullability & kElementNullable) > 0; +class StructDataHeader { + static const int kHeaderSize = 8; + static const int kSizeOffset = 0; + static const int kVersionOffset = 4; + final int size; + final int version; + + const StructDataHeader(this.size, this.version); + + String toString() => "StructDataHeader($size, $version)"; +} + +class ArrayDataHeader { + static const int kHeaderSize = 8; + static const int kSizeOffset = 0; + static const int kNumElementsOffset = 4; + final int size; + final int numElements; + + const ArrayDataHeader(this.size, this.numElements); + + String toString() => "ArrayDataHeader($size, $numElements)"; +} + class MojoCodecError { final String message; MojoCodecError(this.message); @@ -64,18 +90,30 @@ _buffer = buffer, _base = buffer.extent; - Encoder getEncoderAtOffset(DataHeader dataHeader) { + Encoder getStructEncoderAtOffset(StructDataHeader dataHeader) { var result = new Encoder._fromBuffer(_buffer); - result.encodeDataHeader(dataHeader); + result.encodeStructDataHeader(dataHeader); + return result; + } + + Encoder getArrayEncoderAtOffset(ArrayDataHeader dataHeader) { + var result = new Encoder._fromBuffer(_buffer); + result.encodeArrayDataHeader(dataHeader); return result; } Message get message => new Message(_buffer.trimmed, _buffer.handles); - void encodeDataHeader(DataHeader dataHeader) { + void encodeStructDataHeader(StructDataHeader dataHeader) { _buffer.claimMemory(align(dataHeader.size)); - encodeUint32(dataHeader.size, DataHeader.kSizeOffset); - encodeUint32(dataHeader.numFields, DataHeader.kNumFieldsOffset); + encodeUint32(dataHeader.size, StructDataHeader.kSizeOffset); + encodeUint32(dataHeader.version, StructDataHeader.kVersionOffset); + } + + void encodeArrayDataHeader(ArrayDataHeader dataHeader) { + _buffer.claimMemory(align(dataHeader.size)); + encodeUint32(dataHeader.size, ArrayDataHeader.kSizeOffset); + encodeUint32(dataHeader.numElements, ArrayDataHeader.kNumElementsOffset); } static const String kErrorUnsigned = @@ -94,7 +132,7 @@ void encodeUint8(int value, int offset) { if (value < 0) { - throw new MojoCodecError('$kErrorUnsigned: $val'); + throw new MojoCodecError('$kErrorUnsigned: $value'); } _buffer.buffer.setUint8(_base + offset, value); } @@ -104,7 +142,7 @@ void encodeUint16(int value, int offset) { if (value < 0) { - throw new MojoCodecError('$kErrorUnsigned: $val'); + throw new MojoCodecError('$kErrorUnsigned: $value'); } _buffer.buffer.setUint16(_base + offset, value, Endianness.LITTLE_ENDIAN); } @@ -114,7 +152,7 @@ void encodeUint32(int value, int offset) { if (value < 0) { - throw new MojoCodecError('$kErrorUnsigned: $val'); + throw new MojoCodecError('$kErrorUnsigned: $value'); } _buffer.buffer.setUint32(_base + offset, value, Endianness.LITTLE_ENDIAN); } @@ -124,7 +162,7 @@ void encodeUint64(int value, int offset) { if (value < 0) { - throw new MojoCodecError('$kErrorUnsigned: $val'); + throw new MojoCodecError('$kErrorUnsigned: $value'); } _buffer.buffer.setUint64(_base + offset, value, Endianness.LITTLE_ENDIAN); } @@ -170,13 +208,13 @@ encodeMessagePipeHandle(pipe.endpoints[1], offset, nullable); } - void encodeInterfaceRequest(Proxy client, int offset, bool nullable) { + void encodeInterfaceRequest(ProxyBase client, int offset, bool nullable) { if (client == null) { encodeInvalideHandle(offset, nullable); return; } var pipe = new core.MojoMessagePipe(); - client.bind(pipe.endpoints[0]); + client.impl.bind(pipe.endpoints[0]); encodeMessagePipeHandle(pipe.endpoints[1], offset, nullable); } @@ -223,8 +261,8 @@ Encoder encoderForArrayByTotalSize(int size, int length, int offset) { encodePointerToNextUnclaimed(offset); - return getEncoderAtOffset( - new DataHeader(DataHeader.kHeaderSize + size, length)); + return getArrayEncoderAtOffset( + new ArrayDataHeader(ArrayDataHeader.kHeaderSize + size, length)); } void encodeBoolArray( @@ -329,7 +367,8 @@ var encoder = encoderForArray( kSerializedHandleSize, value.length, offset, expectedLength); for (int i = 0; i < value.length; ++i) { - int handleOffset = DataHeader.kHeaderSize + kSerializedHandleSize * i; + int handleOffset = + ArrayDataHeader.kHeaderSize + kSerializedHandleSize * i; elementEncoder( encoder, value[i], handleOffset, isElementNullable(nullability)); } @@ -415,8 +454,8 @@ void appendBytes(Uint8List value) { _buffer.buffer.buffer.asUint8List().setRange( - _base + DataHeader.kHeaderSize, - _base + DataHeader.kHeaderSize + value.lengthInBytes, + _base + ArrayDataHeader.kHeaderSize, + _base + ArrayDataHeader.kHeaderSize + value.lengthInBytes, value); } @@ -444,15 +483,15 @@ void appendUint64Array(List<int> value) => appendBytes(new Uint8List.view(new Uint64List.fromList(value).buffer)); - void appendFloatArray(List<int> value) => + void appendFloatArray(List<double> value) => appendBytes(new Uint8List.view(new Float32List.fromList(value).buffer)); - void appendDoubleArray(List<int> value) => + void appendDoubleArray(List<double> value) => appendBytes(new Uint8List.view(new Float64List.fromList(value).buffer)); Encoder encoderForMap(int offset) { encodePointerToNextUnclaimed(offset); - return getEncoderAtOffset(kMapStructHeader); + return getStructEncoderAtOffset(kMapStructHeader); } } @@ -562,7 +601,7 @@ core.MojoSharedBuffer decodeSharedBufferHandle(int offset, bool nullable) => new core.MojoSharedBuffer(decodeHandle(offset, nullable)); - Proxy decodeServiceInterface( + ProxyBase decodeServiceInterface( int offset, bool nullable, Function clientFactory) { var endpoint = decodeMessagePipeHandle(offset, nullable); return endpoint.handle.isValid ? clientFactory(endpoint) : null; @@ -588,31 +627,47 @@ return new Decoder.atOffset(this, newPosition, _validator); } - DataHeader decodeDataHeader() { - _validator.claimMemory(_base, _base + DataHeader.kHeaderSize); - int size = decodeUint32(DataHeader.kSizeOffset); - int numFields = decodeUint32(DataHeader.kNumFieldsOffset); + StructDataHeader decodeStructDataHeader() { + _validator.claimMemory(_base, _base + StructDataHeader.kHeaderSize); + int size = decodeUint32(StructDataHeader.kSizeOffset); + int version = decodeUint32(StructDataHeader.kVersionOffset); if (size < 0) { throw new MojoCodecError('Negative size.'); } - if (numFields < 0) { - throw new MojoCodecError('Negative number of fields.'); + if (version < 0) { + throw new MojoCodecError('Negative version number.'); } - _validator.claimMemory(_base + DataHeader.kHeaderSize, _base + size); - return new DataHeader(size, numFields); + _validator.claimMemory(_base + StructDataHeader.kHeaderSize, _base + size); + return new StructDataHeader(size, version); + } + + ArrayDataHeader decodeArrayDataHeader() { + _validator.claimMemory(_base, _base + ArrayDataHeader.kHeaderSize); + int size = decodeUint32(ArrayDataHeader.kSizeOffset); + int numElements = decodeUint32(ArrayDataHeader.kNumElementsOffset); + if (size < 0) { + throw new MojoCodecError('Negative size.'); + } + if (numElements < 0) { + throw new MojoCodecError('Negative number of elements.'); + } + _validator.claimMemory(_base + ArrayDataHeader.kHeaderSize, _base + size); + return new ArrayDataHeader(size, numElements); } // Decode arrays. - DataHeader decodeDataHeaderForBoolArray(int expectedLength) { - var header = decodeDataHeader(); - if (header.size < DataHeader.kHeaderSize + (header.numFields + 7) ~/ 8) { + ArrayDataHeader decodeDataHeaderForBoolArray(int expectedLength) { + var header = decodeArrayDataHeader(); + var arrayByteCount = + ArrayDataHeader.kHeaderSize + (header.numElements + 7) ~/ 8; + if (header.size < arrayByteCount) { throw new MojoCodecError('Array header is incorrect'); } if ((expectedLength != kUnspecifiedArrayLength) && - (header.numFields != expectedLength)) { + (header.numElements != expectedLength)) { throw new MojoCodecError( 'Incorrect array length. Expected $expectedLength, but got ' - '${header.numFields}.'); + '${header.numElements}.'); } return header; } @@ -625,9 +680,9 @@ var header = d.decodeDataHeaderForBoolArray(expectedLength); var bytes = new Uint8List.view( d._buffer.buffer, - d._buffer.offsetInBytes + d._base + DataHeader.kHeaderSize, - (header.numFields + 7) ~/ kAlignment); - var result = new List<bool>(header.numFields); + d._buffer.offsetInBytes + d._base + ArrayDataHeader.kHeaderSize, + (header.numElements + 7) ~/ kAlignment); + var result = new List<bool>(header.numElements); for (int i = 0; i < bytes.lengthInBytes; ++i) { for (int j = 0; j < kAlignment; ++j) { int boolIndex = i * kAlignment + j; @@ -639,22 +694,25 @@ return result; } - DataHeader decodeDataHeaderForArray(int elementSize, int expectedLength) { - var header = decodeDataHeader(); - if (header.size < DataHeader.kHeaderSize + header.numFields * elementSize) { + ArrayDataHeader decodeDataHeaderForArray(int elementSize, + int expectedLength) { + var header = decodeArrayDataHeader(); + var arrayByteCount = + ArrayDataHeader.kHeaderSize + header.numElements * elementSize; + if (header.size < arrayByteCount) { throw new MojoCodecError( 'Array header is incorrect: $header, elementSize = $elementSize'); } if ((expectedLength != kUnspecifiedArrayLength) && - (header.numFields != expectedLength)) { + (header.numElements != expectedLength)) { throw new MojoCodecError( 'Incorrect array length. Expected $expectedLength, but got ' - '${header.numFields}'); + '${header.numElements}'); } return header; } - DataHeader decodeDataHeaderForPointerArray(int expectedLength) => + ArrayDataHeader decodeDataHeaderForPointerArray(int expectedLength) => decodeDataHeaderForArray(kPointerSize, expectedLength); List decodeArray(Function arrayViewer, @@ -669,8 +727,8 @@ var header = d.decodeDataHeaderForArray(elementSize, expectedLength); return arrayViewer( d._buffer.buffer, - d._buffer.offsetInBytes + d._base + DataHeader.kHeaderSize, - header.numFields); + d._buffer.offsetInBytes + d._base + ArrayDataHeader.kHeaderSize, + header.numElements); } List<int> decodeInt8Array( @@ -732,11 +790,11 @@ return null; } var header = d.decodeDataHeaderForArray(4, expectedLength); - var result = new List(header.numFields); + var result = new List(header.numElements); for (int i = 0; i < result.length; ++i) { result[i] = elementDecoder( d, - DataHeader.kHeaderSize + kSerializedHandleSize * i, + ArrayDataHeader.kHeaderSize + kSerializedHandleSize * i, isElementNullable(nullability)); } return result; @@ -798,15 +856,15 @@ return _stringOfUtf8(bytes); } - DataHeader decodeDataHeaderForMap() { - var header = decodeDataHeader(); + StructDataHeader decodeDataHeaderForMap() { + var header = decodeStructDataHeader(); if (header.size != kMapStructHeader.size) { throw new MojoCodecError( 'Incorrect header for map. The size is incorrect.'); } - if (header.numFields != kMapStructHeader.numFields) { + if (header.version != kMapStructHeader.version) { throw new MojoCodecError( - 'Incorrect header for map. The number of fields is incorrect.'); + 'Incorrect header for map. The version is incorrect.'); } return header; }
diff --git a/third_party/mojo/src/mojo/public/dart/src/data_pipe.dart b/third_party/mojo/src/mojo/public/dart/src/data_pipe.dart index 7f3b3eb..9739be5 100644 --- a/third_party/mojo/src/mojo/public/dart/src/data_pipe.dart +++ b/third_party/mojo/src/mojo/public/dart/src/data_pipe.dart
@@ -93,7 +93,7 @@ class MojoDataPipeConsumer { static const int FLAG_NONE = 0; static const int FLAG_ALL_OR_NONE = 1 << 0; - static const int FLAG_MAY_DISCARD = 1 << 1; + static const int FLAG_DISCARD = 1 << 1; static const int FLAG_QUERY = 1 << 2; static const int FLAG_PEEK = 1 << 3; @@ -107,7 +107,7 @@ int read(ByteData data, [int numBytes = -1, int flags = 0]) { if (handle == null) { status = MojoResult.INVALID_ARGUMENT; - return status; + return 0; } int data_numBytes = (numBytes == -1) ? data.lengthInBytes : numBytes; @@ -115,7 +115,7 @@ handle.h, data, data_numBytes, flags); if (result == null) { status = MojoResult.INVALID_ARGUMENT; - return status; + return 0; } assert((result is List) && (result.length == 2)); status = new MojoResult(result[0]); @@ -156,7 +156,6 @@ class MojoDataPipe { static const int FLAG_NONE = 0; - static const int FLAG_MAY_DISCARD = 1 << 0; static const int DEFAULT_ELEMENT_SIZE = 1; static const int DEFAULT_CAPACITY = 0;
diff --git a/third_party/mojo/src/mojo/public/dart/src/drain_data.dart b/third_party/mojo/src/mojo/public/dart/src/drain_data.dart index ffc56e5..b5929e567 100644 --- a/third_party/mojo/src/mojo/public/dart/src/drain_data.dart +++ b/third_party/mojo/src/mojo/public/dart/src/drain_data.dart
@@ -16,12 +16,16 @@ _dataSize = 0; } + ByteData _copy(ByteData byteData) => + new ByteData.view( + new Uint8List.fromList(byteData.buffer.asUint8List()).buffer); + MojoResult _doRead() { ByteData thisRead = _consumer.beginRead(); if (thisRead == null) { throw 'Data pipe beginRead failed: ${_consumer.status}'; } - _dataList.add(thisRead); + _dataList.add(_copy(thisRead)); _dataSize += thisRead.lengthInBytes; return _consumer.endRead(thisRead.lengthInBytes); }
diff --git a/third_party/mojo/src/mojo/public/dart/src/event_stream.dart b/third_party/mojo/src/mojo/public/dart/src/event_stream.dart index 610285a3..8f022ac 100644 --- a/third_party/mojo/src/mojo/public/dart/src/event_stream.dart +++ b/third_party/mojo/src/mojo/public/dart/src/event_stream.dart
@@ -4,7 +4,7 @@ part of core; -class MojoEventStream extends Stream<int> { +class MojoEventStream extends Stream<List<int>> { // The underlying Mojo handle. MojoHandle _handle; @@ -26,11 +26,11 @@ // Whether listen has been called. bool _isListening; - MojoEventStream(MojoHandle handle, - [MojoHandleSignals signals = MojoHandleSignals.READABLE]) : - _handle = handle, - _signals = signals, - _isListening = false { + MojoEventStream(MojoHandle handle, [MojoHandleSignals signals = + MojoHandleSignals.PEER_CLOSED_READABLE]) + : _handle = handle, + _signals = signals, + _isListening = false { MojoResult result = MojoHandle.register(this); if (!result.isOk) { throw "Failed to register the MojoHandle: $result."; @@ -39,7 +39,11 @@ void close() { if (_handle != null) { - MojoHandleWatcher.close(_handle); + if (_isListening) { + MojoHandleWatcher.close(_handle); + } else { + _handle.close(); + } _handle = null; } if (_receivePort != null) { @@ -48,20 +52,20 @@ } } - StreamSubscription<List<int>> listen( - void onData(List event), + StreamSubscription<List<int>> listen(void onData(List event), {Function onError, void onDone(), bool cancelOnError}) { if (_isListening) { throw "Listen has already been called: $_handle."; } _receivePort = new ReceivePort(); _sendPort = _receivePort.sendPort; - _controller = new StreamController(sync: true, + _controller = new StreamController( + sync: true, onListen: _onSubscriptionStateChange, onCancel: _onSubscriptionStateChange, onPause: _onPauseStateChange, onResume: _onPauseStateChange); - _controller.addStream(_receivePort); + _controller.addStream(_receivePort).whenComplete(_controller.close); if (_signals != MojoHandleSignals.NONE) { var res = MojoHandleWatcher.add(_handle, _sendPort, _signals.value); @@ -88,7 +92,8 @@ } } - void enableReadEvents() => enableSignals(MojoHandleSignals.READABLE); + void enableReadEvents() => + enableSignals(MojoHandleSignals.PEER_CLOSED_READABLE); void enableWriteEvents() => enableSignals(MojoHandleSignals.WRITABLE); void enableAllEvents() => enableSignals(MojoHandleSignals.READWRITE); @@ -119,19 +124,19 @@ } abstract class Listener { - StreamSubscription<List<int>> listen(); + StreamSubscription<List<int>> listen({Function onClosed}); } -class MojoEventStreamListener implements Listener { +class MojoEventStreamListener { MojoMessagePipeEndpoint _endpoint; MojoEventStream _eventStream; bool _isOpen = false; bool _isInHandler = false; - MojoEventStreamListener(MojoMessagePipeEndpoint endpoint) : - _endpoint = endpoint, - _eventStream = new MojoEventStream(endpoint.handle), - _isOpen = false; + MojoEventStreamListener(MojoMessagePipeEndpoint endpoint) + : _endpoint = endpoint, + _eventStream = new MojoEventStream(endpoint.handle), + _isOpen = false; MojoEventStreamListener.fromHandle(MojoHandle handle) { _endpoint = new MojoMessagePipeEndpoint(handle); @@ -139,10 +144,10 @@ _isOpen = false; } - MojoEventStreamListener.unbound() : - _endpoint = null, - _eventStream = null, - _isOpen = false; + MojoEventStreamListener.unbound() + : _endpoint = null, + _eventStream = null, + _isOpen = false; void bind(MojoMessagePipeEndpoint endpoint) { assert(!isBound); @@ -158,13 +163,14 @@ _isOpen = false; } - StreamSubscription<List<int>> listen() { + StreamSubscription<List<int>> listen({Function onClosed}) { _isOpen = true; return _eventStream.listen((List<int> event) { var signalsWatched = new MojoHandleSignals(event[0]); var signalsReceived = new MojoHandleSignals(event[1]); if (signalsReceived.isPeerClosed) { - handlePeerClosed(); + if (onClosed != null) onClosed(); + close(); // The peer being closed obviates any other signal we might // have received since we won't be able to read or write the handle. // Thus, we just return before invoking other handlers. @@ -180,30 +186,23 @@ handleWrite(); } if (_isOpen) { - _eventStream.enableSignals(enableSignals( - signalsWatched, signalsReceived)); + _eventStream.enableSignals(signalsWatched); } _isInHandler = false; - }); + }, onDone: close); } void close() { - if (_isOpen) { + _isOpen = false; + _endpoint = null; + if (_eventStream != null) { _eventStream.close(); - _isOpen = false; _eventStream = null; - _endpoint = null; } } void handleRead() {} void handleWrite() {} - void handlePeerClosed() { - close(); - } - - MojoHandleSignals enableSignals(MojoHandleSignals watched, - MojoHandleSignals received) => watched; MojoMessagePipeEndpoint get endpoint => _endpoint; bool get isOpen => _isOpen;
diff --git a/third_party/mojo/src/mojo/public/dart/src/handle.dart b/third_party/mojo/src/mojo/public/dart/src/handle.dart index a8198043..53d0fe8 100644 --- a/third_party/mojo/src/mojo/public/dart/src/handle.dart +++ b/third_party/mojo/src/mojo/public/dart/src/handle.dart
@@ -7,11 +7,10 @@ class _MojoHandleNatives { static int register(MojoEventStream eventStream) native "MojoHandle_Register"; static int close(int handle) native "MojoHandle_Close"; - static List wait(int handle, int signals, int deadline) - native "MojoHandle_Wait"; - static List waitMany( - List<int> handles, List<int> signals, int deadline) - native "MojoHandle_WaitMany"; + static List wait(int handle, int signals, int deadline) native + "MojoHandle_Wait"; + static List waitMany(List<int> handles, List<int> signals, + int deadline) native "MojoHandle_WaitMany"; } @@ -50,14 +49,16 @@ } } - bool get readyRead => _ready(MojoHandleSignals.READABLE); + bool get readyRead => _ready(MojoHandleSignals.PEER_CLOSED_READABLE); bool get readyWrite => _ready(MojoHandleSignals.WRITABLE); - static MojoWaitManyResult waitMany( - List<int> handles, List<int> signals, int deadline) { + static MojoWaitManyResult waitMany(List<int> handles, List<int> signals, + int deadline) { List result = _MojoHandleNatives.waitMany(handles, signals, deadline); return new MojoWaitManyResult( - new MojoResult(result[0]), result[1], result[2]); + new MojoResult(result[0]), + result[1], + result[2]); } static MojoResult register(MojoEventStream eventStream) {
diff --git a/third_party/mojo/src/mojo/public/dart/src/handle_watcher.dart b/third_party/mojo/src/mojo/public/dart/src/handle_watcher.dart index da688d4..f69c981 100644 --- a/third_party/mojo/src/mojo/public/dart/src/handle_watcher.dart +++ b/third_party/mojo/src/mojo/public/dart/src/handle_watcher.dart
@@ -5,15 +5,13 @@ part of core; class _MojoHandleWatcherNatives { - static int sendControlData( - int controlHandle, int mojoHandle, SendPort port, int data) - native "MojoHandleWatcher_SendControlData"; - static List recvControlData(int controlHandle) - native "MojoHandleWatcher_RecvControlData"; - static int setControlHandle(int controlHandle) - native "MojoHandleWatcher_SetControlHandle"; - static int getControlHandle() - native "MojoHandleWatcher_GetControlHandle"; + static int sendControlData(int controlHandle, int mojoHandle, SendPort port, + int data) native "MojoHandleWatcher_SendControlData"; + static List recvControlData(int controlHandle) native + "MojoHandleWatcher_RecvControlData"; + static int setControlHandle(int controlHandle) native + "MojoHandleWatcher_SetControlHandle"; + static int getControlHandle() native "MojoHandleWatcher_GetControlHandle"; } // The MojoHandleWatcher sends a stream of events to application isolates that @@ -39,8 +37,14 @@ static const int SHUTDOWN = 4; static int _encodeCommand(int cmd, [int signals = 0]) => - (cmd << 2) | (signals & MojoHandleSignals.kReadWrite); - static int _decodeCommand(int cmd) => cmd >> 2; + (cmd << 3) | (signals & MojoHandleSignals.kAll); + static int _decodeCommand(int cmd) { + assert(MojoHandleSignals.kAll < 1 << 3); + return cmd >> 3; + } + static MojoHandleSignals _decodeSignals(int cmd) { + return new MojoHandleSignals(cmd & MojoHandleSignals.kAll); + } // The Mojo handle over which control messages are sent. int _controlHandle; @@ -69,18 +73,18 @@ // Priority queue of timers registered with the watcher. TimerQueue _timerQueue; - MojoHandleWatcher(this._controlHandle) : - _shutdown = false, - _handles = new List<int>(), - _ports = new List<SendPort>(), - _signals = new List<int>(), - _handleIndices = new Map<int, int>(), - _handleCount = 1, - _tempHandle = new MojoHandle(MojoHandle.INVALID), - _timerQueue = new TimerQueue() { + MojoHandleWatcher(this._controlHandle) + : _shutdown = false, + _handles = new List<int>(), + _ports = new List<SendPort>(), + _signals = new List<int>(), + _handleIndices = new Map<int, int>(), + _handleCount = 1, + _tempHandle = new MojoHandle(MojoHandle.INVALID), + _timerQueue = new TimerQueue() { // Setup control handle. _handles.add(_controlHandle); - _ports.add(null); // There is no port for the control handle. + _ports.add(null); // There is no port for the control handle. _signals.add(MojoHandleSignals.kReadable); _handleIndices[_controlHandle] = 0; } @@ -89,14 +93,17 @@ MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle); while (!watcher._shutdown) { int deadline = watcher._processTimerDeadlines(); - MojoWaitManyResult mwmr = MojoHandle.waitMany( - watcher._handles, watcher._signals, deadline); + MojoWaitManyResult mwmr = + MojoHandle.waitMany(watcher._handles, watcher._signals, deadline); if (mwmr.result.isOk && mwmr.index == 0) { watcher._handleControlMessage(); } else if (mwmr.result.isOk && (mwmr.index > 0)) { int handle = watcher._handles[mwmr.index]; + // Route event. - watcher._routeEvent(mwmr.index); + watcher._routeEvent( + mwmr.states[mwmr.index].satisfied_signals, + mwmr.index); // Remove the handle from the list. watcher._removeHandle(handle); } else if (!mwmr.result.isDeadlineExceeded) { @@ -107,20 +114,8 @@ } } - void _routeEvent(int idx) { - int client_handle = _handles[idx]; - var signals = new MojoHandleSignals(_signals[idx]); - SendPort port = _ports[idx]; - - _tempHandle.h = client_handle; - bool readyWrite = signals.isWritable && _tempHandle.readyWrite; - bool readyRead = signals.isReadable && _tempHandle.readyRead; - _tempHandle.h = MojoHandle.INVALID; - - var event = MojoHandleSignals.NONE; - event += readyRead ? MojoHandleSignals.READABLE : MojoHandleSignals.NONE; - event += readyWrite ? MojoHandleSignals.WRITABLE : MojoHandleSignals.NONE; - port.send([signals.value, event.value]); + void _routeEvent(int satisfiedSignals, int idx) { + _ports[idx].send([_signals[idx], satisfiedSignals & _signals[idx]]); } void _handleControlMessage() { @@ -129,8 +124,7 @@ // result[1] = SendPort if any. // result[2] = command << 2 | WRITABLE | READABLE - var signals = new MojoHandleSignals( - result[2] & MojoHandleSignals.kReadWrite); + var signals = _decodeSignals(result[2]); int command = _decodeCommand(result[2]); switch (command) { case ADD: @@ -199,7 +193,7 @@ } } - void _close(int mojoHandle, {bool pruning : false}) { + void _close(int mojoHandle, {bool pruning: false}) { int idx = _handleIndices[mojoHandle]; if (idx == null) { // A client may request to close a handle that has already been closed on @@ -229,8 +223,9 @@ _timerQueue.removeCurrent(); now = (new DateTime.now()).millisecondsSinceEpoch; } - return _timerQueue.hasTimer ? (_timerQueue.currentTimeout - now) * 1000 - : MojoHandle.DEADLINE_INDEFINITE; + return _timerQueue.hasTimer ? + (_timerQueue.currentTimeout - now) * 1000 : + MojoHandle.DEADLINE_INDEFINITE; } void _timer(SendPort port, int deadline) { @@ -247,7 +242,7 @@ } } else { _tempHandle.h = _handles[i]; - MojoWaitResult mwr = _tempHandle.wait(MojoHandleSignals.kReadWrite, 0); + MojoWaitResult mwr = _tempHandle.wait(MojoHandleSignals.kAll, 0); if ((!mwr.result.isOk) && (!mwr.result.isDeadlineExceeded)) { closed.add(_handles[i]); } @@ -269,9 +264,8 @@ shutdownSendPort.send(null); } - static MojoResult _sendControlData(MojoHandle mojoHandle, - SendPort port, - int data) { + static MojoResult _sendControlData(MojoHandle mojoHandle, SendPort port, + int data) { int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); if (controlHandle == MojoHandle.INVALID) { return MojoResult.FAILED_PRECONDITION; @@ -282,7 +276,10 @@ rawHandle = mojoHandle.h; } var result = _MojoHandleWatcherNatives.sendControlData( - controlHandle, rawHandle, port, data); + controlHandle, + rawHandle, + port, + data); return new MojoResult(result); } @@ -341,6 +338,8 @@ static MojoResult timer(Object ignored, SendPort port, int deadline) { // The deadline will be unwrapped before sending to the handle watcher. return _sendControlData( - new MojoHandle(deadline), port, _encodeCommand(TIMER)); + new MojoHandle(deadline), + port, + _encodeCommand(TIMER)); } }
diff --git a/third_party/mojo/src/mojo/public/dart/src/message.dart b/third_party/mojo/src/mojo/public/dart/src/message.dart index 918d219..9c7cf463 100644 --- a/third_party/mojo/src/mojo/public/dart/src/message.dart +++ b/third_party/mojo/src/mojo/public/dart/src/message.dart
@@ -6,16 +6,20 @@ class MessageHeader { static const int kSimpleMessageSize = 16; - static const int kSimpleMessageNumFields = 2; + // TODO(yzshen): In order to work with other bindings which still interprets + // the |version| field as |num_fields|, set it to version 2 for now. + static const int kSimpleMessageVersion = 2; static const int kMessageWithRequestIdSize = 24; - static const int kMessageWithRequestIdNumFields = 3; - static const int kMessageTypeOffset = DataHeader.kHeaderSize; + // TODO(yzshen): In order to work with other bindings which still interprets + // the |version| field as |num_fields|, set it to version 3 for now. + static const int kMessageWithRequestIdVersion = 3; + static const int kMessageTypeOffset = StructDataHeader.kHeaderSize; static const int kMessageFlagsOffset = kMessageTypeOffset + 4; static const int kMessageRequestIdOffset = kMessageFlagsOffset + 4; static const int kMessageExpectsResponse = 1 << 0; static const int kMessageIsResponse = 1 << 1; - DataHeader _header; + StructDataHeader _header; int type; int flags; int requestId; @@ -24,17 +28,17 @@ (flags & (kMessageExpectsResponse | kMessageIsResponse)) != 0; MessageHeader(this.type) : - _header = new DataHeader(kSimpleMessageSize, kSimpleMessageNumFields), + _header = new StructDataHeader(kSimpleMessageSize, kSimpleMessageVersion), flags = 0, requestId = 0; MessageHeader.withRequestId(this.type, this.flags, this.requestId) : - _header = new DataHeader( - kMessageWithRequestIdSize, kMessageWithRequestIdNumFields); + _header = new StructDataHeader( + kMessageWithRequestIdSize, kMessageWithRequestIdVersion); MessageHeader.fromMessage(Message message) { var decoder = new Decoder(message); - _header = decoder.decodeDataHeader(); + _header = decoder.decodeStructDataHeader(); if (_header.size < kSimpleMessageSize) { throw new MojoCodecError( 'Incorrect message size. Got: ${_header.size} ' @@ -58,7 +62,7 @@ bool get hasRequestId => mustHaveRequestId(flags); void encode(Encoder encoder) { - encoder.encodeDataHeader(_header); + encoder.encodeStructDataHeader(_header); encoder.encodeUint32(type, kMessageTypeOffset); encoder.encodeUint32(flags, kMessageFlagsOffset); if (hasRequestId) { @@ -76,25 +80,25 @@ bool validateHeader(int expectedType, int expectedFlags) => (type == expectedType) && validateHeaderFlags(expectedFlags); - static void _validateDataHeader(DataHeader dataHeader) { - if (dataHeader.numFields < kSimpleMessageNumFields) { - throw 'Incorrect number of fields, expecting at least ' - '$kSimpleMessageNumFields, but got: ${dataHeader.numFields}.'; + static void _validateDataHeader(StructDataHeader dataHeader) { + if (dataHeader.version < kSimpleMessageVersion) { + throw 'Incorrect version, expecting at least ' + '$kSimpleMessageVersion, but got: ${dataHeader.version}.'; } if (dataHeader.size < kSimpleMessageSize) { throw 'Incorrect message size, expecting at least $kSimpleMessageSize, ' 'but got: ${dataHeader.size}'; } - if ((dataHeader.numFields == kSimpleMessageSize) && + if ((dataHeader.version == kSimpleMessageVersion) && (dataHeader.size != kSimpleMessageSize)) { - throw 'Incorrect message size for a message with $kSimpleMessageNumFields' - ' fields, expecting $kSimpleMessageSize, ' + throw 'Incorrect message size for a message of version ' + '$kSimpleMessageVersion, expecting $kSimpleMessageSize, ' 'but got ${dataHeader.size}'; } - if ((dataHeader.numFields == kMessageWithRequestIdNumFields) && + if ((dataHeader.version == kMessageWithRequestIdVersion) && (dataHeader.size != kMessageWithRequestIdSize)) { - throw 'Incorrect message size for a message with ' - '$kMessageWithRequestIdNumFields fields, expecting ' + throw 'Incorrect message size for a message of version ' + '$kMessageWithRequestIdVersion, expecting ' '$kMessageWithRequestIdSize, but got ${dataHeader.size}'; } }
diff --git a/third_party/mojo/src/mojo/public/dart/src/message_pipe.dart b/third_party/mojo/src/mojo/public/dart/src/message_pipe.dart index 7733d33..f1d1a4b 100644 --- a/third_party/mojo/src/mojo/public/dart/src/message_pipe.dart +++ b/third_party/mojo/src/mojo/public/dart/src/message_pipe.dart
@@ -33,7 +33,7 @@ class MojoMessagePipeEndpoint { static const int WRITE_FLAG_NONE = 0; static const int READ_FLAG_NONE = 0; - static const int READ_FLAG_MAY_DISCARD = 0; + static const int READ_FLAG_MAY_DISCARD = 1 << 0; MojoHandle handle; MojoResult status;
diff --git a/third_party/mojo/src/mojo/public/dart/src/proxy.dart b/third_party/mojo/src/mojo/public/dart/src/proxy.dart index 1186232..f7c770f 100644 --- a/third_party/mojo/src/mojo/public/dart/src/proxy.dart +++ b/third_party/mojo/src/mojo/public/dart/src/proxy.dart
@@ -50,7 +50,7 @@ serviceMessage.buffer.lengthInBytes, serviceMessage.handles); if (!endpoint.status.isOk) { - throw "message pipe write failed"; + throw "message pipe write failed - ${endpoint.status}"; } } @@ -69,7 +69,7 @@ serviceMessage.buffer.lengthInBytes, serviceMessage.handles); if (!endpoint.status.isOk) { - throw "message pipe write failed"; + throw "message pipe write failed - ${endpoint.status}"; } var completer = new Completer(); @@ -80,3 +80,10 @@ // Need a getter for this for access in subclasses. Map<int, Completer> get completerMap => _completerMap; } + + +// Generated Proxy classes implement this interface. +abstract class ProxyBase { + final Proxy impl; + final String name; +}
diff --git a/third_party/mojo/src/mojo/public/dart/src/service_provider.dart b/third_party/mojo/src/mojo/public/dart/src/service_provider.dart deleted file mode 100644 index 6b07f2e..0000000 --- a/third_party/mojo/src/mojo/public/dart/src/service_provider.dart +++ /dev/null
@@ -1,40 +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. - -part of application; - -typedef core.Listener ListenerFactory(core.MojoMessagePipeEndpoint endpoint); - -class ServiceProvider extends service_provider.ServiceProvider { - ListenerFactory factory; - - service_provider.ServiceProviderProxy _proxy; - - ServiceProvider( - service_provider.ServiceProviderStub services, - [service_provider.ServiceProviderProxy exposedServices = null]) - : _proxy = exposedServices, - super.fromStub(services) { - delegate = this; - } - - connectToService(String interfaceName, core.MojoMessagePipeEndpoint pipe) => - factory(pipe).listen(); - - requestService(String name, bindings.Proxy clientImpl) { - assert(_proxy != null); - assert(!clientImpl.isBound); - var pipe = new core.MojoMessagePipe(); - clientImpl.bind(pipe.endpoints[0]); - _proxy.connectToService(name, pipe.endpoints[1]); - } - - close({bool nodefer : false}) { - if (_proxy != null) { - _proxy.close(); - _proxy = null; - } - super.close(nodefer: nodefer); - } -}
diff --git a/third_party/mojo/src/mojo/public/dart/src/struct.dart b/third_party/mojo/src/mojo/public/dart/src/struct.dart index 01117324..d4ac3659 100644 --- a/third_party/mojo/src/mojo/public/dart/src/struct.dart +++ b/third_party/mojo/src/mojo/public/dart/src/struct.dart
@@ -4,18 +4,6 @@ part of bindings; -class DataHeader { - static const int kHeaderSize = 8; - static const int kSizeOffset = 0; - static const int kNumFieldsOffset = 4; - final int size; - final int numFields; - - const DataHeader(this.size, this.numFields); - - String toString() => "DataHeader($size, $numFields)"; -} - abstract class Struct { final int encodedSize;
diff --git a/third_party/mojo/src/mojo/public/dart/src/stub.dart b/third_party/mojo/src/mojo/public/dart/src/stub.dart index 8238736..1ce0982 100644 --- a/third_party/mojo/src/mojo/public/dart/src/stub.dart +++ b/third_party/mojo/src/mojo/public/dart/src/stub.dart
@@ -40,9 +40,10 @@ responseFuture.then((response) { _outstandingResponseFutures--; if (isOpen) { - endpoint.write(response.buffer, - response.buffer.lengthInBytes, - response.handles); + endpoint.write( + response.buffer, + response.buffer.lengthInBytes, + response.handles); if (!endpoint.status.isOk) { throw 'message pipe write failed: ${endpoint.status}'; } @@ -69,9 +70,10 @@ // NB: |nodefer| should only be true when calling close() while handling an // exception thrown from handleRead(), e.g. when we receive a malformed // message. - void close({bool nodefer : false}) { - if (!isOpen) return; - if (!nodefer && (isInHandler || (_outstandingResponseFutures > 0))) { + void close({bool nodefer: false}) { + if (isOpen && + !nodefer && + (isInHandler || (_outstandingResponseFutures > 0))) { // Either close() is being called from within handleRead() or // handleWrite(), or close() is being called while there are outstanding // response futures. Defer the actual close until all response futures
diff --git a/third_party/mojo/src/mojo/public/go/bindings/async_waiter.go b/third_party/mojo/src/mojo/public/go/bindings/async_waiter.go new file mode 100644 index 0000000..ebe42cc --- /dev/null +++ b/third_party/mojo/src/mojo/public/go/bindings/async_waiter.go
@@ -0,0 +1,268 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package bindings + +import ( + "fmt" + "sync" + "sync/atomic" + + "mojo/public/go/system" +) + +var defaultWaiter *asyncWaiterImpl +var once sync.Once + +// GetAsyncWaiter returns a default implementation of |AsyncWaiter| interface. +func GetAsyncWaiter() AsyncWaiter { + once.Do(func() { + defaultWaiter = newAsyncWaiter() + }) + return defaultWaiter +} + +// AsyncWaitId is an id returned by |AsyncWait()| used to cancel it. +type AsyncWaitId uint64 + +// WaitResponse is a struct sent to a channel waiting for |AsyncWait()| to +// finish. It contains the same information as if |Wait()| was called on a +// handle. +type WaitResponse struct { + Result system.MojoResult + State system.MojoHandleSignalsState +} + +// AsyncWaiter defines an interface for asynchronously waiting (and cancelling +// asynchronous waits) on a handle. +type AsyncWaiter interface { + // AsyncWait asynchronously waits on a given handle until a signal + // indicated by |signals| is satisfied or it becomes known that no + // signal indicated by |signals| will ever be satisified. The wait + // response will be sent to |responseChan|. + // + // |handle| must not be closed or transferred until the wait response + // is received from |responseChan|. + AsyncWait(handle system.Handle, signals system.MojoHandleSignals, responseChan chan<- WaitResponse) AsyncWaitId + + // CancelWait cancels an outstanding async wait (specified by |id|) + // initiated by |AsyncWait()|. A response with Mojo result + // |MOJO_RESULT_ABORTED| is sent to the corresponding |responseChan|. + CancelWait(id AsyncWaitId) +} + +// waitRequest is a struct sent to asyncWaiterWorker to add another handle to +// the list of waiting handles. +type waitRequest struct { + handle system.Handle + signals system.MojoHandleSignals + + // Used for |CancelWait()| calls. The worker should issue IDs so that + // you can't cancel the wait until the worker received the wait request. + idChan chan<- AsyncWaitId + + // A channel end to send wait results. + responseChan chan<- WaitResponse +} + +// asyncWaiterWorker does the actual work, in its own goroutine. It calls +// |WaitMany()| on all provided handles. New handles a added via |waitChan| +// and removed via |cancelChan| messages. To wake the worker asyncWaiterImpl +// sends mojo messages to a dedicated message pipe, the other end of which has +// index 0 in all slices of the worker. +type asyncWaiterWorker struct { + // |handles| and |signals| are used to make |WaitMany()| calls directly. + // All these arrays should be operated simultaneously; i-th element + // of each refers to i-th handle. + handles []system.Handle + signals []system.MojoHandleSignals + asyncWaitIds []AsyncWaitId + responses []chan<- WaitResponse + + // Flag shared between waiterImpl and worker that is 1 iff the worker is + // already notified by waiterImpl. The worker sets it to 0 as soon as + // |WaitMany()| succeeds. + isNotified *int32 + waitChan <-chan waitRequest // should have a non-empty buffer + cancelChan <-chan AsyncWaitId // should have a non-empty buffer + ids Counter // is incremented each |AsyncWait()| call +} + +// removeHandle removes handle at provided index without sending response by +// swapping all information associated with index-th handle with the last one +// and removing the last one. +func (w *asyncWaiterWorker) removeHandle(index int) { + l := len(w.handles) - 1 + // Swap with the last and remove last. + w.handles[index] = w.handles[l] + w.handles = w.handles[0:l] + w.signals[index] = w.signals[l] + w.signals = w.signals[0:l] + + w.asyncWaitIds[index] = w.asyncWaitIds[l] + w.asyncWaitIds = w.asyncWaitIds[0:l] + w.responses[index] = w.responses[l] + w.responses = w.responses[0:l] +} + +// sendWaitResponseAndRemove send response to corresponding channel and removes +// index-th waiting handle. +func (w *asyncWaiterWorker) sendWaitResponseAndRemove(index int, result system.MojoResult, state system.MojoHandleSignalsState) { + w.responses[index] <- WaitResponse{ + result, + state, + } + w.removeHandle(index) +} + +// respondToSatisfiedWaits responds to all wait requests that have at least +// one satisfied signal and removes them. +func (w *asyncWaiterWorker) respondToSatisfiedWaits(states []system.MojoHandleSignalsState) { + // Don't touch handle at index 0 as it is the waking handle. + for i := 1; i < len(states); { + if (states[i].SatisfiedSignals & w.signals[i]) != 0 { + // Respond and swap i-th with last and remove last. + w.sendWaitResponseAndRemove(i, system.MOJO_RESULT_OK, states[i]) + // Swap i-th with last and remove last. + states[i] = states[len(states)-1] + states = states[:len(states)-1] + } else { + i++ + } + } +} + +// processIncomingRequests processes all queued async wait or cancel requests +// sent by asyncWaiterImpl. +func (w *asyncWaiterWorker) processIncomingRequests() { + for { + select { + case request := <-w.waitChan: + w.handles = append(w.handles, request.handle) + w.signals = append(w.signals, request.signals) + w.responses = append(w.responses, request.responseChan) + + id := AsyncWaitId(w.ids.Next()) + w.asyncWaitIds = append(w.asyncWaitIds, id) + request.idChan <- id + case AsyncWaitId := <-w.cancelChan: + // Zero index is reserved for the waking message pipe handle. + index := 0 + for i := 1; i < len(w.asyncWaitIds); i++ { + if w.asyncWaitIds[i] == AsyncWaitId { + index = i + break + } + } + // Do nothing if the id was not found as wait response may be + // already sent if the async wait was successful. + if index > 0 { + w.sendWaitResponseAndRemove(index, system.MOJO_RESULT_ABORTED, system.MojoHandleSignalsState{}) + } + default: + return + } + } +} + +// runLoop run loop of the asyncWaiterWorker. Blocks on |WaitMany()|. If the +// wait is interrupted by waking handle (index 0) then it means that the worker +// was woken by waiterImpl, so the worker processes incoming requests from +// waiterImpl; otherwise responses to corresponding wait request. +func (w *asyncWaiterWorker) runLoop() { + for { + result, index, states := system.GetCore().WaitMany(w.handles, w.signals, system.MOJO_DEADLINE_INDEFINITE) + // Set flag to 0, so that the next incoming request to + // waiterImpl would explicitly wake worker by sending a message + // to waking message pipe. + atomic.StoreInt32(w.isNotified, 0) + if index == -1 { + panic(fmt.Sprintf("error waiting on handles: %v", result)) + break + } + // Zero index means that the worker was signaled by asyncWaiterImpl. + if index == 0 { + if result != system.MOJO_RESULT_OK { + panic(fmt.Sprintf("error waiting on waking handle: %v", result)) + } + w.handles[0].(system.MessagePipeHandle).ReadMessage(system.MOJO_READ_MESSAGE_FLAG_NONE) + w.processIncomingRequests() + } else if result != system.MOJO_RESULT_OK { + w.sendWaitResponseAndRemove(index, result, system.MojoHandleSignalsState{}) + } else { + w.respondToSatisfiedWaits(states) + } + } +} + +// asyncWaiterImpl is an implementation of |AsyncWaiter| interface. +// Runs a worker in a separate goroutine and comunicates with it by sending a +// message to |wakingHandle| to wake worker from |WaitMany()| call and +// sending request via |waitChan| and |cancelChan|. +type asyncWaiterImpl struct { + wakingHandle system.MessagePipeHandle + + // Flag shared between waiterImpl and worker that is 1 iff the worker is + // already notified by waiterImpl. The worker sets it to 0 as soon as + // |WaitMany()| succeeds. + isWorkerNotified *int32 + waitChan chan<- waitRequest // should have a non-empty buffer + cancelChan chan<- AsyncWaitId // should have a non-empty buffer +} + +// newAsyncWaiter creates an asyncWaiterImpl and starts its worker goroutine. +func newAsyncWaiter() *asyncWaiterImpl { + result, h0, h1 := system.GetCore().CreateMessagePipe(nil) + if result != system.MOJO_RESULT_OK { + panic(fmt.Sprintf("can't create message pipe %v", result)) + } + waitChan := make(chan waitRequest, 10) + cancelChan := make(chan AsyncWaitId, 10) + isNotified := new(int32) + worker := asyncWaiterWorker{ + []system.Handle{h1}, + []system.MojoHandleSignals{system.MOJO_HANDLE_SIGNAL_READABLE}, + []AsyncWaitId{0}, + []chan<- WaitResponse{make(chan WaitResponse)}, + isNotified, + waitChan, + cancelChan, + Counter{}, + } + go worker.runLoop() + return &asyncWaiterImpl{ + wakingHandle: h0, + isWorkerNotified: isNotified, + waitChan: waitChan, + cancelChan: cancelChan, + } +} + +// wakeWorker wakes the worker from |WaitMany()| call. This should be called +// after sending a message to |waitChan| or |cancelChan| to avoid deadlock. +func (w *asyncWaiterImpl) wakeWorker() { + if atomic.CompareAndSwapInt32(w.isWorkerNotified, 0, 1) { + result := w.wakingHandle.WriteMessage([]byte{0}, nil, system.MOJO_WRITE_MESSAGE_FLAG_NONE) + if result != system.MOJO_RESULT_OK { + panic("can't write to a message pipe") + } + } +} + +func (w *asyncWaiterImpl) AsyncWait(handle system.Handle, signals system.MojoHandleSignals, responseChan chan<- WaitResponse) AsyncWaitId { + idChan := make(chan AsyncWaitId, 1) + w.waitChan <- waitRequest{ + handle, + signals, + idChan, + responseChan, + } + w.wakeWorker() + return <-idChan +} + +func (w *asyncWaiterImpl) CancelWait(id AsyncWaitId) { + w.cancelChan <- id + w.wakeWorker() +}
diff --git a/third_party/mojo/src/mojo/public/go/bindings/connector.go b/third_party/mojo/src/mojo/public/go/bindings/connector.go new file mode 100644 index 0000000..00c4cfd --- /dev/null +++ b/third_party/mojo/src/mojo/public/go/bindings/connector.go
@@ -0,0 +1,96 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package bindings + +import ( + "fmt" + "sync" + + "mojo/public/go/system" +) + +// Connector owns a message pipe handle. It can read and write messages +// from the message pipe waiting on it if necessary. The operation are +// thread-safe. +type Connector struct { + mu sync.RWMutex // protects pipe handle + pipe system.MessagePipeHandle + + done chan struct{} + waitMutex sync.Mutex + waiter AsyncWaiter + waitChan chan WaitResponse +} + +// NewStubConnector returns a new |Connector| instance that sends and +// receives messages from a provided message pipe handle. +func NewConnector(pipe system.MessagePipeHandle, waiter AsyncWaiter) *Connector { + return &Connector{ + pipe: pipe, + waiter: waiter, + done: make(chan struct{}), + waitChan: make(chan WaitResponse, 1), + } +} + +// ReadMessage reads a message from message pipe waiting on it if necessary. +func (c *Connector) ReadMessage() (*Message, error) { + // Make sure that only one goroutine at a time waits a the handle. + // We use separate lock so that we can send messages to the message pipe + // while waiting on the pipe. + // + // It is better to acquire this lock first so that a potential queue of + // readers will wait while closing the message pipe in case of Close() + // call. + c.waitMutex.Lock() + defer c.waitMutex.Unlock() + // Use read lock to use pipe handle without modifying it. + c.mu.RLock() + defer c.mu.RUnlock() + + if !c.pipe.IsValid() { + return nil, fmt.Errorf("message pipe is closed") + } + // Check if we already have a message. + result, bytes, handles := c.pipe.ReadMessage(system.MOJO_READ_MESSAGE_FLAG_NONE) + if result == system.MOJO_RESULT_SHOULD_WAIT { + waitId := c.waiter.AsyncWait(c.pipe, system.MOJO_HANDLE_SIGNAL_READABLE, c.waitChan) + select { + case <-c.waitChan: + result, bytes, handles = c.pipe.ReadMessage(system.MOJO_READ_MESSAGE_FLAG_NONE) + if result != system.MOJO_RESULT_OK { + return nil, fmt.Errorf("error reading message: %v", result) + } + case <-c.done: + c.waiter.CancelWait(waitId) + return nil, fmt.Errorf("server stub is closed") + } + } else if result != system.MOJO_RESULT_OK { + return nil, fmt.Errorf("error reading message: %v", result) + } + return ParseMessage(bytes, handles) +} + +// WriteMessage writes a message to the message pipe. +func (c *Connector) WriteMessage(message *Message) error { + // Use read lock to use pipe handle without modifying it. + c.mu.RLock() + defer c.mu.RUnlock() + if !c.pipe.IsValid() { + return fmt.Errorf("message pipe is closed") + } + return WriteMessage(c.pipe, message) +} + +// Close closes the message pipe aborting wait on the message pipe. +// Panics if you try to close the |Connector| more than once. +func (c *Connector) Close() { + // Stop waiting to acquire the lock. + close(c.done) + // Use write lock to modify the pipe handle. + c.mu.Lock() + c.pipe.Close() + c.mu.Unlock() +}
diff --git a/third_party/mojo/src/mojo/public/go/bindings/decoder.go b/third_party/mojo/src/mojo/public/go/bindings/decoder.go index 3f3cce9..6f6b4330 100644 --- a/third_party/mojo/src/mojo/public/go/bindings/decoder.go +++ b/third_party/mojo/src/mojo/public/go/bindings/decoder.go
@@ -68,11 +68,15 @@ if err := d.claimData(int(header.Size - dataHeaderSize)); err != nil { return err } + elements := uint32(0) + if elementBitSize != 0 { + elements = header.ElementsOrVersion + } d.stateStack = append(d.stateStack, encodingState{ offset: oldEnd, limit: d.end, elementBitSize: elementBitSize, - elements: header.Elements, + elements: elements, }) return nil } @@ -94,13 +98,14 @@ if err != nil { return 0, err } - if got, want := int(header.Size), dataHeaderSize+bytesForBits(uint64(header.Elements)*uint64(elementBitSize)); got < want { + minSize := bytesForBits(uint64(header.ElementsOrVersion) * uint64(elementBitSize)) + if got, want := int(header.Size), dataHeaderSize+minSize; got < want { return 0, fmt.Errorf("data header size is too small: is %d, but should be at least %d", got, want) } if err := d.pushState(header, elementBitSize); err != nil { return 0, err } - return header.Elements, nil + return header.ElementsOrVersion, nil } // StartMap starts decoding a map and reads its data header. @@ -120,8 +125,8 @@ return nil } -// StartArray starts decoding a struct and reads its data header, -// returning number of fields declared in data header. +// StartStruct starts decoding a struct and reads its data header, +// returning struct version declared in data header. // Note: it doesn't read a pointer to the encoded struct. // Call |Finish()| after reading all fields. func (d *Decoder) StartStruct() (uint32, error) { @@ -135,7 +140,7 @@ if err := d.pushState(header, 0); err != nil { return 0, err } - return header.Elements, nil + return header.ElementsOrVersion, nil } func (d *Decoder) readDataHeader() (DataHeader, error) { @@ -144,8 +149,8 @@ } oldEnd := d.end - dataHeaderSize header := DataHeader{ - Size: binary.LittleEndian.Uint32(d.buf[oldEnd:]), - Elements: binary.LittleEndian.Uint32(d.buf[oldEnd+4:]), + Size: binary.LittleEndian.Uint32(d.buf[oldEnd:]), + ElementsOrVersion: binary.LittleEndian.Uint32(d.buf[oldEnd+4:]), } return header, nil }
diff --git a/third_party/mojo/src/mojo/public/go/bindings/encoder.go b/third_party/mojo/src/mojo/public/go/bindings/encoder.go index 5ea1a50c..542cc21 100644 --- a/third_party/mojo/src/mojo/public/go/bindings/encoder.go +++ b/third_party/mojo/src/mojo/public/go/bindings/encoder.go
@@ -74,10 +74,10 @@ if state == nil { return fmt.Errorf("empty state stack") } - if state.elementBitSize > 0 && state.elementBitSize != bitSize { + if state.elementBitSize != 0 && state.elementBitSize != bitSize { return fmt.Errorf("unexpected element bit size: expected %d, but got %d", state.elementBitSize, bitSize) } - if state.elementsProcessed >= state.elements { + if state.elementBitSize != 0 && state.elementsProcessed >= state.elements { return fmt.Errorf("can't process more than elements defined in header(%d)", state.elements) } byteSize := bytesForBits(uint64(state.bitOffset + bitSize)) @@ -112,11 +112,15 @@ func (e *Encoder) pushState(header DataHeader, elementBitSize uint32) { oldEnd := e.end e.claimData(align(int(header.Size), defaultAlignment)) + elements := uint32(0) + if elementBitSize != 0 { + elements = header.ElementsOrVersion + } e.stateStack = append(e.stateStack, encodingState{ offset: oldEnd, limit: e.end, elementBitSize: elementBitSize, - elements: header.Elements, + elements: elements, }) e.writeDataHeader(header) } @@ -153,15 +157,15 @@ // StartStruct starts encoding a struct and writes its data header. // Note: it doesn't write a pointer to the encoded struct. // Call |Finish()| after writing all fields. -func (e *Encoder) StartStruct(size, numFields uint32) { +func (e *Encoder) StartStruct(size, version uint32) { dataSize := dataHeaderSize + int(size) - header := DataHeader{uint32(dataSize), numFields} + header := DataHeader{uint32(dataSize), version} e.pushState(header, 0) } func (e *Encoder) writeDataHeader(header DataHeader) { binary.LittleEndian.PutUint32(e.buf[e.state().offset:], header.Size) - binary.LittleEndian.PutUint32(e.buf[e.state().offset+4:], header.Elements) + binary.LittleEndian.PutUint32(e.buf[e.state().offset+4:], header.ElementsOrVersion) e.state().offset += 8 } @@ -171,7 +175,7 @@ if e.state() == nil { return fmt.Errorf("state stack is empty") } - if e.state().elementsProcessed != e.state().elements { + if e.state().elementBitSize != 0 && e.state().elementsProcessed != e.state().elements { return fmt.Errorf("unexpected number of elements written: defined in header %d, but written %d", e.state().elements, e.state().elementsProcessed) } e.popState()
diff --git a/third_party/mojo/src/mojo/public/go/bindings/interface.go b/third_party/mojo/src/mojo/public/go/bindings/interface.go new file mode 100644 index 0000000..9e449ad --- /dev/null +++ b/third_party/mojo/src/mojo/public/go/bindings/interface.go
@@ -0,0 +1,66 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package bindings + +import ( + "mojo/public/go/system" +) + +// MessagePipeHandleOwner owns a message pipe handle, it can only pass it +// invalidating itself or close it. +type MessagePipeHandleOwner struct { + handle system.MessagePipeHandle +} + +// PassMessagePipe passes ownership of the underlying message pipe handle to +// the newly created handle object, invalidating the underlying handle object +// in the process. +func (o *MessagePipeHandleOwner) PassMessagePipe() system.MessagePipeHandle { + if o.handle == nil { + return &InvalidHandle{} + } + return o.handle.ToUntypedHandle().ToMessagePipeHandle() +} + +// Close closes the underlying handle. +func (o *MessagePipeHandleOwner) Close() { + if o.handle != nil { + o.handle.Close() + } +} + +// NewMessagePipeHandleOwner creates |MessagePipeHandleOwner| that owns the +// provided message pipe handle. +func NewMessagePipeHandleOwner(handle system.MessagePipeHandle) MessagePipeHandleOwner { + return MessagePipeHandleOwner{handle} +} + +// InterfaceRequest represents a request from a remote client for an +// implementation of mojo interface over a specified message pipe. The +// implementor of the interface should remove the message pipe by calling +// PassMessagePipe() and attach it to the implementation. +type InterfaceRequest struct { + MessagePipeHandleOwner +} + +// InterfacePointer owns a message pipe handle with an implementation of mojo +// interface attached to the other end of the message pipe. The client of the +// interface should remove the message pipe by calling PassMessagePipe() and +// attach it to the proxy. +type InterfacePointer struct { + MessagePipeHandleOwner +} + +// CreateMessagePipeForInterface creates a message pipe with interface request +// on one end and interface pointer on the other end. The interface request +// should be attached to appropriate mojo interface implementation and +// the interface pointer should be attached to mojo interface proxy. +func CreateMessagePipeForMojoInterface() (InterfaceRequest, InterfacePointer) { + r, h0, h1 := system.GetCore().CreateMessagePipe(nil) + if r != system.MOJO_RESULT_OK { + panic("can't create a message pipe") + } + return InterfaceRequest{MessagePipeHandleOwner{h0}}, InterfacePointer{MessagePipeHandleOwner{h1}} +}
diff --git a/third_party/mojo/src/mojo/public/go/bindings/message.go b/third_party/mojo/src/mojo/public/go/bindings/message.go index 786ec47..e5c8329 100644 --- a/third_party/mojo/src/mojo/public/go/bindings/message.go +++ b/third_party/mojo/src/mojo/public/go/bindings/message.go
@@ -40,8 +40,8 @@ // DataHeader is a header for a mojo complex element. type DataHeader struct { - Size uint32 - Elements uint32 + Size uint32 + ElementsOrVersion uint32 } // MessageHeader is a header information for a message.
diff --git a/third_party/mojo/src/mojo/public/go/bindings/router.go b/third_party/mojo/src/mojo/public/go/bindings/router.go new file mode 100644 index 0000000..84a5d3c --- /dev/null +++ b/third_party/mojo/src/mojo/public/go/bindings/router.go
@@ -0,0 +1,226 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package bindings + +import ( + "fmt" + "sync" + + "mojo/public/go/system" +) + +// MessageReadResult contains information returned after reading and parsing +// a message: a non-nil error of a valid message. +type MessageReadResult struct { + Message *Message + Error error +} + +// routeRequest is a request sent from Router to routerWorker. +type routeRequest struct { + // The outgoing message with non-zero request id. + message *Message + // The channel to send respond for the message. + responseChan chan<- MessageReadResult +} + +// routerWorker sends messages that require a response and and routes responses +// to appropriate receivers. The work is done on a separate go routine. +type routerWorker struct { + // The message pipe handle to send requests and receive responses. + handle system.MessagePipeHandle + // Map from request id to response channel. + responders map[uint64]chan<- MessageReadResult + // The channel of incoming requests that require responses. + requestChan <-chan routeRequest + // The channel that indicates that the worker should terminate. + done <-chan struct{} + // Implementation of async waiter. + waiter AsyncWaiter + waitChan chan WaitResponse + waitId AsyncWaitId +} + +// readOutstandingMessages reads and dispatches available messages in the +// message pipe until the messages is empty or there are no waiting responders. +// If the worker is currently waiting on the message pipe, returns immediately +// without an error. +func (w *routerWorker) readAndDispatchOutstandingMessages() error { + if w.waitId != 0 { + // Still waiting for a new message in the message pipe. + return nil + } + for len(w.responders) > 0 { + result, bytes, handles := w.handle.ReadMessage(system.MOJO_READ_MESSAGE_FLAG_NONE) + if result == system.MOJO_RESULT_SHOULD_WAIT { + w.waitId = w.waiter.AsyncWait(w.handle, system.MOJO_HANDLE_SIGNAL_READABLE, w.waitChan) + return nil + } + if result != system.MOJO_RESULT_OK { + return fmt.Errorf("error reading message: %v", result) + } + message, err := ParseMessage(bytes, handles) + if err != nil { + return err + } + id := message.Header.RequestId + w.responders[id] <- MessageReadResult{message, nil} + delete(w.responders, id) + } + return nil +} + +func (w *routerWorker) cancelIfWaiting() { + if w.waitId != 0 { + w.waiter.CancelWait(w.waitId) + w.waitId = 0 + } +} + +// runLoop is the main run loop of the worker. It processes incoming requests +// from Router and waits on a message pipe for new messages. +// Returns an error describing the cause of stopping. +func (w *routerWorker) runLoop() error { + for { + select { + case waitResponse := <-w.waitChan: + w.waitId = 0 + if waitResponse.Result != system.MOJO_RESULT_OK { + return fmt.Errorf("error waiting for message: %v", waitResponse.Result) + } + case request := <-w.requestChan: + if err := WriteMessage(w.handle, request.message); err != nil { + return err + } + if request.responseChan != nil { + w.responders[request.message.Header.RequestId] = request.responseChan + } + case <-w.done: + return fmt.Errorf("message pipe is closed") + } + // Returns immediately without an error if still waiting for + // a new message. + if err := w.readAndDispatchOutstandingMessages(); err != nil { + return err + } + } +} + +// Router sends messages to a message pipe and routes responses back to senders +// of messages with non-zero request ids. The caller should issue unique request +// ids for each message given to the router. +type Router struct { + // Mutex protecting requestChan from new requests in case the router is + // closed and the handle. + mu sync.Mutex + // The message pipe handle to send requests and receive responses. + handle system.MessagePipeHandle + // Channel to communicate with worker. + requestChan chan<- routeRequest + + // Channel to stop the worker. + done chan<- struct{} +} + +// NewRouter returns a new Router instance that sends and receives messages +// from a provided message pipe handle. +func NewRouter(handle system.MessagePipeHandle, waiter AsyncWaiter) *Router { + requestChan := make(chan routeRequest, 10) + doneChan := make(chan struct{}) + router := &Router{ + handle: handle, + requestChan: requestChan, + done: doneChan, + } + router.runWorker(&routerWorker{ + handle, + make(map[uint64]chan<- MessageReadResult), + requestChan, + doneChan, + waiter, + make(chan WaitResponse, 1), + 0, + }) + return router +} + +// Close closes the router and the underlying message pipe. All new incoming +// requests are returned with an error. Panics if you try to close the router +// more than once. +func (r *Router) Close() { + close(r.done) +} + +// Accept sends a message to the message pipe. The message should have a +// zero request id in header. +func (r *Router) Accept(message *Message) error { + if message.Header.RequestId != 0 { + return fmt.Errorf("message header should have a zero request ID") + } + r.mu.Lock() + defer r.mu.Unlock() + // This can also mean that the router is closed. + if !r.handle.IsValid() { + return fmt.Errorf("can't write a message to an invalid handle") + } + r.requestChan <- routeRequest{message, nil} + return nil +} + +func (r *Router) runWorker(worker *routerWorker) { + // Run worker on a separate go routine. + go func() { + // Get the reason why the worker stopped. The error means that + // either the router is closed or there was an error reading + // or writing to a message pipe. In both cases it will be + // the reason why we can't process any more requests. + err := worker.runLoop() + worker.cancelIfWaiting() + // Respond to all pending requests. + for _, responseChan := range worker.responders { + responseChan <- MessageReadResult{nil, err} + } + // Respond to incoming requests until we make sure that all + // new requests return with an error before sending request + // to responseChan. + go func() { + for responder := range worker.requestChan { + responder.responseChan <- MessageReadResult{nil, err} + } + }() + r.mu.Lock() + r.handle.Close() + // If we acquire the lock then no other go routine is waiting + // to write to responseChan. All go routines that acquire the + // lock after us will return before sending to responseChan as + // the underlying handle is invalid (already closed). + // We can safely close the requestChan. + close(r.requestChan) + r.mu.Unlock() + }() +} + +// AcceptWithResponse sends a message to the message pipe and returns a channel +// that will stream the result of reading corresponding response. The message +// should have a non-zero request id in header. It is responsibility of the +// caller to issue unique request ids for all given messages. +func (r *Router) AcceptWithResponse(message *Message) <-chan MessageReadResult { + responseChan := make(chan MessageReadResult, 1) + if message.Header.RequestId == 0 { + responseChan <- MessageReadResult{nil, fmt.Errorf("message header should have a request ID")} + return responseChan + } + r.mu.Lock() + defer r.mu.Unlock() + // Return an error before sending a request to requestChan if the router + // is closed so that we can safely close responseChan once we close the + // router. + if !r.handle.IsValid() { + responseChan <- MessageReadResult{nil, fmt.Errorf("can't write a message to an invalid handle")} + return responseChan + } + r.requestChan <- routeRequest{message, responseChan} + return responseChan +}
diff --git a/third_party/mojo/src/mojo/public/go/bindings/stub.go b/third_party/mojo/src/mojo/public/go/bindings/stub.go new file mode 100644 index 0000000..b2b3120 --- /dev/null +++ b/third_party/mojo/src/mojo/public/go/bindings/stub.go
@@ -0,0 +1,47 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package bindings + +// MessageReceiver can receive |Message| objects. +type MessageReceiver interface { + // Accept receives a |Message|. Returns a error if the message was not + // handled. + Accept(message *Message) error +} + +// Stub is a base implementation of Stub. Stubs receives messages from message +// pipe, deserialize the payload and call the appropriate method in the +// implementation. If the method returns result, the stub serializes the +// response and sends it back. +type Stub struct { + connector *Connector + receiver MessageReceiver +} + +// NewStub returns a new Stub instance using provided |Connector| to send and +// receive messages. Incoming messages are handled by the provided |receiver|. +func NewStub(connector *Connector, receiver MessageReceiver) *Stub { + return &Stub{connector, receiver} +} + +// ServeRequest synchronously serves one request from the message pipe: the +// |Stub| waits on its underlying message pipe for a message and handles it. +// Can be called from multiple goroutines. Each calling goroutine will receive +// a different message or an error. +func (s *Stub) ServeRequest() error { + message, err := s.connector.ReadMessage() + if err != nil { + return err + } + return s.receiver.Accept(message) +} + +// Close immediately closes the |Stub| and its underlying message pipe. If the +// |Stub| is waiting on its message pipe handle the wait process is interrupted. +// All goroutines trying to serve will start returning errors as the underlying +// message pipe becomes invalid. +func (s *Stub) Close() { + s.connector.Close() +}
diff --git a/third_party/mojo/src/mojo/public/go/bindings/util.go b/third_party/mojo/src/mojo/public/go/bindings/util.go index 8d51ddb7..7886fe3 100644 --- a/third_party/mojo/src/mojo/public/go/bindings/util.go +++ b/third_party/mojo/src/mojo/public/go/bindings/util.go
@@ -4,6 +4,13 @@ package bindings +import ( + "fmt" + "sync/atomic" + + "mojo/public/go/system" +) + func align(size, alignment int) int { return ((size - 1) | (alignment - 1)) + 1 } @@ -14,7 +21,27 @@ return int((bits + 7) / 8) } +// WriteMessage writes a message to a message pipe. +func WriteMessage(handle system.MessagePipeHandle, message *Message) error { + result := handle.WriteMessage(message.Bytes, message.Handles, system.MOJO_WRITE_MESSAGE_FLAG_NONE) + if result != system.MOJO_RESULT_OK { + return fmt.Errorf("error writing message: %v", result) + } + return nil +} + // StringPointer converts provided string to *string. func StringPointer(s string) *string { return &s } + +// Counter is a simple thread-safe lock-free counter that can issue unique +// numbers starting from 1 to callers. +type Counter struct { + last uint64 +} + +// Next returns next unused value, each value is returned only once. +func (c *Counter) Next() uint64 { + return atomic.AddUint64(&c.last, 1) +}
diff --git a/third_party/mojo/src/mojo/public/go/system/mojo_types.go b/third_party/mojo/src/mojo/public/go/system/mojo_types.go index afb9df3..20dbf92 100644 --- a/third_party/mojo/src/mojo/public/go/system/mojo_types.go +++ b/third_party/mojo/src/mojo/public/go/system/mojo_types.go
@@ -72,7 +72,6 @@ MOJO_WRITE_DATA_FLAG_ALL_OR_NONE MojoWriteDataFlags = 1 << 0 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE MojoCreateDataPipeOptionsFlags = 0 - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD MojoCreateDataPipeOptionsFlags = 1 << 0 MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE MojoCreateMessagePipeOptionsFlags = 0 MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE MojoCreateSharedBufferOptionsFlags = 0
diff --git a/third_party/mojo/src/mojo/public/interfaces/application/application.mojom b/third_party/mojo/src/mojo/public/interfaces/application/application.mojom index cffcb1f..eaa742d 100644 --- a/third_party/mojo/src/mojo/public/interfaces/application/application.mojom +++ b/third_party/mojo/src/mojo/public/interfaces/application/application.mojom
@@ -10,11 +10,20 @@ // This is the primary interface implemented by every Mojo application. It // allows the application to receive its startup arguments from the shell, and // to be notified of events that occur during its execution. +// +// TODO(aa): It would be good to reorder the parameters once we have interface +// versioning. interface Application { // Initializes the application with the specified arguments. This method is // guaranteed to be called before any other method is called, and will only be // called once. - Initialize(Shell shell, array<string>? args); + // + // The |url| parameter is the identity of the application as far as the shell + // is concerned. This will be the URL the application was found at, after all + // mappings, resolution, and redirects. And it will not include the + // querystring, since the querystring is not part of an application's + // identity. + Initialize(Shell shell, array<string>? args, string url); // Called when another application (identified by |requestor_url|) attempts to // open a connection to this application. @@ -36,9 +45,14 @@ // // This application is free to ignore the |services| or |exposed_services| // parameters if it does not wish to offer or request services. + // + // resolved_url is the URL that was requested to create this connection, after + // all mappings, resolutions, and redirects. This will include any querystring + // that was part of the request. AcceptConnection(string requestor_url, ServiceProvider&? services, - ServiceProvider? exposed_services); + ServiceProvider? exposed_services, + string resolved_url); // Called to request the application shut itself down gracefully. RequestQuit();
diff --git a/third_party/mojo/src/mojo/public/interfaces/application/shell.mojom b/third_party/mojo/src/mojo/public/interfaces/application/shell.mojom index 6fc0cca..523e263 100644 --- a/third_party/mojo/src/mojo/public/interfaces/application/shell.mojom +++ b/third_party/mojo/src/mojo/public/interfaces/application/shell.mojom
@@ -9,7 +9,7 @@ // An interface through which a Mojo application may communicate with the Mojo // system and request connections to other applications. interface Shell { - // Establishes a connection with another application (identified by + // Establishes a connection with another application (located at // |application_url|) through which the calling application and the other // application may request services from one another. //
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/BUILD.gn b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/BUILD.gn index f68b113..dabc3f6 100644 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/BUILD.gn +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/BUILD.gn
@@ -11,7 +11,6 @@ "no_module.mojom", "rect.mojom", "regression_tests.mojom", - "regression_tests_import.mojom", "sample_factory.mojom", "sample_import.mojom", "sample_import2.mojom",
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version0.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version0.data new file mode 100644 index 0000000..083f0e9 --- /dev/null +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version0.data
@@ -0,0 +1,17 @@ +[dist4]message_header // num_bytes +[u4]2 // version +[u4]11 // name +[u4]0 // flags +[anchr]message_header + +[dist4]method11_params // num_bytes +[u4]1 // version +[dist8]param0_ptr // param0 +[anchr]method11_params + +[anchr]param0_ptr +[dist4]struct_g // num_bytes +[u4]0 // version +[s4]123 // i +[u4]0 // padding +[anchr]struct_g
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version0.expected similarity index 100% copy from third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected copy to third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version0.expected
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version1.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version1.data new file mode 100644 index 0000000..39e3643 --- /dev/null +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version1.data
@@ -0,0 +1,18 @@ +[dist4]message_header // num_bytes +[u4]2 // version +[u4]11 // name +[u4]0 // flags +[anchr]message_header + +[dist4]method11_params // num_bytes +[u4]1 // version +[dist8]param0_ptr // param0 +[anchr]method11_params + +[anchr]param0_ptr +[dist4]struct_g // num_bytes +[u4]1 // version +[s4]123 // i +[u4]0 // padding +[u8]0 // struct_a +[anchr]struct_g
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version1.expected similarity index 100% copy from third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected copy to third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version1.expected
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version2.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version2.data new file mode 100644 index 0000000..2fcd552 --- /dev/null +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version2.data
@@ -0,0 +1,18 @@ +[dist4]message_header // num_bytes +[u4]2 // version +[u4]11 // name +[u4]0 // flags +[anchr]message_header + +[dist4]method11_params // num_bytes +[u4]1 // version +[dist8]param0_ptr // param0 +[anchr]method11_params + +[anchr]param0_ptr +[dist4]struct_g // num_bytes +[u4]2 // version +[s4]123 // i +[u4]0 // padding +[u8]0 // struct_a +[anchr]struct_g
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version2.expected similarity index 100% copy from third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected copy to third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version2.expected
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version3.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version3.data new file mode 100644 index 0000000..940ac88 --- /dev/null +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version3.data
@@ -0,0 +1,26 @@ +[dist4]message_header // num_bytes +[u4]2 // version +[u4]11 // name +[u4]0 // flags +[anchr]message_header + +[dist4]method11_params // num_bytes +[u4]1 // version +[dist8]param0_ptr // param0 +[anchr]method11_params + +[anchr]param0_ptr +[dist4]struct_g // num_bytes +[u4]3 // version +[s4]123 // i +[b]00000001 // b +0 0 0 // padding +[u8]0 // struct_a +[dist8]str_ptr // str +[anchr]struct_g + +[anchr]str_ptr +[dist4]string // num_bytes +[u4]2 // num_elements +0 1 +[anchr]string
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version3.expected similarity index 100% copy from third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected copy to third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version3.expected
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version_newer_than_known_1.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version_newer_than_known_1.data new file mode 100644 index 0000000..24b060c --- /dev/null +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version_newer_than_known_1.data
@@ -0,0 +1,28 @@ +[dist4]message_header // num_bytes +[u4]2 // version +[u4]11 // name +[u4]0 // flags +[anchr]message_header + +[dist4]method11_params // num_bytes +[u4]1 // version +[dist8]param0_ptr // param0 +[anchr]method11_params + +[anchr]param0_ptr +[dist4]struct_g // num_bytes +[u4]5 // version: Newer than what the validator knows. + // It is okay that the size is the same as the latest + // version that the validator knows. +[s4]123 // i +[b]00000001 // b +0 0 0 // padding +[u8]0 // struct_a +[dist8]str_ptr // str +[anchr]struct_g + +[anchr]str_ptr +[dist4]string // num_bytes +[u4]2 // num_elements +0 1 +[anchr]string
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version_newer_than_known_1.expected similarity index 100% copy from third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected copy to third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version_newer_than_known_1.expected
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version_newer_than_known_2.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version_newer_than_known_2.data new file mode 100644 index 0000000..887f276 --- /dev/null +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version_newer_than_known_2.data
@@ -0,0 +1,28 @@ +[dist4]message_header // num_bytes +[u4]2 // version +[u4]11 // name +[u4]0 // flags +[anchr]message_header + +[dist4]method11_params // num_bytes +[u4]1 // version +[dist8]param0_ptr // param0 +[anchr]method11_params + +[anchr]param0_ptr +[dist4]struct_g // num_bytes +[u4]5 // version: Newer than what the validator knows. +[s4]123 // i +[b]00000001 // b +0 0 0 // padding +[u8]0 // struct_a +[dist8]str_ptr // str +[u8]0 // unknown contents +[u8]0 // unknown contents +[anchr]struct_g + +[anchr]str_ptr +[dist4]string // num_bytes +[u4]2 // num_elements +0 1 +[anchr]string
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version_newer_than_known_2.expected similarity index 100% copy from third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected copy to third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_good_version_newer_than_known_2.expected
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_num_bytes_version_mismatch_1.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_num_bytes_version_mismatch_1.data new file mode 100644 index 0000000..26bab886 --- /dev/null +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_num_bytes_version_mismatch_1.data
@@ -0,0 +1,19 @@ +[dist4]message_header // num_bytes +[u4]2 // version +[u4]11 // name +[u4]0 // flags +[anchr]message_header + +[dist4]method11_params // num_bytes +[u4]1 // version +[dist8]param0_ptr // param0 +[anchr]method11_params + +[anchr]param0_ptr +[dist4]struct_g // num_bytes: The size is too big for the version. +[u4]1 // version +[s4]123 // i +[u4]0 // padding +[u8]0 // struct_a +[u8]0 // Unexpected contents that cause the mismatch. +[anchr]struct_g
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_num_bytes_version_mismatch_1.expected similarity index 100% copy from third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.expected copy to third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_num_bytes_version_mismatch_1.expected
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_num_bytes_version_mismatch_2.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_num_bytes_version_mismatch_2.data new file mode 100644 index 0000000..f9457f7 --- /dev/null +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_num_bytes_version_mismatch_2.data
@@ -0,0 +1,17 @@ +[dist4]message_header // num_bytes +[u4]2 // version +[u4]11 // name +[u4]0 // flags +[anchr]message_header + +[dist4]method11_params // num_bytes +[u4]1 // version +[dist8]param0_ptr // param0 +[anchr]method11_params + +[anchr]param0_ptr +[dist4]struct_g // num_bytes: The size is too small for the version. +[u4]2 // version +[s4]123 // i +[u4]0 // padding +[anchr]struct_g
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_num_bytes_version_mismatch_2.expected similarity index 100% copy from third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.expected copy to third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd11_num_bytes_version_mismatch_2.expected
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_good.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_good.data index 9a983a7..c0be013 100644 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_good.data +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_good.data
@@ -8,7 +8,6 @@ [u4]2 // num_fields [dist8]param0_ptr // param0 [dist8]param1_ptr // param1 -[u8]0 // unknown [anchr]method7_params [anchr]param0_ptr
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.data deleted file mode 100644 index df7b7e8e6..0000000 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.data +++ /dev/null
@@ -1,17 +0,0 @@ -[dist4]message_header // num_bytes -[u4]2 // num_fields -[u4]0 // name -[u4]0 // flags -[anchr]message_header - -[dist4]method0_params // num_bytes -[u4]1 // num_fields -[dist8]param0_ptr // param0 -[anchr]method0_params - -[anchr]param0_ptr -[dist4]basic_struct // num_bytes -[u4]1 // num_fields -[s4]-1 // a -[u4]0 // padding -[anchr]basic_struct
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.data deleted file mode 100644 index 3dcca9d5..0000000 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.data +++ /dev/null
@@ -1,14 +0,0 @@ -[dist4]message_header // num_bytes -[u4]2 // num_fields -[u4]0 // name -[u4]0 // flags -[anchr]message_header - -[dist4]method0_params // num_bytes -[u4]1 // num_fields -[dist8]param0_ptr // param0 -[anchr]method0_params - -[anchr]param0_ptr -[u4]0 // num_bytes: The struct size is too small. -[u4]0 // num_fields
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_good.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_good.data deleted file mode 100644 index f4b6c40..0000000 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_good.data +++ /dev/null
@@ -1,17 +0,0 @@ -[dist4]message_header // num_bytes -[u4]3 // num_fields -[u4]0 // name -[u4]2 // flags: Is response. -[u8]1 // request_id -[anchr]message_header - -[dist4]method0_params // num_bytes -[u4]1 // num_fields -[dist8]param0_ptr // param0 -[anchr]method0_params - -[anchr]param0_ptr -[dist4]uint8_array // num_bytes -[u4]1 // num_elements -[u1]0 -[anchr]uint8_array
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_good.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_good.expected deleted file mode 100644 index 7ef22e9..0000000 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_good.expected +++ /dev/null
@@ -1 +0,0 @@ -PASS
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_unexpected_array_header.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_unexpected_array_header.data deleted file mode 100644 index a3570135..0000000 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_unexpected_array_header.data +++ /dev/null
@@ -1,17 +0,0 @@ -[dist4]message_header // num_bytes -[u4]3 // num_fields -[u4]0 // name -[u4]2 // flags: Is response. -[u8]1 // request_id -[anchr]message_header - -[dist4]method0_params // num_bytes -[u4]1 // num_fields -[dist8]param0_ptr // param0 -[anchr]method0_params - -[anchr]param0_ptr -[dist4]uint8_array // num_bytes -[u4]2 // num_elements: The size is too small to hold 2 elements. -[u1]0 -[anchr]uint8_array
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_resp_mthd0_good.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_resp_mthd0_good.data new file mode 100644 index 0000000..0ee26af --- /dev/null +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_resp_mthd0_good.data
@@ -0,0 +1,17 @@ +[dist4]message_header // num_bytes +[u4]3 // num_fields +[u4]0 // name +[u4]2 // flags kMessageIsResponse +[u8]1 // request_id +[anchr]message_header + +[dist4]method0_params // num_bytes +[u4]1 // num_fields +[dist8]param0_ptr // param0 +[anchr]method0_params + +[anchr]param0_ptr +[dist4]uint8_array // num_bytes +[u4]1 // num_elements +[u1]0 +[anchr]uint8_array
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_resp_mthd0_good.expected similarity index 100% rename from third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected rename to third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_resp_mthd0_good.expected
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_resp_mthd0_unexpected_array_header.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_resp_mthd0_unexpected_array_header.data new file mode 100644 index 0000000..25540b1 --- /dev/null +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_resp_mthd0_unexpected_array_header.data
@@ -0,0 +1,17 @@ +[dist4]message_header // num_bytes +[u4]3 // num_fields +[u4]0 // name +[u4]2 // flags kMessageIsResponse +[u8]1 // request_id +[anchr]message_header + +[dist4]method0_params // num_bytes +[u4]1 // num_fields +[dist8]param0_ptr // param0 +[anchr]method0_params + +[anchr]param0_ptr +[dist4]uint8_array // num_bytes +[u4]2 // num_elements: The size is too small to hold 2 elements. +[u1]0 +[anchr]uint8_array
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_unexpected_array_header.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_resp_mthd0_unexpected_array_header.expected similarity index 100% rename from third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_unexpected_array_header.expected rename to third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_resp_mthd0_unexpected_array_header.expected
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_rqst_mthd0_good.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_rqst_mthd0_good.data new file mode 100644 index 0000000..c57d4bd --- /dev/null +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_rqst_mthd0_good.data
@@ -0,0 +1,18 @@ +[dist4]message_header // num_bytes +[u4]3 // num_fields +[u4]0 // name +[u4]1 // flags kMessageExpectsResponse +[u8]7 // request_id +[anchr]message_header + +[dist4]method0_params // num_bytes +[u4]1 // num_fields +[dist8]param0_ptr // param0 +[anchr]method0_params + +[anchr]param0_ptr +[dist4]basic_struct // num_bytes +[u4]1 // num_fields +[s4]-1 // a +[u4]0 // padding +[anchr]basic_struct
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_rqst_mthd0_good.expected similarity index 100% copy from third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected copy to third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_rqst_mthd0_good.expected
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_rqst_mthd0_unexpected_struct_header.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_rqst_mthd0_unexpected_struct_header.data new file mode 100644 index 0000000..8b6bd2d --- /dev/null +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_rqst_mthd0_unexpected_struct_header.data
@@ -0,0 +1,15 @@ +[dist4]message_header // num_bytes +[u4]3 // num_fields +[u4]0 // name +[u4]1 // flags kMessageExpectsResponse +[u8]7 // request_id +[anchr]message_header + +[dist4]method0_params // num_bytes +[u4]1 // num_fields +[dist8]param0_ptr // param0 +[anchr]method0_params + +[anchr]param0_ptr +[u4]0 // num_bytes: The struct size is too small. +[u4]0 // num_fields
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_rqst_mthd0_unexpected_struct_header.expected similarity index 100% rename from third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.expected rename to third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/integration_intf_rqst_mthd0_unexpected_struct_header.expected
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/not_implemented_mthd0_struct_num_fields_less_than_min_requirement.data b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/not_implemented_mthd0_struct_num_fields_less_than_min_requirement.data deleted file mode 100644 index ffcafd3b..0000000 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/not_implemented_mthd0_struct_num_fields_less_than_min_requirement.data +++ /dev/null
@@ -1,12 +0,0 @@ -[dist4]message_header // num_bytes -[u4]2 // num_fields -[u4]0 // name -[u4]0 // flags -[anchr]message_header - -[dist4]method0_params // num_bytes -[u4]0 // num_fields: Less than the minimal number of fields - // that we expect. -[f]-1 // param0 -[u4]0 // padding -[anchr]method0_params
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/not_implemented_mthd0_struct_num_fields_less_than_min_requirement.expected b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/not_implemented_mthd0_struct_num_fields_less_than_min_requirement.expected deleted file mode 100644 index 25aceee..0000000 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/data/validation/not_implemented_mthd0_struct_num_fields_less_than_min_requirement.expected +++ /dev/null
@@ -1 +0,0 @@ -VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/regression_tests.mojom b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/regression_tests.mojom index 4a85b0a..313f1f4d 100644 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/regression_tests.mojom +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/regression_tests.mojom
@@ -7,8 +7,6 @@ [JavaPackage="org.chromium.mojo.bindings.test.mojom.regression_tests"] module regression_tests; -import "regression_tests_import.mojom"; - interface CheckMethodWithEmptyResponse { WithouParameterAndEmptyResponse() => (); WithParameterAndEmptyResponse(bool b) => (); @@ -54,7 +52,3 @@ struct B { A? a; }; - -[Client=InterfaceWithClientImportedClient] -interface InterfaceWithClientImported { -};
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/regression_tests_import.mojom b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/regression_tests_import.mojom deleted file mode 100644 index fbed983..0000000 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/regression_tests_import.mojom +++ /dev/null
@@ -1,11 +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. - -// 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/third_party/mojo/src/mojo/public/interfaces/bindings/tests/sample_factory.mojom b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/sample_factory.mojom index eb5d9307..ade3bf3 100644 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/sample_factory.mojom +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/sample_factory.mojom
@@ -29,18 +29,13 @@ GetName() => (string name); }; -[Client=FactoryClient] interface Factory { - DoStuff(Request request, handle<message_pipe>? pipe); - DoStuff2(handle<data_pipe_consumer> pipe); + DoStuff(Request request, handle<message_pipe>? pipe) => + (Response response, string text); + DoStuff2(handle<data_pipe_consumer> pipe) => (string text); CreateNamedObject(NamedObject& obj); RequestImportedInterface( imported.ImportedInterface& obj) => (imported.ImportedInterface& obj); TakeImportedInterface( imported.ImportedInterface obj) => (imported.ImportedInterface obj); }; - -interface FactoryClient { - DidStuff(Response response, string text); - DidStuff2(string text); -};
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom index 37405ca7..52589a9 100644 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom
@@ -13,14 +13,9 @@ VALUE }; -[Client=ProviderClient] interface Provider { EchoString(string a) => (string a); EchoStrings(string a, string b) => (string a, string b); EchoMessagePipeHandle(handle<message_pipe> a) => (handle<message_pipe> a); EchoEnum(Enum a) => (Enum a); }; - -// TODO(darin): We shouldn't need this, but JS bindings don't work without it. -interface ProviderClient { -};
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/sample_service.mojom b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/sample_service.mojom index 5c80781c..700481c 100644 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/sample_service.mojom +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/sample_service.mojom
@@ -104,21 +104,16 @@ int32 v3 = 3; }; -[Client=ServiceClient] interface Service { enum BazOptions { REGULAR = 0, EXTRA }; const uint8 kFavoriteBaz = 1; - Frobinate@0(Foo? foo@0, BazOptions baz@1, Port? port@2); + Frobinate@0(Foo? foo@0, BazOptions baz@1, Port? port@2) => (int32 result@0); GetPort@1(Port& port @0); }; -interface ServiceClient { - DidFrobinate@0(int32 result@0); -}; - // This interface is referenced above where it is defined. It also refers to // itself from a method. interface Port {
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_structs.mojom b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_structs.mojom index dc4f05e..97ce3a3 100644 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_structs.mojom +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_structs.mojom
@@ -283,3 +283,69 @@ array<array<bool>?> f5; array<array<bool, 2>?> f6; }; + +// Used to verify that different versions can be decoded correctly. + +struct MultiVersionStruct { + [MinVersion=0] + int32 f_int32; + [MinVersion=1] + Rect? f_rect; + [MinVersion=3] + string? f_string; + [MinVersion=5] + array<int8> f_array; + [MinVersion=7] + handle<message_pipe>? f_message_pipe; + [MinVersion=7] + bool f_bool; + [MinVersion=9] + int16 f_int16; +}; + +struct MultiVersionStructV0 { + [MinVersion=0] + int32 f_int32; +}; + +struct MultiVersionStructV1 { + [MinVersion=0] + int32 f_int32; + [MinVersion=1] + Rect? f_rect; +}; + +struct MultiVersionStructV3 { + [MinVersion=0] + int32 f_int32; + [MinVersion=1] + Rect? f_rect; + [MinVersion=3] + string? f_string; +}; + +struct MultiVersionStructV5 { + [MinVersion=0] + int32 f_int32; + [MinVersion=1] + Rect? f_rect; + [MinVersion=3] + string? f_string; + [MinVersion=5] + array<int8> f_array; +}; + +struct MultiVersionStructV7 { + [MinVersion=0] + int32 f_int32; + [MinVersion=1] + Rect? f_rect; + [MinVersion=3] + string? f_string; + [MinVersion=5] + array<int8> f_array; + [MinVersion=7] + handle<message_pipe>? f_message_pipe; + [MinVersion=7] + bool f_bool; +};
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom index 290b792..13d0b52 100644 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom
@@ -31,6 +31,16 @@ array<uint8, 3> fixed_size_array; }; +struct StructG { + int32 i; + [MinVersion=1] + StructA? struct_a; + [MinVersion=3] + string? str; + [MinVersion=3] + bool b; +}; + interface ConformanceTestInterface { Method0(float param0); Method1(StructA param0); @@ -43,18 +53,13 @@ Method8(array<array<string>?> param0); Method9(array<array<handle?>>? param0); Method10(map<string, uint8> param0); + Method11(StructG param0); }; struct BasicStruct { int32 a; }; -[Client=IntegrationTestInterface2] -interface IntegrationTestInterface1 { - Method0(BasicStruct param0); -}; - -[Client=IntegrationTestInterface1] -interface IntegrationTestInterface2 { - Method0() => (array<uint8> param0); +interface IntegrationTestInterface { + Method0(BasicStruct param0) => (array<uint8> param0); };
diff --git a/third_party/mojo/src/mojo/public/java/BUILD.gn b/third_party/mojo/src/mojo/public/java/BUILD.gn index 04d2ef6..2bcf1ed 100644 --- a/third_party/mojo/src/mojo/public/java/BUILD.gn +++ b/third_party/mojo/src/mojo/public/java/BUILD.gn
@@ -18,6 +18,7 @@ "system/src/org/chromium/mojo/system/Pair.java", "system/src/org/chromium/mojo/system/SharedBufferHandle.java", "system/src/org/chromium/mojo/system/UntypedHandle.java", + "system/src/org/chromium/mojo/system/RunLoop.java", ] } @@ -36,7 +37,6 @@ "bindings/src/org/chromium/mojo/bindings/HandleOwner.java", "bindings/src/org/chromium/mojo/bindings/Interface.java", "bindings/src/org/chromium/mojo/bindings/InterfaceRequest.java", - "bindings/src/org/chromium/mojo/bindings/InterfaceWithClient.java", "bindings/src/org/chromium/mojo/bindings/MessageHeader.java", "bindings/src/org/chromium/mojo/bindings/Message.java", "bindings/src/org/chromium/mojo/bindings/MessageReceiver.java", @@ -53,3 +53,18 @@ ":system", ] } + +android_library("application") { + java_files = [ + "application/src/org/chromium/mojo/application/ApplicationConnection.java", + "application/src/org/chromium/mojo/application/ApplicationDelegate.java", + "application/src/org/chromium/mojo/application/ApplicationImpl.java", + "application/src/org/chromium/mojo/application/ApplicationRunner.java", + "application/src/org/chromium/mojo/application/ServiceFactoryBinder.java", + ] + deps = [ + ":bindings", + ":system", + "../interfaces/application:application_java", + ] +}
diff --git a/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ApplicationConnection.java b/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ApplicationConnection.java new file mode 100644 index 0000000..b6676c6 --- /dev/null +++ b/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ApplicationConnection.java
@@ -0,0 +1,108 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.mojo.application; + +import org.chromium.mojo.bindings.Interface; +import org.chromium.mojo.system.MessagePipeHandle; +import org.chromium.mojo.system.MojoException; +import org.chromium.mojom.mojo.ServiceProvider; + +import java.io.Closeable; +import java.util.HashMap; +import java.util.Map; + +/** + * Represents a connection to another application. + */ +public class ApplicationConnection implements Closeable { + private final String mConnectionUrl; + private final ServiceProvider mExposedServices; + private final String mRequestorUrl; + private final ServiceProviderImpl mServiceProviderImpl; + + /** + * @param requestorUrl URL of the application requesting this connection. + * @param exposedServices ServiceProvider for services exposed by the remote application. + */ + public ApplicationConnection( + String requestorUrl, ServiceProvider exposedServices, String connectionUrl) { + mRequestorUrl = requestorUrl; + mExposedServices = exposedServices; + mConnectionUrl = connectionUrl; + mServiceProviderImpl = new ServiceProviderImpl(); + } + + /** + * @return URL of the application requesting this connection. + */ + public String getRequestorUrl() { + return mRequestorUrl; + } + + /** + * @return URL that was used by the source application to establish this connection. + */ + public String connectionUrl() { + return mConnectionUrl; + } + + /** + * @return ServiceProvider for services exposed by the remote application. + */ + public ServiceProvider getRemoteServiceProvider() { + return mExposedServices; + } + + /** + * Add a new service for this application. + * + * @param binder Handle to a ServiceFactoryBinder which contains a service implementation. + */ + public void addService(ServiceFactoryBinder<? extends Interface> binder) { + mServiceProviderImpl.addService(binder); + } + + /** + * @return ServiceProvider for this application. + */ + public ServiceProvider getLocalServiceProvider() { + return mServiceProviderImpl; + } + + @Override + public void close() { + mServiceProviderImpl.close(); + if (mExposedServices != null) { + mExposedServices.close(); + } + } +} + +class ServiceProviderImpl implements ServiceProvider { + private final Map<String, ServiceFactoryBinder<? extends Interface>> mNameToServiceMap = + new HashMap<String, ServiceFactoryBinder<? extends Interface>>(); + + ServiceProviderImpl() {} + + public void addService(ServiceFactoryBinder<? extends Interface> binder) { + mNameToServiceMap.put(binder.getInterfaceName(), binder); + } + + @Override + public void connectToService(String interfaceName, MessagePipeHandle pipe) { + if (mNameToServiceMap.containsKey(interfaceName)) { + mNameToServiceMap.get(interfaceName).bindNewInstanceToMessagePipe(pipe); + } else { + pipe.close(); + } + } + + @Override + public void close() {} + + @Override + public void onConnectionError(MojoException e) {} +} +;
diff --git a/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ApplicationDelegate.java b/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ApplicationDelegate.java new file mode 100644 index 0000000..61f39da --- /dev/null +++ b/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ApplicationDelegate.java
@@ -0,0 +1,39 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.mojo.application; + +import org.chromium.mojom.mojo.Shell; + +/** + * Applications should implement this interface to control various behaviors of Mojo application + * interface. + */ +public interface ApplicationDelegate { + /** + * Called exactly once before any other method. + * + * @param shell A handle to the shell interface. + * @param args Arguments used for this application. + * @param url URL of this application. + */ + public void initialize(Shell shell, String[] args, String url); + + /** + * This method is used to configure what services a connection supports when being connected to. + * Return false to reject the connection entirely. + * + * @param requestorUrl URL of the application requesting service. + * @param connection A handle to the connection. + * @return If this application accepts any incoming connection. + */ + public boolean configureIncomingConnection( + String requestorUrl, ApplicationConnection connection); + + /** + * Called before exiting. After returning from this call, the delegate cannot expect RunLoop to + * still be running. + */ + public void quit(); +}
diff --git a/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ApplicationImpl.java b/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ApplicationImpl.java new file mode 100644 index 0000000..2676f38d --- /dev/null +++ b/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ApplicationImpl.java
@@ -0,0 +1,72 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.mojo.application; + +import org.chromium.mojo.bindings.InterfaceRequest; +import org.chromium.mojo.system.Core; +import org.chromium.mojo.system.MessagePipeHandle; +import org.chromium.mojo.system.MojoException; +import org.chromium.mojom.mojo.Application; +import org.chromium.mojom.mojo.ServiceProvider; +import org.chromium.mojom.mojo.Shell; + +import java.util.ArrayList; + +/** + * Utility class for communicating with the Shell, and provide Services to clients. + */ +class ApplicationImpl implements Application { + private final ApplicationDelegate mApplicationDelegate; + private final ArrayList<ApplicationConnection> mIncomingConnections = + new ArrayList<ApplicationConnection>(); + private final Core mCore; + private Shell mShell; + + public ApplicationImpl( + ApplicationDelegate delegate, Core core, MessagePipeHandle applicationRequest) { + mApplicationDelegate = delegate; + mCore = core; + ApplicationImpl.MANAGER.bind(this, applicationRequest); + } + + @Override + public void initialize(Shell shell, String[] args, String url) { + mShell = shell; + mApplicationDelegate.initialize(shell, args, url); + } + + @Override + public void acceptConnection(String requestorUrl, InterfaceRequest<ServiceProvider> services, + ServiceProvider exposedServices, String connectionUrl) { + ApplicationConnection connection = + new ApplicationConnection(requestorUrl, exposedServices, connectionUrl); + if (services != null + && mApplicationDelegate.configureIncomingConnection(requestorUrl, connection)) { + ServiceProvider.MANAGER.bind(connection.getLocalServiceProvider(), services); + mIncomingConnections.add(connection); + } else { + connection.close(); + } + } + + @Override + public void requestQuit() { + mApplicationDelegate.quit(); + for (ApplicationConnection connection : mIncomingConnections) { + connection.close(); + } + mCore.getCurrentRunLoop().quit(); + } + + @Override + public void close() { + if (mShell != null) { + mShell.close(); + } + } + + @Override + public void onConnectionError(MojoException e) {} +}
diff --git a/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ApplicationRunner.java b/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ApplicationRunner.java new file mode 100644 index 0000000..1a903b4 --- /dev/null +++ b/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ApplicationRunner.java
@@ -0,0 +1,32 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.mojo.application; + +import org.chromium.mojo.system.Core; +import org.chromium.mojo.system.MessagePipeHandle; +import org.chromium.mojo.system.RunLoop; + +/** + * A utility for running an Application. + * + */ +public class ApplicationRunner { + /** + * Runs the delegate in a RunLoop. + * + * @param delegate Application specific functionality. + * @param core Core mojo interface. + * @param applicationRequest Handle for the application request. + */ + public static void run( + ApplicationDelegate delegate, Core core, MessagePipeHandle applicationRequest) { + try (RunLoop runLoop = core.createDefaultRunLoop()) { + try (ApplicationImpl application = + new ApplicationImpl(delegate, core, applicationRequest)) { + runLoop.run(); + } + } + } +}
diff --git a/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ServiceFactoryBinder.java b/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ServiceFactoryBinder.java new file mode 100644 index 0000000..462d74e --- /dev/null +++ b/third_party/mojo/src/mojo/public/java/application/src/org/chromium/mojo/application/ServiceFactoryBinder.java
@@ -0,0 +1,30 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.mojo.application; + +import org.chromium.mojo.bindings.Interface; +import org.chromium.mojo.system.MessagePipeHandle; + +/** + * ServiceFactoryBinder holds the necessary information to bind a service interface to a message + * pipe. + * + * @param <T> A mojo service interface. + */ +public interface ServiceFactoryBinder<T extends Interface> { + /** + * An application implements to bind a service implementation to |pipe|. + * + * @param pipe A handle to the incoming connection pipe. + */ + public void bindNewInstanceToMessagePipe(MessagePipeHandle pipe); + + /** + * Name of the service interface being implemented. + * + * @return Service interface name. + */ + public String getInterfaceName(); +}
diff --git a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java index b95b6dd..fa1eb236 100644 --- a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java +++ b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java
@@ -120,22 +120,47 @@ // Claim the memory for the header. mValidator.claimMemory(mBaseOffset, mBaseOffset + DataHeader.HEADER_SIZE); int size = readInt(DataHeader.SIZE_OFFSET); - int numFields = readInt(DataHeader.NUM_FIELDS_OFFSET); + int elementsOrVersion = readInt(DataHeader.ELEMENTS_OR_VERSION_OFFSET); if (size < 0) { throw new DeserializationException( "Negative size. Unsigned integers are not valid for java."); } - if (numFields < 0) { + if (elementsOrVersion < 0) { throw new DeserializationException( - "Negative number of fields. Unsigned integers are not valid for java."); + "Negative elements or version. Unsigned integers are not valid for java."); } // Claim the remaining memory. mValidator.claimMemory(mBaseOffset + DataHeader.HEADER_SIZE, mBaseOffset + size); - DataHeader res = new DataHeader(size, numFields); + DataHeader res = new DataHeader(size, elementsOrVersion); return res; } + public DataHeader readAndValidateDataHeader(DataHeader[] versionArray) { + DataHeader header = readDataHeader(); + int maxVersionIndex = versionArray.length - 1; + if (header.elementsOrVersion <= versionArray[maxVersionIndex].elementsOrVersion) { + DataHeader referenceHeader = null; + for (int index = maxVersionIndex; index >= 0; index--) { + DataHeader dataHeader = versionArray[index]; + if (header.elementsOrVersion >= dataHeader.elementsOrVersion) { + referenceHeader = dataHeader; + break; + } + } + if (referenceHeader == null || referenceHeader.size != header.size) { + throw new DeserializationException( + "Header doesn't correspond to any known version."); + } + } else { + if (header.size < versionArray[maxVersionIndex].size) { + throw new DeserializationException("Message newer than the last known version" + + " cannot be shorter than required by the last known version."); + } + } + return header; + } + /** * Deserializes a {@link DataHeader} at the given offset and checks if it is correct for an * array where element have the given size. @@ -153,9 +178,9 @@ throw new DeserializationException( "Incorrect header for map. The size is incorrect."); } - if (si.numFields != BindingsHelper.MAP_STRUCT_HEADER.numFields) { + if (si.elementsOrVersion != BindingsHelper.MAP_STRUCT_HEADER.elementsOrVersion) { throw new DeserializationException( - "Incorrect header for map. The number of fields is incorrect."); + "Incorrect header for map. The version is incorrect."); } } @@ -244,10 +269,10 @@ return null; } DataHeader si = d.readDataHeaderForBooleanArray(expectedLength); - byte[] bytes = new byte[(si.numFields + 7) / BindingsHelper.ALIGNMENT]; + byte[] bytes = new byte[(si.elementsOrVersion + 7) / BindingsHelper.ALIGNMENT]; d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); d.mMessage.getData().get(bytes); - boolean[] result = new boolean[si.numFields]; + boolean[] result = new boolean[si.elementsOrVersion]; for (int i = 0; i < bytes.length; ++i) { for (int j = 0; j < BindingsHelper.ALIGNMENT; ++j) { int booleanIndex = i * BindingsHelper.ALIGNMENT + j; @@ -268,7 +293,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(1, expectedLength); - byte[] result = new byte[si.numFields]; + byte[] result = new byte[si.elementsOrVersion]; d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); d.mMessage.getData().get(result); return result; @@ -283,7 +308,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(2, expectedLength); - short[] result = new short[si.numFields]; + short[] result = new short[si.elementsOrVersion]; d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); d.mMessage.getData().asShortBuffer().get(result); return result; @@ -298,7 +323,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(4, expectedLength); - int[] result = new int[si.numFields]; + int[] result = new int[si.elementsOrVersion]; d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); d.mMessage.getData().asIntBuffer().get(result); return result; @@ -313,7 +338,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(4, expectedLength); - float[] result = new float[si.numFields]; + float[] result = new float[si.elementsOrVersion]; d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); d.mMessage.getData().asFloatBuffer().get(result); return result; @@ -328,7 +353,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(8, expectedLength); - long[] result = new long[si.numFields]; + long[] result = new long[si.elementsOrVersion]; d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); d.mMessage.getData().asLongBuffer().get(result); return result; @@ -343,7 +368,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(8, expectedLength); - double[] result = new double[si.numFields]; + double[] result = new double[si.elementsOrVersion]; d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); d.mMessage.getData().asDoubleBuffer().get(result); return result; @@ -447,7 +472,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(4, expectedLength); - Handle[] result = new Handle[si.numFields]; + Handle[] result = new Handle[si.elementsOrVersion]; for (int i = 0; i < result.length; ++i) { result[i] = d.readHandle( DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i, @@ -466,7 +491,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(4, expectedLength); - UntypedHandle[] result = new UntypedHandle[si.numFields]; + UntypedHandle[] result = new UntypedHandle[si.elementsOrVersion]; for (int i = 0; i < result.length; ++i) { result[i] = d.readUntypedHandle( DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i, @@ -485,7 +510,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(4, expectedLength); - DataPipe.ConsumerHandle[] result = new DataPipe.ConsumerHandle[si.numFields]; + DataPipe.ConsumerHandle[] result = new DataPipe.ConsumerHandle[si.elementsOrVersion]; for (int i = 0; i < result.length; ++i) { result[i] = d.readConsumerHandle( DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i, @@ -504,7 +529,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(4, expectedLength); - DataPipe.ProducerHandle[] result = new DataPipe.ProducerHandle[si.numFields]; + DataPipe.ProducerHandle[] result = new DataPipe.ProducerHandle[si.elementsOrVersion]; for (int i = 0; i < result.length; ++i) { result[i] = d.readProducerHandle( DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i, @@ -524,7 +549,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(4, expectedLength); - MessagePipeHandle[] result = new MessagePipeHandle[si.numFields]; + MessagePipeHandle[] result = new MessagePipeHandle[si.elementsOrVersion]; for (int i = 0; i < result.length; ++i) { result[i] = d.readMessagePipeHandle( DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i, @@ -544,7 +569,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(4, expectedLength); - SharedBufferHandle[] result = new SharedBufferHandle[si.numFields]; + SharedBufferHandle[] result = new SharedBufferHandle[si.elementsOrVersion]; for (int i = 0; i < result.length; ++i) { result[i] = d.readSharedBufferHandle( DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i, @@ -564,7 +589,7 @@ return null; } DataHeader si = d.readDataHeaderForArray(4, expectedLength); - S[] result = manager.buildArray(si.numFields); + S[] result = manager.buildArray(si.elementsOrVersion); for (int i = 0; i < result.length; ++i) { // This cast is necessary because java 6 doesn't handle wildcard correctly when using // Manager<S, ? extends S> @@ -588,7 +613,7 @@ } DataHeader si = d.readDataHeaderForArray(4, expectedLength); @SuppressWarnings("unchecked") - InterfaceRequest<I>[] result = new InterfaceRequest[si.numFields]; + InterfaceRequest<I>[] result = new InterfaceRequest[si.elementsOrVersion]; for (int i = 0; i < result.length; ++i) { result[i] = d.readInterfaceRequest( DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i, @@ -610,13 +635,13 @@ */ private DataHeader readDataHeaderForBooleanArray(int expectedLength) { DataHeader dataHeader = readDataHeader(); - if (dataHeader.size < DataHeader.HEADER_SIZE + (dataHeader.numFields + 7) / 8) { + if (dataHeader.size < DataHeader.HEADER_SIZE + (dataHeader.elementsOrVersion + 7) / 8) { throw new DeserializationException("Array header is incorrect."); } if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH - && dataHeader.numFields != expectedLength) { - throw new DeserializationException("Incorrect array length. Expected: " - + expectedLength + ", but got: " + dataHeader.numFields + "."); + && dataHeader.elementsOrVersion != expectedLength) { + throw new DeserializationException("Incorrect array length. Expected: " + expectedLength + + ", but got: " + dataHeader.elementsOrVersion + "."); } return dataHeader; } @@ -626,13 +651,14 @@ */ private DataHeader readDataHeaderForArray(long elementSize, int expectedLength) { DataHeader dataHeader = readDataHeader(); - if (dataHeader.size < (DataHeader.HEADER_SIZE + elementSize * dataHeader.numFields)) { + if (dataHeader.size + < (DataHeader.HEADER_SIZE + elementSize * dataHeader.elementsOrVersion)) { throw new DeserializationException("Array header is incorrect."); } if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH - && dataHeader.numFields != expectedLength) { - throw new DeserializationException("Incorrect array length. Expected: " - + expectedLength + ", but got: " + dataHeader.numFields + "."); + && dataHeader.elementsOrVersion != expectedLength) { + throw new DeserializationException("Incorrect array length. Expected: " + expectedLength + + ", but got: " + dataHeader.elementsOrVersion + "."); } return dataHeader; }
diff --git a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java index 75cddc97..0f85232 100644 --- a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java +++ b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java
@@ -150,7 +150,7 @@ public void encode(DataHeader s) { mEncoderState.claimMemory(BindingsHelper.align(s.size)); encode(s.size, DataHeader.SIZE_OFFSET); - encode(s.numFields, DataHeader.NUM_FIELDS_OFFSET); + encode(s.elementsOrVersion, DataHeader.ELEMENTS_OR_VERSION_OFFSET); } /**
diff --git a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceWithClient.java b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceWithClient.java deleted file mode 100644 index f7d8afe..0000000 --- a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceWithClient.java +++ /dev/null
@@ -1,115 +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. - -package org.chromium.mojo.bindings; - -import org.chromium.mojo.system.Core; -import org.chromium.mojo.system.MessagePipeHandle; -import org.chromium.mojo.system.Pair; - -/** - * Base class for mojo generated interfaces that have a client. - * - * @param <CI> the type of the client interface. - */ -public interface InterfaceWithClient<CI extends Interface> extends Interface { - - /** - * Proxy class for interfaces with a client. - */ - interface Proxy<CI extends Interface> extends Interface.Proxy, InterfaceWithClient<CI> { - } - - /** - * Base implementation of Proxy. - * - * @param <CI> the type of the client interface. - */ - abstract class AbstractProxy<CI extends Interface> extends Interface.AbstractProxy - implements Proxy<CI> { - - /** - * Constructor. - * - * @param core the Core implementation used to create pipes and access the async waiter. - * @param messageReceiver the message receiver to send message to. - */ - public AbstractProxy(Core core, MessageReceiverWithResponder messageReceiver) { - super(core, messageReceiver); - } - - /** - * @see InterfaceWithClient#setClient(Interface) - */ - @Override - public void setClient(CI client) { - throw new UnsupportedOperationException( - "Setting the client on a proxy is not supported"); - } - } - - /** - * Base manager implementation for interfaces that have a client. - * - * @param <I> the type of the interface the manager can handle. - * @param <P> the type of the proxy the manager can handle. To be noted, P always extends I. - * @param <CI> the type of the client interface. - */ - abstract class Manager<I extends InterfaceWithClient<CI>, P extends Proxy<CI>, - CI extends Interface> extends Interface.Manager<I, P> { - - /** - * @see Interface.Manager#bind(Interface, MessagePipeHandle) - */ - @Override - public final void bind(I impl, MessagePipeHandle handle) { - Router router = new RouterImpl(handle); - super.bind(handle.getCore(), impl, router); - @SuppressWarnings("unchecked") - CI client = (CI) getClientManager().attachProxy(handle.getCore(), router); - impl.setClient(client); - router.start(); - } - - /** - * Returns a Proxy that will send messages to the given |handle|. This implies that the - * other end of the handle must be connected to an implementation of the interface. |client| - * is the implementation of the client interface. - */ - public P attachProxy(MessagePipeHandle handle, CI client) { - Router router = new RouterImpl(handle); - DelegatingConnectionErrorHandler handlers = new DelegatingConnectionErrorHandler(); - handlers.addConnectionErrorHandler(client); - router.setErrorHandler(handlers); - getClientManager().bind(handle.getCore(), client, router); - P proxy = super.attachProxy(handle.getCore(), router); - handlers.addConnectionErrorHandler(proxy); - router.start(); - return proxy; - } - - /** - * Constructs a new |InterfaceRequest| for the interface. This method returns a Pair where - * the first element is a proxy, and the second element is the request. The proxy can be - * used immediately. - * - * @param client the implementation of the client interface. - */ - public final Pair<P, InterfaceRequest<I>> getInterfaceRequest(Core core, CI client) { - Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null); - P proxy = attachProxy(handles.first, client); - return Pair.create(proxy, new InterfaceRequest<I>(handles.second)); - } - - /** - * Returns a manager for the client inetrafce. - */ - protected abstract Interface.Manager<CI, ?> getClientManager(); - } - - /** - * Set the client implementation for this interface. - */ - public void setClient(CI client); -}
diff --git a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageHeader.java b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageHeader.java index dcaf86c..34f3d14 100644 --- a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageHeader.java +++ b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageHeader.java
@@ -14,14 +14,14 @@ public class MessageHeader { private static final int SIMPLE_MESSAGE_SIZE = 16; - private static final int SIMPLE_MESSAGE_NUM_FIELDS = 2; + private static final int SIMPLE_MESSAGE_VERSION = 2; private static final DataHeader SIMPLE_MESSAGE_STRUCT_INFO = - new DataHeader(SIMPLE_MESSAGE_SIZE, SIMPLE_MESSAGE_NUM_FIELDS); + new DataHeader(SIMPLE_MESSAGE_SIZE, SIMPLE_MESSAGE_VERSION); private static final int MESSAGE_WITH_REQUEST_ID_SIZE = 24; - private static final int MESSAGE_WITH_REQUEST_ID_NUM_FIELDS = 3; + private static final int MESSAGE_WITH_REQUEST_ID_VERSION = 3; private static final DataHeader MESSAGE_WITH_REQUEST_ID_STRUCT_INFO = - new DataHeader(MESSAGE_WITH_REQUEST_ID_SIZE, MESSAGE_WITH_REQUEST_ID_NUM_FIELDS); + new DataHeader(MESSAGE_WITH_REQUEST_ID_SIZE, MESSAGE_WITH_REQUEST_ID_VERSION); private static final int TYPE_OFFSET = 8; private static final int FLAGS_OFFSET = 12; @@ -216,28 +216,25 @@ * Validate that the given {@link DataHeader} can be the data header of a message header. */ private static void validateDataHeader(DataHeader dataHeader) { - if (dataHeader.numFields < SIMPLE_MESSAGE_NUM_FIELDS) { - throw new DeserializationException( - "Incorrect number of fields, expecting at least " + SIMPLE_MESSAGE_NUM_FIELDS - + ", but got: " + dataHeader.numFields); + if (dataHeader.elementsOrVersion < SIMPLE_MESSAGE_VERSION) { + throw new DeserializationException("Incorrect number of fields, expecting at least " + + SIMPLE_MESSAGE_VERSION + ", but got: " + dataHeader.elementsOrVersion); } if (dataHeader.size < SIMPLE_MESSAGE_SIZE) { throw new DeserializationException( "Incorrect message size, expecting at least " + SIMPLE_MESSAGE_SIZE + ", but got: " + dataHeader.size); } - if (dataHeader.numFields == SIMPLE_MESSAGE_NUM_FIELDS + if (dataHeader.elementsOrVersion == SIMPLE_MESSAGE_VERSION && dataHeader.size != SIMPLE_MESSAGE_SIZE) { - throw new DeserializationException( - "Incorrect message size for a message with " + SIMPLE_MESSAGE_NUM_FIELDS - + " fields, expecting " + SIMPLE_MESSAGE_SIZE + ", but got: " - + dataHeader.size); + throw new DeserializationException("Incorrect message size for a message with " + + SIMPLE_MESSAGE_VERSION + " fields, expecting " + SIMPLE_MESSAGE_SIZE + + ", but got: " + dataHeader.size); } - if (dataHeader.numFields == MESSAGE_WITH_REQUEST_ID_NUM_FIELDS + if (dataHeader.elementsOrVersion == MESSAGE_WITH_REQUEST_ID_VERSION && dataHeader.size != MESSAGE_WITH_REQUEST_ID_SIZE) { - throw new DeserializationException( - "Incorrect message size for a message with " - + MESSAGE_WITH_REQUEST_ID_NUM_FIELDS + " fields, expecting " + throw new DeserializationException("Incorrect message size for a message with " + + MESSAGE_WITH_REQUEST_ID_VERSION + " fields, expecting " + MESSAGE_WITH_REQUEST_ID_SIZE + ", but got: " + dataHeader.size); } }
diff --git a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Struct.java b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Struct.java index 017d0ef..d7369fab 100644 --- a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Struct.java +++ b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Struct.java
@@ -15,7 +15,6 @@ * The header for a mojo complex element. */ public static final class DataHeader { - /** * The size of a serialized header, in bytes. */ @@ -29,18 +28,26 @@ /** * The offset of the number of fields field. */ - public static final int NUM_FIELDS_OFFSET = 4; + public static final int ELEMENTS_OR_VERSION_OFFSET = 4; + /** + * The size of the object owning this header. + */ public final int size; - public final int numFields; + + /** + * Number of element (for an array) or version (for a struct) of the object owning this + * header. + */ + public final int elementsOrVersion; /** * Constructor. */ - public DataHeader(int size, int numFields) { + public DataHeader(int size, int elementsOrVersion) { super(); this.size = size; - this.numFields = numFields; + this.elementsOrVersion = elementsOrVersion; } /** @@ -50,7 +57,7 @@ public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + numFields; + result = prime * result + elementsOrVersion; result = prime * result + size; return result; } @@ -68,8 +75,7 @@ return false; DataHeader other = (DataHeader) object; - return (numFields == other.numFields && - size == other.size); + return (elementsOrVersion == other.elementsOrVersion && size == other.size); } }
diff --git a/third_party/mojo/src/mojo/public/java/system/src/org/chromium/mojo/system/Core.java b/third_party/mojo/src/mojo/public/java/system/src/org/chromium/mojo/system/Core.java index 660a13f..ba0e5c6f 100644 --- a/third_party/mojo/src/mojo/public/java/system/src/org/chromium/mojo/system/Core.java +++ b/third_party/mojo/src/mojo/public/java/system/src/org/chromium/mojo/system/Core.java
@@ -309,4 +309,13 @@ */ public AsyncWaiter getDefaultAsyncWaiter(); + /** + * Returns a new run loop. + */ + public RunLoop createDefaultRunLoop(); + + /** + * Returns the current run loop if it exists. + */ + public RunLoop getCurrentRunLoop(); }
diff --git a/third_party/mojo/src/mojo/public/java/system/src/org/chromium/mojo/system/DataPipe.java b/third_party/mojo/src/mojo/public/java/system/src/org/chromium/mojo/system/DataPipe.java index a5b77ae9..a6683fdd 100644 --- a/third_party/mojo/src/mojo/public/java/system/src/org/chromium/mojo/system/DataPipe.java +++ b/third_party/mojo/src/mojo/public/java/system/src/org/chromium/mojo/system/DataPipe.java
@@ -18,7 +18,6 @@ */ public static class CreateFlags extends Flags<CreateFlags> { private static final int FLAG_NONE = 0; - private static final int FLAG_MAY_DISCARD = 1 << 0; /** * Immutable flag with not bit set. @@ -35,18 +34,6 @@ } /** - * Change the may-discard bit of this flag. This indicates that the data pipe may discard - * data for whatever reason; best-effort delivery. In particular, if the capacity is - * reached, old data may be discard to make room for new data. - * - * @param mayDiscard the new value of the may-discard bit. - * @return this. - */ - public CreateFlags setMayDiscard(boolean mayDiscard) { - return setFlag(FLAG_MAY_DISCARD, mayDiscard); - } - - /** * @return flags with no bit set. */ public static CreateFlags none() {
diff --git a/third_party/mojo/src/mojo/public/java/system/src/org/chromium/mojo/system/RunLoop.java b/third_party/mojo/src/mojo/public/java/system/src/org/chromium/mojo/system/RunLoop.java new file mode 100644 index 0000000..4038b295 --- /dev/null +++ b/third_party/mojo/src/mojo/public/java/system/src/org/chromium/mojo/system/RunLoop.java
@@ -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. + +package org.chromium.mojo.system; + +import java.io.Closeable; + +/** + * Definition of a run loop. + */ +public interface RunLoop extends Closeable { + /** + * Start the run loop. It will continue until quit() is called. + */ + public void run(); + + /** + * Start the run loop and stop it as soon as no task is present in the work queue. + */ + public void runUntilIdle(); + + /* + * Quit the currently running run loop. + */ + public void quit(); + + /** + * Add a runnable to the queue of tasks. + * @param runnable Callback to be executed by the run loop. + * @param delay Delay, in MojoTimeTicks (microseconds) before the callback should + * be executed. + */ + public void postDelayedTask(Runnable runnable, long delay); + + /** + * Destroy the run loop and deregister it from Core. + */ + @Override + public abstract void close(); +}
diff --git a/third_party/mojo/src/mojo/public/js/connection.js b/third_party/mojo/src/mojo/public/js/connection.js index 4a7a8b8..62e8798 100644 --- a/third_party/mojo/src/mojo/public/js/connection.js +++ b/third_party/mojo/src/mojo/public/js/connection.js
@@ -73,52 +73,6 @@ TestConnection.prototype = Object.create(Connection.prototype); - // TODO(hansmuller): remove when Shell.mojom loses its client. - function createOpenConnection( - messagePipeHandle, client, localInterface, remoteInterface) { - var stubClass = (localInterface && localInterface.stubClass) || EmptyStub; - var proxyClass = - (remoteInterface && remoteInterface.proxyClass) || EmptyProxy; - var proxy = new proxyClass; - var stub = new stubClass; - var router = new Router(messagePipeHandle); - var connection = new BaseConnection(stub, proxy, router); - - ProxyBindings(proxy).connection = connection; - ProxyBindings(proxy).local = connection.local; - StubBindings(stub).connection = connection; - StubBindings(proxy).remote = connection.remote; - - var clientImpl = client instanceof Function ? client(proxy) : client; - if (clientImpl) - StubBindings(stub).delegate = clientImpl; - - return connection; - } - - // TODO(hansmuller): remove when Shell.mojom loses its client. - // Return a message pipe handle. - function bindProxyClient(clientImpl, localInterface, remoteInterface) { - var messagePipe = core.createMessagePipe(); - if (messagePipe.result != core.RESULT_OK) - throw new Error("createMessagePipe failed " + messagePipe.result); - - createOpenConnection( - messagePipe.handle0, clientImpl, localInterface, remoteInterface); - return messagePipe.handle1; - } - - // TODO(hansmuller): remove when Shell.mojom loses its client. - // Return a proxy. - function bindProxyHandle(proxyHandle, localInterface, remoteInterface) { - if (!core.isHandle(proxyHandle)) - throw new Error("Not a handle " + proxyHandle); - - var connection = createOpenConnection( - proxyHandle, undefined, localInterface, remoteInterface); - return connection.remote; - } - // Return a handle for a message pipe that's connected to a proxy // for remoteInterface. Used by generated code for outgoing interface& // (request) parameters: the caller is given the generated proxy via @@ -193,10 +147,6 @@ exports.Connection = Connection; exports.TestConnection = TestConnection; - // TODO(hansmuller): remove these when Shell.mojom loses its client. - exports.bindProxyHandle = bindProxyHandle; - exports.bindProxyClient = bindProxyClient; - exports.bindProxy = bindProxy; exports.bindImpl = bindImpl; exports.bindHandleToProxy = bindHandleToProxy;
diff --git a/third_party/mojo/src/mojo/public/js/core.js b/third_party/mojo/src/mojo/public/js/core.js index 6eb6ae6..b89a9560 100644 --- a/third_party/mojo/src/mojo/public/js/core.js +++ b/third_party/mojo/src/mojo/public/js/core.js
@@ -95,7 +95,6 @@ // MojoCreateDataPipeOptionsFlags var CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; -var CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD; /* * MojoWriteDataFlags: Used to specify different modes to |writeData()|.
diff --git a/third_party/mojo/src/mojo/public/js/validation_unittests.js b/third_party/mojo/src/mojo/public/js/validation_unittests.js index 05988f3..a04879c 100644 --- a/third_party/mojo/src/mojo/public/js/validation_unittests.js +++ b/third_party/mojo/src/mojo/public/js/validation_unittests.js
@@ -225,8 +225,11 @@ expect(testFiles.length).toBeGreaterThan(0); for (var i = 0; i < testFiles.length; i++) { - // TODO(hansmuller): Temporarily skipping array pointer overflow tests. - if (testFiles[i].indexOf("overflow") != -1) { + // TODO(hansmuller, yzshen): Temporarily skipping: + // - array pointer overflow tests; + // - struct versioning tests (tests with "mthd11" in the name). + if (testFiles[i].indexOf("overflow") != -1 || + testFiles[i].indexOf("mthd11") != -1) { console.log("[Skipping " + testFiles[i] + "]"); continue; } @@ -249,13 +252,8 @@ testInterface.ConformanceTestInterface.validateRequest]); } - function testNotImplementedMessageValidation() { - testMessageValidation("not_implemented_", [ - testInterface.ConformanceTestInterface.validateRequest]); - } - - function testIntegratedMessageValidation() { - var testFiles = getMessageTestFiles("integration_"); + function testIntegratedMessageValidation(testFilesPattern) { + var testFiles = getMessageTestFiles(testFilesPattern); expect(testFiles.length).toBeGreaterThan(0); for (var i = 0; i < testFiles.length; i++) { @@ -279,8 +277,8 @@ var testConnection = new connection.TestConnection( testMessagePipe.handle1, - testInterface.IntegrationTestInterface1.stubClass, - testInterface.IntegrationTestInterface2.proxyClass); + testInterface.IntegrationTestInterface.stubClass, + testInterface.IntegrationTestInterface.proxyClass); var validationError = noError; testConnection.router_.validationErrorHandler = function(err) { @@ -295,8 +293,22 @@ } } + function testIntegratedMessageHeaderValidation() { + testIntegratedMessageValidation("integration_msghdr"); + } + + function testIntegratedRequestMessageValidation() { + testIntegratedMessageValidation("integration_intf_rqst"); + } + + function testIntegratedResponseMessageValidation() { + testIntegratedMessageValidation("integration_intf_resp"); + } + expect(checkTestMessageParser()).toBeNull(); testConformanceMessageValidation(); - testIntegratedMessageValidation(); + testIntegratedMessageHeaderValidation(); + testIntegratedResponseMessageValidation(); + testIntegratedRequestMessageValidation(); this.result = "PASS"; });
diff --git a/third_party/mojo/src/mojo/public/mojo.gni b/third_party/mojo/src/mojo/public/mojo.gni index 9f1b86b..bc90a236 100644 --- a/third_party/mojo/src/mojo/public/mojo.gni +++ b/third_party/mojo/src/mojo/public/mojo.gni
@@ -6,10 +6,19 @@ # If using the prebuilt shell, gate its usage by the platforms for which it is # published. -if (!defined(use_prebuilt_mojo_shell) || use_prebuilt_mojo_shell) { +use_prebuilt_mojo_shell = false +if (!defined(build_mojo_shell_from_source) || !build_mojo_shell_from_source) { use_prebuilt_mojo_shell = is_linux || is_android } +# If using the prebuilt network service, gate its usage by the platforms for +# which it is published. +use_prebuilt_network_service = false +if (!defined(build_network_service_from_source) || + !build_network_service_from_source) { + use_prebuilt_network_service = is_linux || is_android +} + # The absolute path to the directory containing the mojo public SDK (i.e., the # directory containing mojo/public). The build files within the Mojo public # SDK use this variable to allow themselves to be parameterized by the location
diff --git a/third_party/mojo/src/mojo/public/mojo_application.gni b/third_party/mojo/src/mojo/public/mojo_application.gni index 7661c888..0cf7bff5 100644 --- a/third_party/mojo/src/mojo/public/mojo_application.gni +++ b/third_party/mojo/src/mojo/public/mojo_application.gni
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/module_args/mojo.gni") import("mojo.gni") import("mojo_sdk.gni") @@ -9,144 +10,281 @@ # of a shared library. template("mojo_native_application") { if (defined(invoker.output_name)) { - output = invoker.output_name + ".mojo" - library_target_name = invoker.output_name + "_library" + base_target_name = invoker.output_name } else { - output = target_name + ".mojo" - library_target_name = target_name + "_library" - } - - if (is_linux || is_android) { - library_name = "lib${library_target_name}.so" - } else if (is_win) { - library_name = "${library_target_name}.dll" - } else if (is_mac) { - library_name = "lib${library_target_name}.dylib" - } else { - assert(false, "Platform not supported.") - } - - if (is_android) { - # On android, use the stripped version of the library, because applications - # are always fetched over the network. - library_dir = "${root_out_dir}/lib.stripped" - } else { - library_dir = root_out_dir + base_target_name = target_name } final_target_name = target_name - shared_library(library_target_name) { - 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.defines)) { - defines = invoker.defines - } - 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 (!is_nacl) { + output = base_target_name + ".mojo" + library_target_name = base_target_name + "_library" - if (use_prebuilt_mojo_shell) { - copy_mojo_shell = - rebase_path("mojo/public/tools:copy_mojo_shell", ".", mojo_root) - } - - # Copy the prebuilt mojo_shell if using it. - if (defined(invoker.data_deps)) { - data_deps = invoker.data_deps - if (use_prebuilt_mojo_shell) { - data_deps += [ copy_mojo_shell ] - } + if (is_linux || is_android) { + library_name = "lib${library_target_name}.so" + } else if (is_win) { + library_name = "${library_target_name}.dll" + } else if (is_mac) { + library_name = "lib${library_target_name}.dylib" } else { - if (use_prebuilt_mojo_shell) { - data_deps = [ copy_mojo_shell ] + assert(false, "Platform not supported.") + } + + if (is_android) { + # On android, use the stripped version of the library, because applications + # are always fetched over the network. + library_dir = "${root_out_dir}/lib.stripped" + } else { + library_dir = root_out_dir + } + + shared_library(library_target_name) { + if (defined(invoker.cflags)) { + cflags = invoker.cflags } - } - deps = rebase_path([ - "mojo/public/c/system", - "mojo/public/platform/native:system", - ], - ".", - mojo_root) - if (defined(invoker.deps)) { - deps += invoker.deps - } - if (defined(invoker.forward_dependent_configs_from)) { - forward_dependent_configs_from = invoker.forward_dependent_configs_from - } - if (defined(invoker.public_deps)) { - public_deps = invoker.public_deps - } - if (defined(invoker.all_dependent_configs)) { - all_dependent_configs = invoker.all_dependent_configs - } - if (defined(invoker.public_configs)) { - public_configs = invoker.public_configs - } - if (defined(invoker.check_includes)) { - check_includes = invoker.check_includes - } - if (defined(invoker.configs)) { - configs += invoker.configs - } - if (defined(invoker.data)) { - data = invoker.data - } - if (defined(invoker.inputs)) { - inputs = invoker.inputs - } - if (defined(invoker.public)) { - public = invoker.public - } - if (defined(invoker.sources)) { - sources = invoker.sources - } - if (defined(invoker.testonly)) { - testonly = invoker.testonly + 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.defines)) { + defines = invoker.defines + } + 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 + } + + data_deps = [] + if (defined(invoker.data_deps)) { + data_deps = invoker.data_deps + } + + # Copy any necessary prebuilt artifacts. + if (use_prebuilt_mojo_shell) { + data_deps += + [ rebase_path("mojo/public/tools:copy_mojo_shell", ".", mojo_root) ] + } + if (use_prebuilt_network_service) { + data_deps += [ rebase_path("mojo/public/tools:copy_network_service", + ".", + mojo_root) ] + } + + deps = rebase_path([ + "mojo/public/c/system", + "mojo/public/platform/native:system", + ], + ".", + mojo_root) + if (defined(invoker.deps)) { + deps += invoker.deps + } + if (defined(invoker.forward_dependent_configs_from)) { + forward_dependent_configs_from = invoker.forward_dependent_configs_from + } + if (defined(invoker.public_deps)) { + public_deps = invoker.public_deps + } + if (defined(invoker.all_dependent_configs)) { + all_dependent_configs = invoker.all_dependent_configs + } + if (defined(invoker.public_configs)) { + public_configs = invoker.public_configs + } + if (defined(invoker.check_includes)) { + check_includes = invoker.check_includes + } + if (defined(invoker.configs)) { + configs += invoker.configs + } + if (defined(invoker.data)) { + data = invoker.data + } + if (defined(invoker.inputs)) { + inputs = invoker.inputs + } + if (defined(invoker.public)) { + public = invoker.public + } + if (defined(invoker.sources)) { + sources = invoker.sources + } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + + visibility = [ ":${final_target_name}" ] } - visibility = [ ":${final_target_name}" ] - } + copy(final_target_name) { + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + if (defined(invoker.visibility)) { + visibility = invoker.visibility + } + deps = [ + ":${library_target_name}", + ] - copy(final_target_name) { - if (defined(invoker.testonly)) { - testonly = invoker.testonly + sources = [ + "${library_dir}/${library_name}", + ] + outputs = [ + "${root_out_dir}/${output}", + ] } - if (defined(invoker.visibility)) { - visibility = invoker.visibility - } - deps = [ - ":${library_target_name}", - ] + } else { + nexe_target_name = base_target_name + "_nexe" + nexe_name = base_target_name + ".nexe" - sources = [ - "${library_dir}/${library_name}", - ] - outputs = [ - "${root_out_dir}/${output}", - ] + output = "${base_target_name}_${cpu_arch}.nexe.mojo" + + executable(nexe_target_name) { + output_name = base_target_name + + 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.defines)) { + defines = invoker.defines + } + 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 + } + + data_deps = [] + if (defined(invoker.data_deps)) { + data_deps = invoker.data_deps + } + + # Copy any necessary prebuilt artifacts. + if (use_prebuilt_mojo_shell) { + data_deps += + [ rebase_path("mojo/public/tools:copy_mojo_shell", ".", mojo_root) ] + } + if (use_prebuilt_network_service) { + data_deps += [ rebase_path("mojo/public/tools:copy_network_service", + ".", + mojo_root) ] + } + + deps = rebase_path([ + "mojo/public/c/system", + "mojo/public/platform/nacl:system", + ], + ".", + mojo_root) + if (defined(invoker.deps)) { + deps += invoker.deps + } + if (defined(invoker.forward_dependent_configs_from)) { + forward_dependent_configs_from = invoker.forward_dependent_configs_from + } + if (defined(invoker.public_deps)) { + public_deps = invoker.public_deps + } + if (defined(invoker.all_dependent_configs)) { + all_dependent_configs = invoker.all_dependent_configs + } + if (defined(invoker.public_configs)) { + public_configs = invoker.public_configs + } + if (defined(invoker.check_includes)) { + check_includes = invoker.check_includes + } + if (defined(invoker.configs)) { + configs += invoker.configs + } + if (defined(invoker.data)) { + data = invoker.data + } + if (defined(invoker.inputs)) { + inputs = invoker.inputs + } + if (defined(invoker.public)) { + public = invoker.public + } + if (defined(invoker.sources)) { + sources = invoker.sources + } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + + visibility = [ ":${final_target_name}" ] + } + + action(target_name) { + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + if (defined(invoker.visibility)) { + visibility = invoker.visibility + } + + script = rebase_path("mojo/public/tools/prepend.py", ".", mojo_root) + + input_path = "${root_out_dir}/${nexe_name}" + inputs = [ + input_path, + ] + + output_path = "${root_build_dir}/${output}" + outputs = [ + output_path, + ] + + deps = [ + ":${nexe_target_name}", + ] + + rebase_input = rebase_path(input_path, root_build_dir) + rebase_output = rebase_path(output_path, root_build_dir) + args = [ + "--input=$rebase_input", + "--output=$rebase_output", + "--line=#!mojo mojo:nacl_content_handler", + ] + } } }
diff --git a/third_party/mojo/src/mojo/public/platform/nacl/BUILD.gn b/third_party/mojo/src/mojo/public/platform/nacl/BUILD.gn new file mode 100644 index 0000000..29ad7976 --- /dev/null +++ b/third_party/mojo/src/mojo/public/platform/nacl/BUILD.gn
@@ -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. + +import("../../mojo_sdk.gni") + +# Untrusted code +if (is_nacl) { + # Thunk mapping the Mojo public API onto NaCl syscalls. + mojo_sdk_source_set("mojo") { + sources = [ + "libmojo.cc", + "mojo_irt.h", + ] + mojo_sdk_deps = [ "mojo/public/c/system" ] + } + + mojo_sdk_source_set("system") { + sources = [ + "mojo_initial_handle.h", + "mojo_main_thunk.cc", + ] + + mojo_sdk_deps = [ + "mojo/public/c/system", + "mojo/public/platform/nacl:mojo", + ] + } +}
diff --git a/third_party/mojo/src/mojo/public/platform/nacl/libmojo.cc b/third_party/mojo/src/mojo/public/platform/nacl/libmojo.cc new file mode 100644 index 0000000..99eddf0 --- /dev/null +++ b/third_party/mojo/src/mojo/public/platform/nacl/libmojo.cc
@@ -0,0 +1,226 @@ +// 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. + +// WARNING this file was generated by generate_nacl_bindings.py +// Do not edit by hand. + +#include "mojo/public/c/system/core.h" +#include "mojo/public/platform/nacl/mojo_irt.h" +#include "native_client/src/public/chrome_main.h" +#include "native_client/src/public/imc_syscalls.h" +#include "native_client/src/public/imc_types.h" +#include "native_client/src/untrusted/irt/irt.h" + +// The value for this FD must not conflict with uses inside Chromium. However, +// mojo/nacl doesn't depend on any Chromium headers, so we can't use a #define +// from there. +#define NACL_MOJO_DESC (NACL_CHROME_DESC_BASE + 3) + +bool g_irt_mojo_valid = false; +struct nacl_irt_mojo g_irt_mojo; + +struct nacl_irt_mojo* get_irt_mojo() { + if (!g_irt_mojo_valid) { + size_t rc = nacl_interface_query(NACL_IRT_MOJO_v0_1, &g_irt_mojo, + sizeof(g_irt_mojo)); + if (rc != sizeof(g_irt_mojo)) + return NULL; + else + g_irt_mojo_valid = true; + } + return &g_irt_mojo; +} + +MojoResult MojoCreateSharedBuffer( + const struct MojoCreateSharedBufferOptions* options, + uint64_t num_bytes, + MojoHandle* shared_buffer_handle) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoCreateSharedBuffer(options, num_bytes, + shared_buffer_handle); +} + +MojoResult MojoDuplicateBufferHandle( + MojoHandle buffer_handle, + const struct MojoDuplicateBufferHandleOptions* options, + MojoHandle* new_buffer_handle) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoDuplicateBufferHandle(buffer_handle, options, + new_buffer_handle); +} + +MojoResult MojoMapBuffer(MojoHandle buffer_handle, + uint64_t offset, + uint64_t num_bytes, + void** buffer, + MojoMapBufferFlags flags) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoMapBuffer(buffer_handle, offset, num_bytes, buffer, + flags); +} + +MojoResult MojoUnmapBuffer(void* buffer) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoUnmapBuffer(buffer); +} + +MojoResult MojoCreateDataPipe(const struct MojoCreateDataPipeOptions* options, + MojoHandle* data_pipe_producer_handle, + MojoHandle* data_pipe_consumer_handle) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoCreateDataPipe(options, data_pipe_producer_handle, + data_pipe_consumer_handle); +} + +MojoResult MojoWriteData(MojoHandle data_pipe_producer_handle, + const void* elements, + uint32_t* num_bytes, + MojoWriteDataFlags flags) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoWriteData(data_pipe_producer_handle, elements, num_bytes, + flags); +} + +MojoResult MojoBeginWriteData(MojoHandle data_pipe_producer_handle, + void** buffer, + uint32_t* buffer_num_bytes, + MojoWriteDataFlags flags) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoBeginWriteData(data_pipe_producer_handle, buffer, + buffer_num_bytes, flags); +} + +MojoResult MojoEndWriteData(MojoHandle data_pipe_producer_handle, + uint32_t num_bytes_written) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoEndWriteData(data_pipe_producer_handle, + num_bytes_written); +} + +MojoResult MojoReadData(MojoHandle data_pipe_consumer_handle, + void* elements, + uint32_t* num_bytes, + MojoReadDataFlags flags) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoReadData(data_pipe_consumer_handle, elements, num_bytes, + flags); +} + +MojoResult MojoBeginReadData(MojoHandle data_pipe_consumer_handle, + const void** buffer, + uint32_t* buffer_num_bytes, + MojoReadDataFlags flags) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoBeginReadData(data_pipe_consumer_handle, buffer, + buffer_num_bytes, flags); +} + +MojoResult MojoEndReadData(MojoHandle data_pipe_consumer_handle, + uint32_t num_bytes_read) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoEndReadData(data_pipe_consumer_handle, num_bytes_read); +} + +MojoTimeTicks MojoGetTimeTicksNow() { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoGetTimeTicksNow(); +} + +MojoResult MojoClose(MojoHandle handle) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoClose(handle); +} + +MojoResult MojoWait(MojoHandle handle, + MojoHandleSignals signals, + MojoDeadline deadline, + struct MojoHandleSignalsState* signals_state) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoWait(handle, signals, deadline, signals_state); +} + +MojoResult MojoWaitMany(const MojoHandle* handles, + const MojoHandleSignals* signals, + uint32_t num_handles, + MojoDeadline deadline, + uint32_t* result_index, + struct MojoHandleSignalsState* signals_states) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoWaitMany(handles, signals, num_handles, deadline, + result_index, signals_states); +} + +MojoResult MojoCreateMessagePipe( + const struct MojoCreateMessagePipeOptions* options, + MojoHandle* message_pipe_handle0, + MojoHandle* message_pipe_handle1) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoCreateMessagePipe(options, message_pipe_handle0, + message_pipe_handle1); +} + +MojoResult MojoWriteMessage(MojoHandle message_pipe_handle, + const void* bytes, + uint32_t num_bytes, + const MojoHandle* handles, + uint32_t num_handles, + MojoWriteMessageFlags flags) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoWriteMessage(message_pipe_handle, bytes, num_bytes, + handles, num_handles, flags); +} + +MojoResult MojoReadMessage(MojoHandle message_pipe_handle, + void* bytes, + uint32_t* num_bytes, + MojoHandle* handles, + uint32_t* num_handles, + MojoReadMessageFlags flags) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->MojoReadMessage(message_pipe_handle, bytes, num_bytes, + handles, num_handles, flags); +} + +MojoResult _MojoGetInitialHandle(MojoHandle* handle) { + struct nacl_irt_mojo* irt_mojo = get_irt_mojo(); + if (irt_mojo == NULL) + return MOJO_RESULT_INTERNAL; + return irt_mojo->_MojoGetInitialHandle(handle); +}
diff --git a/third_party/mojo/src/mojo/public/platform/nacl/mojo_irt.h b/third_party/mojo/src/mojo/public/platform/nacl/mojo_irt.h new file mode 100644 index 0000000..db3a180f --- /dev/null +++ b/third_party/mojo/src/mojo/public/platform/nacl/mojo_irt.h
@@ -0,0 +1,100 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// WARNING this file was generated by generate_nacl_bindings.py +// Do not edit by hand. + +#ifndef MOJO_PUBLIC_PLATFORM_NACL_MOJO_IRT_H_ +#define MOJO_PUBLIC_PLATFORM_NACL_MOJO_IRT_H_ + +#include "mojo/public/c/system/buffer.h" +#include "mojo/public/c/system/data_pipe.h" +#include "mojo/public/c/system/message_pipe.h" +#include "mojo/public/c/system/types.h" + +#define NACL_IRT_MOJO_v0_1 "nacl-irt-mojo-0.1" + +struct nacl_irt_mojo { + MojoResult (*MojoCreateSharedBuffer)( + const struct MojoCreateSharedBufferOptions* options, + uint64_t num_bytes, + MojoHandle* shared_buffer_handle); + MojoResult (*MojoDuplicateBufferHandle)( + MojoHandle buffer_handle, + const struct MojoDuplicateBufferHandleOptions* options, + MojoHandle* new_buffer_handle); + MojoResult (*MojoMapBuffer)(MojoHandle buffer_handle, + uint64_t offset, + uint64_t num_bytes, + void** buffer, + MojoMapBufferFlags flags); + MojoResult (*MojoUnmapBuffer)(void* buffer); + MojoResult (*MojoCreateDataPipe)( + const struct MojoCreateDataPipeOptions* options, + MojoHandle* data_pipe_producer_handle, + MojoHandle* data_pipe_consumer_handle); + MojoResult (*MojoWriteData)(MojoHandle data_pipe_producer_handle, + const void* elements, + uint32_t* num_bytes, + MojoWriteDataFlags flags); + MojoResult (*MojoBeginWriteData)(MojoHandle data_pipe_producer_handle, + void** buffer, + uint32_t* buffer_num_bytes, + MojoWriteDataFlags flags); + MojoResult (*MojoEndWriteData)(MojoHandle data_pipe_producer_handle, + uint32_t num_bytes_written); + MojoResult (*MojoReadData)(MojoHandle data_pipe_consumer_handle, + void* elements, + uint32_t* num_bytes, + MojoReadDataFlags flags); + MojoResult (*MojoBeginReadData)(MojoHandle data_pipe_consumer_handle, + const void** buffer, + uint32_t* buffer_num_bytes, + MojoReadDataFlags flags); + MojoResult (*MojoEndReadData)(MojoHandle data_pipe_consumer_handle, + uint32_t num_bytes_read); + MojoTimeTicks (*MojoGetTimeTicksNow)(); + MojoResult (*MojoClose)(MojoHandle handle); + MojoResult (*MojoWait)(MojoHandle handle, + MojoHandleSignals signals, + MojoDeadline deadline, + struct MojoHandleSignalsState* signals_state); + MojoResult (*MojoWaitMany)(const MojoHandle* handles, + const MojoHandleSignals* signals, + uint32_t num_handles, + MojoDeadline deadline, + uint32_t* result_index, + struct MojoHandleSignalsState* signals_states); + MojoResult (*MojoCreateMessagePipe)( + const struct MojoCreateMessagePipeOptions* options, + MojoHandle* message_pipe_handle0, + MojoHandle* message_pipe_handle1); + MojoResult (*MojoWriteMessage)(MojoHandle message_pipe_handle, + const void* bytes, + uint32_t num_bytes, + const MojoHandle* handles, + uint32_t num_handles, + MojoWriteMessageFlags flags); + MojoResult (*MojoReadMessage)(MojoHandle message_pipe_handle, + void* bytes, + uint32_t* num_bytes, + MojoHandle* handles, + uint32_t* num_handles, + MojoReadMessageFlags flags); + MojoResult (*_MojoGetInitialHandle)(MojoHandle* handle); +}; + +#ifdef __cplusplus +extern "C" { +#endif + +size_t mojo_irt_query(const char* interface_ident, + void* table, + size_t tablesize); + +#ifdef __cplusplus +} +#endif + +#endif // MOJO_PUBLIC_PLATFORM_NACL_MOJO_IRT_H_
diff --git a/third_party/mojo/src/mojo/public/platform/nacl/mojo_main_thunk.cc b/third_party/mojo/src/mojo/public/platform/nacl/mojo_main_thunk.cc new file mode 100644 index 0000000..7cb5b52 --- /dev/null +++ b/third_party/mojo/src/mojo/public/platform/nacl/mojo_main_thunk.cc
@@ -0,0 +1,12 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/c/system/main.h" +#include "mojo/public/platform/nacl/mojo_initial_handle.h" + +int main() { + MojoHandle handle; + _MojoGetInitialHandle(&handle); + return MojoMain(handle); +}
diff --git a/third_party/mojo/src/mojo/public/platform/native/BUILD.gn b/third_party/mojo/src/mojo/public/platform/native/BUILD.gn index d67608b..a369e17 100644 --- a/third_party/mojo/src/mojo/public/platform/native/BUILD.gn +++ b/third_party/mojo/src/mojo/public/platform/native/BUILD.gn
@@ -6,8 +6,8 @@ mojo_sdk_source_set("system") { sources = [ - "system_thunks.cc", "system_thunks.h", + "system_thunks.cc", ] defines = [ "MOJO_SYSTEM_IMPLEMENTATION" ] mojo_sdk_deps = [ "mojo/public/c/system" ] @@ -24,14 +24,14 @@ mojo_sdk_source_set("gles2") { sources = [ - "gles2_impl_chromium_sync_point_thunks.cc", - "gles2_impl_chromium_sync_point_thunks.h", - "gles2_impl_chromium_texture_mailbox_thunks.cc", - "gles2_impl_chromium_texture_mailbox_thunks.h", - "gles2_impl_thunks.cc", - "gles2_impl_thunks.h", "gles2_thunks.cc", "gles2_thunks.h", + "gles2_impl_thunks.cc", + "gles2_impl_thunks.h", + "gles2_impl_chromium_texture_mailbox_thunks.cc", + "gles2_impl_chromium_texture_mailbox_thunks.h", + "gles2_impl_chromium_sync_point_thunks.cc", + "gles2_impl_chromium_sync_point_thunks.h", ] defines = [ "MOJO_GLES2_IMPLEMENTATION" ]
diff --git a/third_party/mojo/src/mojo/public/python/BUILD.gn b/third_party/mojo/src/mojo/public/python/BUILD.gn index f4b0b03..d2e13c2c 100644 --- a/third_party/mojo/src/mojo/public/python/BUILD.gn +++ b/third_party/mojo/src/mojo/public/python/BUILD.gn
@@ -78,6 +78,16 @@ ] } +python_package("packaged_application") { + sources = [ + "mojo_application/__init__.py", + "mojo_application/application_delegate.py", + "mojo_application/application_impl.py", + "mojo_application/application_runner.py", + "mojo_application/service_provider_impl.py", + ] +} + # GYP version: mojo.gyp:mojo_python_bindings copy("bindings") { sources = [
diff --git a/third_party/mojo/src/mojo/public/python/c_core.pxd b/third_party/mojo/src/mojo/public/python/c_core.pxd index bd3edd9..fd8fb89 100644 --- a/third_party/mojo/src/mojo/public/python/c_core.pxd +++ b/third_party/mojo/src/mojo/public/python/c_core.pxd
@@ -106,7 +106,6 @@ # data_pipe.h ctypedef uint32_t MojoCreateDataPipeOptionsFlags const MojoCreateDataPipeOptionsFlags MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE - const MojoCreateDataPipeOptionsFlags MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD cdef struct MojoCreateDataPipeOptions: uint32_t struct_size
diff --git a/third_party/mojo/src/mojo/public/python/mojo_application/__init__.py b/third_party/mojo/src/mojo/public/python/mojo_application/__init__.py new file mode 100644 index 0000000..50b23df --- /dev/null +++ b/third_party/mojo/src/mojo/public/python/mojo_application/__init__.py
@@ -0,0 +1,3 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file.
diff --git a/third_party/mojo/src/mojo/public/python/mojo_application/application_delegate.py b/third_party/mojo/src/mojo/public/python/mojo_application/application_delegate.py new file mode 100644 index 0000000..c4a817d --- /dev/null +++ b/third_party/mojo/src/mojo/public/python/mojo_application/application_delegate.py
@@ -0,0 +1,27 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Interface for the delegate of ApplicationImpl.""" + +import mojo_application.application_impl +import mojo_application.service_provider_impl +import shell_mojom + +import mojo_system + +# pylint: disable=unused-argument +class ApplicationDelegate: + def Initialize(self, shell, application): + """ + Called from ApplicationImpl's Initialize() method. + """ + pass + + def OnAcceptConnection(self, service_provider, requestor_url, + exposed_services): + """ + Called from ApplicationImpl's OnAcceptConnection() method. Returns a bool + indicating whether this connection should be accepted. + """ + return True
diff --git a/third_party/mojo/src/mojo/public/python/mojo_application/application_impl.py b/third_party/mojo/src/mojo/public/python/mojo_application/application_impl.py new file mode 100644 index 0000000..34c5780 --- /dev/null +++ b/third_party/mojo/src/mojo/public/python/mojo_application/application_impl.py
@@ -0,0 +1,57 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Python implementation of the Application interface.""" + +import application_mojom +import service_provider_mojom +import shell_mojom +from mojo_application.service_provider_impl import ServiceProviderImpl + +import mojo_system + +class ApplicationImpl(application_mojom.Application): + def __init__(self, delegate, app_request_handle): + self.shell = None + self.url = None + self.args = None + self._delegate = delegate + self._providers = [] + application_mojom.Application.manager.Bind(self, app_request_handle) + + def Initialize(self, shell, url, args): + self.shell = shell + self.url = url + self.args = args + self._delegate.Initialize(shell, self) + + def AcceptConnection(self, requestor_url, services, exposed_services, + resolved_url): + service_provider = ServiceProviderImpl(services) + if self._delegate.OnAcceptConnection(service_provider, requestor_url, + exposed_services): + # We keep a reference to ServiceProviderImpl to ensure neither it nor + # |services| gets garbage collected. + services.Bind(service_provider) + self._providers.append(service_provider) + + def removeServiceProvider(): + self._providers.remove(service_provider) + service_provider.manager.AddOnErrorCallback(removeServiceProvider) + + def ConnectToService(self, application_url, service_class): + """ + Helper method to connect to a service. |application_url| is the URL of the + application to be connected to, and |service_class| is the class of the + service to be connected to. Returns a proxy to the service. + """ + application_proxy, request = ( + service_provider_mojom.ServiceProvider.manager.NewRequest()) + self.shell.ConnectToApplication(application_url, request, None) + + service_proxy, request = service_class.manager.NewRequest() + application_proxy.ConnectToService(service_class.manager.name, + request.PassMessagePipe()) + + return service_proxy
diff --git a/third_party/mojo/src/mojo/public/python/mojo_application/application_runner.py b/third_party/mojo/src/mojo/public/python/mojo_application/application_runner.py new file mode 100644 index 0000000..e43a518f --- /dev/null +++ b/third_party/mojo/src/mojo/public/python/mojo_application/application_runner.py
@@ -0,0 +1,17 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Helper for running Mojo applications in Python.""" + +from mojo_application.application_impl import ApplicationImpl + +import mojo_system + +def RunMojoApplication(application_delegate, app_request_handle): + loop = mojo_system.RunLoop() + + application = ApplicationImpl(application_delegate, app_request_handle) + application.manager.AddOnErrorCallback(loop.Quit) + + loop.Run()
diff --git a/third_party/mojo/src/mojo/public/python/mojo_application/service_provider_impl.py b/third_party/mojo/src/mojo/public/python/mojo_application/service_provider_impl.py new file mode 100644 index 0000000..0166c76 --- /dev/null +++ b/third_party/mojo/src/mojo/public/python/mojo_application/service_provider_impl.py
@@ -0,0 +1,24 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Python implementation of the ServiceProvider interface.""" + +import logging + +import service_provider_mojom + +class ServiceProviderImpl(service_provider_mojom.ServiceProvider): + def __init__(self, provider): + self._provider = provider + self._name_to_service_connector = {} + + def AddService(self, service_class): + self._name_to_service_connector[service_class.manager.name] = service_class + + def ConnectToService(self, interface_name, pipe): + if interface_name in self._name_to_service_connector: + service = self._name_to_service_connector[interface_name] + service.manager.Bind(service(), pipe) + else: + logging.error("Unable to find service " + interface_name)
diff --git a/third_party/mojo/src/mojo/public/python/mojo_bindings/descriptor.py b/third_party/mojo/src/mojo/public/python/mojo_bindings/descriptor.py index 45e073f..109e5ce 100644 --- a/third_party/mojo/src/mojo/public/python/mojo_bindings/descriptor.py +++ b/third_party/mojo/src/mojo/public/python/mojo_bindings/descriptor.py
@@ -508,8 +508,8 @@ '__module__': __name__, 'DESCRIPTOR': { 'fields': [ - SingleFieldGroup('keys', MapType._GetArrayType(key_type), 0, 0), - SingleFieldGroup('values', MapType._GetArrayType(value_type), 1, 1), + SingleFieldGroup('keys', MapType._GetArrayType(key_type), 0, 1), + SingleFieldGroup('values', MapType._GetArrayType(value_type), 1, 2), ], } } @@ -608,7 +608,10 @@ def GetByteSize(self): raise NotImplementedError() - def GetVersion(self): + def GetMinVersion(self): + raise NotImplementedError() + + def GetMaxVersion(self): raise NotImplementedError() def Serialize(self, obj, data_offset, data, handle_offset): @@ -617,6 +620,9 @@ def Deserialize(self, value, context): raise NotImplementedError() + def Filter(self, version): + raise NotImplementedError() + class SingleFieldGroup(FieldGroup, FieldDescriptor): """A FieldGroup that contains a single FieldDescriptor.""" @@ -632,7 +638,10 @@ def GetByteSize(self): return self.field_type.GetByteSize() - def GetVersion(self): + def GetMinVersion(self): + return self.version + + def GetMaxVersion(self): return self.version def Serialize(self, obj, data_offset, data, handle_offset): @@ -643,12 +652,16 @@ entity = self.field_type.Deserialize(value, context) return { self.name: entity } + def Filter(self, version): + return self + class BooleanGroup(FieldGroup): """A FieldGroup to pack booleans.""" def __init__(self, descriptors): FieldGroup.__init__(self, descriptors) - self.version = min([descriptor.version for descriptor in descriptors]) + self.min_version = min([descriptor.version for descriptor in descriptors]) + self.max_version = max([descriptor.version for descriptor in descriptors]) def GetTypeCode(self): return 'B' @@ -656,8 +669,11 @@ def GetByteSize(self): return 1 - def GetVersion(self): - return self.version + def GetMinVersion(self): + return self.min_version + + def GetMaxVersion(self): + return self.max_version def Serialize(self, obj, data_offset, data, handle_offset): value = _ConvertBooleansToByte( @@ -670,6 +686,10 @@ fillvalue=False) return dict(values) + def Filter(self, version): + return BooleanGroup( + filter(lambda d: d.version <= version, self.descriptors)) + def _SerializeNativeArray(value, data_offset, data, length): data_size = len(data)
diff --git a/third_party/mojo/src/mojo/public/python/mojo_bindings/messaging.py b/third_party/mojo/src/mojo/public/python/mojo_bindings/messaging.py index 385a080..ebdf1ee3 100644 --- a/third_party/mojo/src/mojo/public/python/mojo_bindings/messaging.py +++ b/third_party/mojo/src/mojo/public/python/mojo_bindings/messaging.py
@@ -30,13 +30,13 @@ class MessageHeader(object): """The header of a mojo message.""" - _SIMPLE_MESSAGE_NUM_FIELDS = 2 + _SIMPLE_MESSAGE_VERSION = 2 _SIMPLE_MESSAGE_STRUCT = struct.Struct("<IIII") _REQUEST_ID_STRUCT = struct.Struct("<Q") _REQUEST_ID_OFFSET = _SIMPLE_MESSAGE_STRUCT.size - _MESSAGE_WITH_REQUEST_ID_NUM_FIELDS = 3 + _MESSAGE_WITH_REQUEST_ID_VERSION = 3 _MESSAGE_WITH_REQUEST_ID_SIZE = ( _SIMPLE_MESSAGE_STRUCT.size + _REQUEST_ID_STRUCT.size) @@ -53,11 +53,11 @@ raise serialization.DeserializationException('Header is too short.') (size, version, message_type, flags) = ( cls._SIMPLE_MESSAGE_STRUCT.unpack_from(buf)) - if (version < cls._SIMPLE_MESSAGE_NUM_FIELDS): + if (version < cls._SIMPLE_MESSAGE_VERSION): raise serialization.DeserializationException('Incorrect version.') request_id = 0 if _HasRequestId(flags): - if version < cls._MESSAGE_WITH_REQUEST_ID_NUM_FIELDS: + if version < cls._MESSAGE_WITH_REQUEST_ID_VERSION: raise serialization.DeserializationException('Incorrect version.') if (size < cls._MESSAGE_WITH_REQUEST_ID_SIZE or len(data) < cls._MESSAGE_WITH_REQUEST_ID_SIZE): @@ -105,10 +105,10 @@ def Serialize(self): if not self._data: self._data = bytearray(self.size) - version = self._SIMPLE_MESSAGE_NUM_FIELDS + version = self._SIMPLE_MESSAGE_VERSION size = self._SIMPLE_MESSAGE_STRUCT.size if self.has_request_id: - version = self._MESSAGE_WITH_REQUEST_ID_NUM_FIELDS + version = self._MESSAGE_WITH_REQUEST_ID_VERSION size = self._MESSAGE_WITH_REQUEST_ID_SIZE self._SIMPLE_MESSAGE_STRUCT.pack_into(self._data, 0, size, version, self._message_type, self._flags)
diff --git a/third_party/mojo/src/mojo/public/python/mojo_bindings/promise.py b/third_party/mojo/src/mojo/public/python/mojo_bindings/promise.py index ebf6f85e..7ceb52c 100644 --- a/third_party/mojo/src/mojo/public/python/mojo_bindings/promise.py +++ b/third_party/mojo/src/mojo/public/python/mojo_bindings/promise.py
@@ -149,6 +149,21 @@ """Equivalent to |Then(None, onCatched)|""" return self.Then(None, onCatched) + def __getattr__(self, attribute): + """ + Allows to get member of a promise. It will return a promise that will + resolve to the member of the result. + """ + return self.Then(lambda v: getattr(v, attribute)) + + def __call__(self, *args, **kwargs): + """ + Allows to call this promise. It will return a promise that will resolved to + the result of calling the result of this promise with the given arguments. + """ + return self.Then(lambda v: v(*args, **kwargs)) + + def _Resolve(self, value): if self.state != Promise.STATE_PENDING: return @@ -175,6 +190,16 @@ self._onRejected = None +def async(f): + def _ResolvePromises(*args, **kwargs): + keys = kwargs.keys() + values = kwargs.values() + all_args = list(args) + values + return Promise.All(*all_args).Then( + lambda r: f(*r[:len(args)], **dict(zip(keys, r[len(args):])))) + return _ResolvePromises + + def _IterateAction(iterable): def _Run(x): for f in iterable:
diff --git a/third_party/mojo/src/mojo/public/python/mojo_bindings/reflection.py b/third_party/mojo/src/mojo/public/python/mojo_bindings/reflection.py index 35b8ff2..e41601a 100644 --- a/third_party/mojo/src/mojo/public/python/mojo_bindings/reflection.py +++ b/third_party/mojo/src/mojo/public/python/mojo_bindings/reflection.py
@@ -12,6 +12,7 @@ import mojo_bindings.messaging as messaging import mojo_bindings.promise as promise import mojo_bindings.serialization as serialization +import mojo_system class MojoEnumType(type): @@ -273,6 +274,10 @@ router.Start() + def NewRequest(self): + pipe = mojo_system.MessagePipe() + return (self.Proxy(pipe.handle0), InterfaceRequest(pipe.handle1)) + def _InternalProxy(self, router, error_handler): if error_handler is None: error_handler = _ProxyErrorHandler() @@ -529,6 +534,7 @@ payload.data, payload.handles)).AsDict() response = getattr(self.impl, method.name)(**parameters) if header.expects_response: + @promise.async def SendResponse(response): if isinstance(response, dict): response_message = _GetMessage(method, @@ -539,8 +545,8 @@ messaging.MESSAGE_IS_RESPONSE_FLAG, response) response_message.header.request_id = header.request_id - responder.Accept(response_message) - p = promise.Promise.Resolve(response).Then(SendResponse) + return responder.Accept(response_message) + p = SendResponse(response) if self.impl.manager: # Close the connection in case of error. p.Catch(lambda _: self.impl.manager.Close()) @@ -550,6 +556,7 @@ # Close the connection in case of error. logging.warning( 'Error occured in accept method. Connection will be closed.') + logging.debug("Exception", exc_info=True) if self.impl.manager: self.impl.manager.Close() return False
diff --git a/third_party/mojo/src/mojo/public/python/mojo_bindings/serialization.py b/third_party/mojo/src/mojo/public/python/mojo_bindings/serialization.py index b5ea1bd..dac3518 100644 --- a/third_party/mojo/src/mojo/public/python/mojo_bindings/serialization.py +++ b/third_party/mojo/src/mojo/public/python/mojo_bindings/serialization.py
@@ -152,6 +152,10 @@ version_struct = self._GetStruct(version) entitities = version_struct.unpack_from(context.data, HEADER_STRUCT.size) filtered_groups = self._GetGroups(version) + if ((version <= self.version and + size != version_struct.size + HEADER_STRUCT.size) or + size < version_struct.size + HEADER_STRUCT.size): + raise DeserializationException('Struct size in incorrect.') position = HEADER_STRUCT.size for (group, value) in zip(filtered_groups, entitities): position = position + NeededPaddingForAlignment(position, @@ -168,11 +172,14 @@ def _GetVersion(groups): - return sum([len(x.descriptors) for x in groups]) + if not len(groups): + return 0 + return max([x.GetMaxVersion() for x in groups]) def _FilterGroups(groups, version): - return [group for group in groups if group.GetVersion() < version] + return [group.Filter(version) for + group in groups if group.GetMinVersion() <= version] def _GetStruct(groups):
diff --git a/third_party/mojo/src/mojo/public/python/mojo_system.pyx b/third_party/mojo/src/mojo/public/python/mojo_system.pyx index 4e684af..e07b0e6 100644 --- a/third_party/mojo/src/mojo/public/python/mojo_system.pyx +++ b/third_party/mojo/src/mojo/public/python/mojo_system.pyx
@@ -19,7 +19,7 @@ from cpython.object cimport Py_EQ, Py_NE from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t, uintptr_t -import ctypes +import weakref import threading import mojo_system_impl @@ -685,7 +685,6 @@ See mojo/public/c/system/data_pipe.h """ FLAG_NONE = c_core.MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE - FLAG_MAY_DISCARD = c_core.MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD def __init__(self): self.flags = CreateDataPipeOptions.FLAG_NONE @@ -770,7 +769,7 @@ def __init__(self): self.__run_loop = mojo_system_impl.RunLoop() - _RUN_LOOPS.loop = id(self) + _RUN_LOOPS.loop = weakref.ref(self) def __del__(self): del _RUN_LOOPS.loop @@ -797,7 +796,7 @@ @staticmethod def Current(): if hasattr(_RUN_LOOPS, 'loop'): - return ctypes.cast(_RUN_LOOPS.loop, ctypes.py_object).value + return _RUN_LOOPS.loop() return None
diff --git a/third_party/mojo/src/mojo/public/python/rules.gni b/third_party/mojo/src/mojo/public/python/rules.gni index 934a94e5..2c1fab11 100644 --- a/third_party/mojo/src/mojo/public/python/rules.gni +++ b/third_party/mojo/src/mojo/public/python/rules.gni
@@ -62,6 +62,12 @@ mojo_output = "$root_out_dir/" + target_name + ".mojo" } + if (defined(invoker.debug) && invoker.debug) { + content_handler_param = "?debug=true" + } else { + content_handler_param = "" + } + python_package(package_name) { sources = invoker.sources if (defined(invoker.deps)) { @@ -106,7 +112,7 @@ args = [ "--input=$rebase_input", "--output=$rebase_output", - "--line=#!mojo mojo:py_content_handler", + "--line=#!mojo mojo:py_content_handler${content_handler_param}", ] } }
diff --git a/third_party/mojo/src/mojo/public/python/src/common.cc b/third_party/mojo/src/mojo/public/python/src/common.cc index e2a832ab..d14d718c 100644 --- a/third_party/mojo/src/mojo/public/python/src/common.cc +++ b/third_party/mojo/src/mojo/public/python/src/common.cc
@@ -41,7 +41,12 @@ ScopedPyRef::ScopedPyRef(PyObject* object, ScopedPyRefAcquire) : object_(object) { - Py_XINCREF(object_); + if (object_) + Py_XINCREF(object_); +} + +ScopedPyRef::ScopedPyRef(const ScopedPyRef& other) + : ScopedPyRef(other, kAcquire) { } PyObject* ScopedPyRef::Release() { @@ -57,8 +62,14 @@ } } -ScopedPyRef::operator PyObject*() const { - return object_; +ScopedPyRef& ScopedPyRef::operator=(const ScopedPyRef& other) { + if (other) + Py_XINCREF(other); + PyObject* old = object_; + object_ = other; + if (old) + Py_DECREF(old); + return *this; } PythonClosure::PythonClosure(PyObject* callable, const mojo::Closure& quit)
diff --git a/third_party/mojo/src/mojo/public/python/src/common.h b/third_party/mojo/src/mojo/public/python/src/common.h index 4eae72e5..2ada2a4 100644 --- a/third_party/mojo/src/mojo/public/python/src/common.h +++ b/third_party/mojo/src/mojo/public/python/src/common.h
@@ -37,18 +37,19 @@ public: explicit ScopedPyRef(PyObject* object); ScopedPyRef(PyObject* object, ScopedPyRefAcquire); + ScopedPyRef(const ScopedPyRef& other); ~ScopedPyRef(); // Releases ownership of the python object contained by this instance. PyObject* Release(); - operator PyObject*() const; + operator PyObject*() const { return object_; } + + ScopedPyRef& operator=(const ScopedPyRef& other); private: PyObject* object_; - - MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedPyRef); };
diff --git a/third_party/mojo/src/mojo/public/tools/BUILD.gn b/third_party/mojo/src/mojo/public/tools/BUILD.gn index 103c259..e03d1d31 100644 --- a/third_party/mojo/src/mojo/public/tools/BUILD.gn +++ b/third_party/mojo/src/mojo/public/tools/BUILD.gn
@@ -2,28 +2,64 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/module_args/mojo.gni") import("../mojo.gni") if (use_prebuilt_mojo_shell) { copy("copy_mojo_shell") { filename = "mojo_shell" - if (is_win) { - filename += ".exe" - } if (is_android) { filename = "MojoShell.apk" - } - sources = [ - "prebuilt/$filename", - ] - if (is_android) { + sources = [ + "prebuilt/shell/android-arm/$filename", + ] outputs = [ "$root_out_dir/apks/$filename", ] } else { + assert(is_linux) + sources = [ + "prebuilt/shell/linux-x64/$filename", + ] outputs = [ "$root_out_dir/$filename", ] } } } + +if (use_prebuilt_network_service) { + copy("copy_network_service") { + filename = "network_service.mojo" + if (is_android) { + sources = [ + "prebuilt/network_service/android-arm/$filename", + ] + } else { + assert(is_linux) + sources = [ + "prebuilt/network_service/linux-x64/$filename", + ] + } + outputs = [ + "$root_out_dir/$filename", + ] + } + + copy("copy_network_service_apptests") { + filename = "network_service_apptests.mojo" + if (is_android) { + sources = [ + "prebuilt/network_service_apptests/android-arm/$filename", + ] + } else { + assert(is_linux) + sources = [ + "prebuilt/network_service_apptests/linux-x64/$filename", + ] + } + outputs = [ + "$root_out_dir/$filename", + ] + } +}
diff --git a/third_party/mojo/src/mojo/public/tools/NETWORK_SERVICE_VERSION b/third_party/mojo/src/mojo/public/tools/NETWORK_SERVICE_VERSION new file mode 100644 index 0000000..597e852 --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/NETWORK_SERVICE_VERSION
@@ -0,0 +1 @@ +bf9a4b53049b10cfdd85934075ed3e147be889f5 \ No newline at end of file
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl index 25c01bb..2c21d0d 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
@@ -6,9 +6,6 @@ {%- if interface|has_callbacks %} class {{interface.name}}ResponseValidator; {%- endif %} -{% if interface.client %} -class {{interface.client}}; -{% endif %} class {{interface.name}} { public: @@ -23,11 +20,6 @@ {%- else %} using ResponseValidator_ = mojo::PassThroughFilter; {%- endif %} -{% if interface.client %} - using Client = {{interface.client}}; -{% else %} - using Client = mojo::NoInterface; -{% endif %} {#--- Constants #} {%- for constant in interface.constants %}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl index 2b45808..308c8b6 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -1,90 +1,29 @@ {%- import "interface_macros.tmpl" as interface_macros %} +{%- import "struct_macros.tmpl" as struct_macros %} {%- set class_name = interface.name %} {%- set proxy_name = interface.name ~ "Proxy" %} {%- set namespace_as_string = "%s"|format(namespace|replace(".","::")) %} -{%- macro alloc_params(parameters) %} -{%- for param in parameters %} -{%- if param.kind|is_object_kind %} -{{param.kind|cpp_result_type}} p{{loop.index}}; -Deserialize_(params->{{param.name}}.ptr, &p{{loop.index}}); -{% endif -%} +{%- macro alloc_params(struct) %} +{%- for param in struct.packed.packed_fields_in_ordinal_order %} + {{param.field.kind|cpp_result_type}} p_{{param.field.name}}{}; {%- endfor %} + {{struct_macros.deserialize(struct, "params", "p_%s")}} {%- endmacro %} {%- macro pass_params(parameters) %} {%- for param in parameters %} -{%- if param.kind|is_string_kind -%} -p{{loop.index}} -{%- elif param.kind|is_object_kind -%} -p{{loop.index}}.Pass() -{%- elif param.kind|is_interface_kind -%} -mojo::MakeProxy<{{param.kind|get_name_for_kind}}>(mojo::MakeScopedHandle(mojo::internal::FetchAndReset(¶ms->{{param.name}}))) -{%- elif param.kind|is_interface_request_kind -%} -mojo::MakeRequest<{{param.kind.kind|get_name_for_kind}}>(mojo::MakeScopedHandle(mojo::internal::FetchAndReset(¶ms->{{param.name}}))) -{%- elif param.kind|is_any_handle_kind -%} -mojo::MakeScopedHandle(mojo::internal::FetchAndReset(¶ms->{{param.name}})) -{%- elif param.kind|is_enum_kind -%} -static_cast<{{param.kind|cpp_wrapper_type}}>(params->{{param.name}}) +{%- if param.kind|is_move_only_kind -%} +p_{{param.name}}.Pass() {%- else -%} -params->{{param.name}} +p_{{param.name}} {%- endif -%} {%- if not loop.last %}, {% endif %} {%- endfor %} {%- endmacro %} -{%- macro compute_payload_size(params_name, parameters) -%} - size_t payload_size = - mojo::internal::Align(sizeof({{params_name}})); -{#--- Computes #} -{%- for param in parameters %} -{%- if param.kind|is_object_kind %} - payload_size += GetSerializedSize_(in_{{param.name}}); -{%- endif %} -{%- endfor %} -{%- endmacro %} - -{%- macro build_message(params_name, parameters, params_description) -%} - {# TODO(yzshen): Consider refactoring to share code with - struct_serialization_definition.tmpl #} - {{params_name}}* params = - {{params_name}}::New(builder.buffer()); -{#--- Sets #} -{% for param in parameters %} -{%- if param.kind|is_object_kind %} -{%- if param.kind|is_array_kind %} - mojo::SerializeArray_<{{param.kind|get_array_validate_params|indent(24)}}>( - mojo::internal::Forward(in_{{param.name}}), builder.buffer(), ¶ms->{{param.name}}.ptr); -{%- elif param.kind|is_map_kind %} - mojo::SerializeMap_<{{param.kind.value_kind|get_map_validate_params|indent(24)}}>( - mojo::internal::Forward(in_{{param.name}}), builder.buffer(), ¶ms->{{param.name}}.ptr); -{%- else %} - Serialize_(mojo::internal::Forward(in_{{param.name}}), builder.buffer(), ¶ms->{{param.name}}.ptr); -{%- endif %} -{%- if not param.kind|is_nullable_kind %} - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - !params->{{param.name}}.ptr, - mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, - "null {{param.name}} argument in {{params_description}}"); -{%- endif %} -{%- elif param.kind|is_any_handle_kind %} -{%- if param.kind|is_interface_kind or - param.kind|is_interface_request_kind %} - // Delegate handle. - params->{{param.name}} = in_{{param.name}}.PassMessagePipe().release(); -{%- else %} - params->{{param.name}} = in_{{param.name}}.release(); -{%- endif %} -{%- if not param.kind|is_nullable_kind %} - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - !params->{{param.name}}.is_valid(), - mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, - "invalid {{param.name}} argument in {{params_description}}"); -{%- endif %} -{%- else %} - params->{{param.name}} = in_{{param.name}}; -{%- endif %} -{%- endfor %} +{%- macro build_message(struct, struct_display_name) -%} + {{struct_macros.serialize(struct, struct_display_name, "in_%s", "params", "builder.buffer()")}} mojo::Message message; params->EncodePointersAndHandles(message.mutable_handles()); builder.Finish(&message); @@ -119,7 +58,7 @@ message->mutable_payload()); params->DecodePointersAndHandles(message->mutable_handles()); - {{alloc_params(method.response_parameters)|indent(2)}} + {{alloc_params(method|response_struct_from_method)}} callback_.Run({{pass_params(method.response_parameters)}}); return true; } @@ -135,21 +74,20 @@ {%- for method in interface.methods %} {%- set message_name = "internal::k%s_%s_Name"|format(interface.name, method.name) %} -{%- set params_name = - "internal::%s_%s_Params_Data"|format(interface.name, method.name) %} +{%- set params_struct = method|struct_from_method %} {%- set params_description = "%s.%s request"|format(interface.name, method.name) %} void {{proxy_name}}::{{method.name}}( {{interface_macros.declare_request_params("in_", method)}}) { - {{compute_payload_size(params_name, method.parameters)}} + {{struct_macros.get_serialized_size(params_struct, "in_%s")}} {%- if method.response_parameters != None %} - mojo::internal::RequestMessageBuilder builder({{message_name}}, payload_size); + mojo::internal::RequestMessageBuilder builder({{message_name}}, size); {%- else %} - mojo::internal::MessageBuilder builder({{message_name}}, payload_size); + mojo::internal::MessageBuilder builder({{message_name}}, size); {%- endif %} - {{build_message(params_name, method.parameters, params_description)}} + {{build_message(params_struct, params_description)}} {%- if method.response_parameters != None %} mojo::MessageReceiver* responder = @@ -170,8 +108,7 @@ {%- if method.response_parameters != None %} {%- set message_name = "internal::k%s_%s_Name"|format(interface.name, method.name) %} -{%- set params_name = - "internal::%s_%s_ResponseParams_Data"|format(interface.name, method.name) %} +{%- set response_params_struct = method|response_struct_from_method %} {%- set params_description = "%s.%s response"|format(interface.name, method.name) %} class {{class_name}}_{{method.name}}_ProxyToResponder @@ -197,10 +134,10 @@ }; void {{class_name}}_{{method.name}}_ProxyToResponder::Run( {{interface_macros.declare_params("in_", method.response_parameters)}}) const { - {{compute_payload_size(params_name, method.response_parameters)}} + {{struct_macros.get_serialized_size(response_params_struct, "in_%s")}} mojo::internal::ResponseMessageBuilder builder( - {{message_name}}, payload_size, request_id_); - {{build_message(params_name, method.response_parameters, params_description)}} + {{message_name}}, size, request_id_); + {{build_message(response_params_struct, params_description)}} bool ok = responder_->Accept(&message); MOJO_ALLOW_UNUSED_LOCAL(ok); // TODO(darin): !ok returned here indicates a malformed message, and that may @@ -229,9 +166,8 @@ message->mutable_payload()); params->DecodePointersAndHandles(message->mutable_handles()); - {{alloc_params(method.parameters)|indent(6)}} - // A null |sink_| typically means there is a missing call to - // InterfacePtr::set_client(). + {{alloc_params(method|struct_from_method)|indent(4)}} + // A null |sink_| means no implementation was bound. assert(sink_); sink_->{{method.name}}({{pass_params(method.parameters)}}); return true; @@ -261,9 +197,8 @@ new {{class_name}}_{{method.name}}_ProxyToResponder( message->request_id(), responder); {{class_name}}::{{method.name}}Callback callback(runnable); - {{alloc_params(method.parameters)|indent(6)}} - // A null |sink_| typically means there is a missing call to - // InterfacePtr::set_client(). + {{alloc_params(method|struct_from_method)|indent(4)}} + // A null |sink_| means no implementation was bound. assert(sink_); sink_->{{method.name}}( {%- if method.parameters -%}{{pass_params(method.parameters)}}, {% endif -%}callback); @@ -311,8 +246,6 @@ } {%- endif %} - // A null |sink_| typically means there is a missing call to - // InterfacePtr::set_client(). assert(sink_); return sink_->Accept(message); } @@ -343,8 +276,6 @@ } {%- endif %} - // A null |sink_| typically means there is a missing call to - // InterfacePtr::set_client(). assert(sink_); return sink_->Accept(message); }
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl index 863d18fe..969bea2 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
@@ -47,10 +47,12 @@ {%- set method_name = "k%s_%s_Name"|format(interface.name, method.name) %} const uint32_t {{method_name}} = {{method.ordinal}}; {% set struct = method|struct_from_method %} -{%- include "params_definition.tmpl" %} +{% include "struct_declaration.tmpl" %} +{%- include "struct_definition.tmpl" %} {%- if method.response_parameters != None %} {%- set struct = method|response_struct_from_method %} -{%- include "params_definition.tmpl" %} +{% include "struct_declaration.tmpl" %} +{%- include "struct_definition.tmpl" %} {%- endif %} {%- endfor %} {%- endfor %}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl deleted file mode 100644 index 0892b64..0000000 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl +++ /dev/null
@@ -1,33 +0,0 @@ -{%- import "struct_macros.tmpl" as struct_macros %} -{%- set class_name = struct.name ~ "_Data" %} -class {{class_name}} { - public: - static {{class_name}}* New(mojo::internal::Buffer* buf) { - return new (buf->Allocate(sizeof({{class_name}}))) - {{class_name}}(); - } - - static bool Validate(const void* data, - mojo::internal::BoundsChecker* bounds_checker) { - {{ struct_macros.validate(struct, class_name)|indent(4) }} - } - - mojo::internal::StructHeader header_; -{{struct_macros.fields(struct)}} - - void EncodePointersAndHandles(std::vector<mojo::Handle>* handles) { - {{ struct_macros.encodes(struct)|indent(4) }} - } - - void DecodePointersAndHandles(std::vector<mojo::Handle>* handles) { - {{ struct_macros.decodes(struct)|indent(4) }} - } - - private: - {{class_name}}() { - header_.num_bytes = sizeof(*this); - header_.num_fields = {{struct.packed.packed_fields|length}}; - } -}; -static_assert(sizeof({{class_name}}) == {{struct.versions[-1].num_bytes}}, - "Bad sizeof({{class_name}})");
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl index ee8934e2..255005ad 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl
@@ -1,4 +1,3 @@ -{%- import "struct_macros.tmpl" as struct_macros %} {%- set class_name = struct.name ~ "_Data" -%} class {{class_name}} { @@ -8,12 +7,39 @@ static bool Validate(const void* data, mojo::internal::BoundsChecker* bounds_checker); - mojo::internal::StructHeader header_; -{{struct_macros.fields(struct)}} - void EncodePointersAndHandles(std::vector<mojo::Handle>* handles); void DecodePointersAndHandles(std::vector<mojo::Handle>* handles); + mojo::internal::StructHeader header_; +{%- for packed_field in struct.packed.packed_fields %} +{%- set name = packed_field.field.name %} +{%- set kind = packed_field.field.kind %} +{%- if kind.spec == 'b' %} + uint8_t {{name}} : 1; +{%- elif kind|is_enum_kind %} + int32_t {{name}}; +{%- else %} + {{kind|cpp_field_type}} {{name}}; +{%- endif %} +{%- if not loop.last %} +{%- set next_pf = struct.packed.packed_fields[loop.index0 + 1] %} +{%- set pad = next_pf.offset - (packed_field.offset + packed_field.size) %} +{%- if pad > 0 %} + uint8_t pad{{loop.index0}}_[{{pad}}]; +{%- endif %} +{%- endif %} +{%- endfor %} + +{%- set num_fields = struct.versions[-1].num_fields %} +{%- if num_fields > 0 %} +{%- set last_field = struct.packed.packed_fields[num_fields - 1] %} +{%- set offset = last_field.offset + last_field.size %} +{%- set pad = offset|get_pad(8) %} +{%- if pad > 0 %} + uint8_t padfinal_[{{pad}}]; +{%- endif %} +{%- endif %} + private: {{class_name}}(); ~{{class_name}}() = delete;
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl index 461f1586..79a0bc4 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl
@@ -1,6 +1,69 @@ -{%- import "struct_macros.tmpl" as struct_macros %} {%- set class_name = struct.name ~ "_Data" %} +{#- TODO(yzshen): Consider eliminating _validate_object() and + _validate_handle(). #} + +{#- Validates the specified struct field, which is supposed to be an object + (struct/array/string/map/union). + This macro is expanded by the Validate() method. #} +{%- macro _validate_object(struct, packed_field) %} +{%- set name = packed_field.field.name %} +{%- set kind = packed_field.field.kind %} +{%- set wrapper_type = kind|cpp_wrapper_type %} +{%- if not kind|is_nullable_kind %} + if (!object->{{name}}.offset) { + ReportValidationError( + mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, + "null {{name}} field in {{struct.name}} struct"); + return false; + } +{%- endif %} + if (!mojo::internal::ValidateEncodedPointer(&object->{{name}}.offset)) { + ReportValidationError(mojo::internal::VALIDATION_ERROR_ILLEGAL_POINTER); + return false; + } +{%- if kind|is_array_kind or kind|is_string_kind %} + if (!{{wrapper_type}}::Data_::Validate< + {{kind|get_array_validate_params|indent(10)}}>( + mojo::internal::DecodePointerRaw(&object->{{name}}.offset), + bounds_checker)) { +{%- elif kind|is_map_kind %} + if (!{{wrapper_type}}::Data_::Validate< + {{kind.value_kind|get_map_validate_params|indent(10)}}>( + mojo::internal::DecodePointerRaw(&object->{{name}}.offset), + bounds_checker)) { +{%- elif kind|is_struct_kind %} + if (!{{kind|get_name_for_kind}}::Data_::Validate( + mojo::internal::DecodePointerRaw(&object->{{name}}.offset), + bounds_checker)) { +{%- else %} + if (!{{wrapper_type}}::Data_::Validate( + mojo::internal::DecodePointerRaw(&object->{{name}}.offset), + bounds_checker)) { +{%- endif %} + return false; + } +{%- endmacro %} + +{#- Validates the specified struct field, which is supposed to be a handle. + This macro is expanded by the Validate() method. #} +{%- macro _validate_handle(struct, packed_field) %} +{%- set name = packed_field.field.name %} +{%- set kind = packed_field.field.kind %} +{%- if not kind|is_nullable_kind %} + if (object->{{name}}.value() == mojo::internal::kEncodedInvalidHandleValue) { + ReportValidationError( + mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, + "invalid {{name}} field in {{struct.name}} struct"); + return false; + } +{%- endif %} + if (!bounds_checker->ClaimHandle(object->{{name}})) { + ReportValidationError(mojo::internal::VALIDATION_ERROR_ILLEGAL_HANDLE); + return false; + } +{%- endmacro %} + // static {{class_name}}* {{class_name}}::New(mojo::internal::Buffer* buf) { return new (buf->Allocate(sizeof({{class_name}}))) {{class_name}}(); @@ -9,20 +72,109 @@ // static bool {{class_name}}::Validate(const void* data, mojo::internal::BoundsChecker* bounds_checker) { - {{ struct_macros.validate(struct, class_name)|indent(2) }} -} + if (!data) + return true; -{{class_name}}::{{class_name}}() { - header_.num_bytes = sizeof(*this); - header_.num_fields = {{struct.packed.packed_fields|length}}; + if (!ValidateStructHeaderAndClaimMemory(data, bounds_checker)) + return false; + + // NOTE: The memory backing |object| may be smaller than |sizeof(*object)| if + // the message comes from an older version. + const {{class_name}}* object = static_cast<const {{class_name}}*>(data); + + static const struct { + uint32_t version; + uint32_t num_bytes; + } kVersionSizes[] = { +{%- for version in struct.versions -%} + { {{version.version}}, {{version.num_bytes}} }{% if not loop.last %}, {% endif -%} +{%- endfor -%} + }; + + if (object->header_.version <= + kVersionSizes[MOJO_ARRAYSIZE(kVersionSizes) - 1].version) { + // Scan in reverse order to optimize for more recent versions. + for (int i = MOJO_ARRAYSIZE(kVersionSizes) - 1; i >= 0; --i) { + if (object->header_.version >= kVersionSizes[i].version) { + if (object->header_.num_bytes == kVersionSizes[i].num_bytes) + break; + + ReportValidationError( + mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + } + } else if (object->header_.num_bytes < + kVersionSizes[MOJO_ARRAYSIZE(kVersionSizes) - 1].num_bytes) { + ReportValidationError( + mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + +{#- Before validating fields introduced at a certain version, we need to add + a version check, which makes sure we skip further validation if |object| + is from an earlier version. |last_checked_version| records the last + version that we have added such version check. #} +{%- set last_checked_version = 0 %} +{%- for packed_field in struct.packed.packed_fields_in_ordinal_order %} +{%- set kind = packed_field.field.kind %} +{%- if kind|is_object_kind or kind|is_any_handle_kind %} +{%- if packed_field.min_version > last_checked_version %} +{%- set last_checked_version = packed_field.min_version %} + if (object->header_.version < {{packed_field.min_version}}) + return true; +{%- endif %} +{%- if kind|is_object_kind %} +{{_validate_object(struct, packed_field)}} +{%- elif kind|is_any_handle_kind %} +{{_validate_handle(struct, packed_field)}} +{%- endif %} +{%- endif %} +{%- endfor %} + + return true; } void {{class_name}}::EncodePointersAndHandles( std::vector<mojo::Handle>* handles) { - {{ struct_macros.encodes(struct)|indent(2) }} + MOJO_CHECK(header_.version == {{struct.versions[-1].version}}); +{%- for pf in struct.packed.packed_fields_in_ordinal_order %} +{%- if pf.field.kind|is_object_kind %} + mojo::internal::Encode(&{{pf.field.name}}, handles); +{%- elif pf.field.kind|is_any_handle_kind %} + mojo::internal::EncodeHandle(&{{pf.field.name}}, handles); +{%- endif %} +{%- endfor %} } void {{class_name}}::DecodePointersAndHandles( std::vector<mojo::Handle>* handles) { - {{ struct_macros.decodes(struct)|indent(2) }} + // NOTE: The memory backing |this| may has be smaller than |sizeof(*this)|, if + // the message comes from an older version. +{#- Before decoding fields introduced at a certain version, we need to add + a version check, which makes sure we skip further decoding if |this| + is from an earlier version. |last_checked_version| records the last + version that we have added such version check. #} +{%- set last_checked_version = 0 %} +{%- for pf in struct.packed.packed_fields_in_ordinal_order %} +{%- set name = pf.field.name %} +{%- set kind = pf.field.kind %} +{%- if kind|is_object_kind or kind|is_any_handle_kind %} +{%- if pf.min_version > last_checked_version %} +{%- set last_checked_version = pf.min_version %} + if (header_.version < {{pf.min_version}}) + return; +{%- endif %} +{%- if kind|is_object_kind %} + mojo::internal::Decode(&{{name}}, handles); +{%- else %} + mojo::internal::DecodeHandle(&{{name}}, handles); +{%- endif %} +{%- endif %} +{%- endfor %} +} + +{{class_name}}::{{class_name}}() { + header_.num_bytes = sizeof(*this); + header_.version = {{struct.versions[-1].version}}; }
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl index 623ebb4..03911b9b 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
@@ -1,124 +1,118 @@ -{%- macro validate(struct, class_name) %} - if (!data) - return true; +{# TODO(yzshen): Make these templates more readable. #} - if (!ValidateStructHeader( - data, sizeof({{class_name}}), - {{struct.packed.packed_fields|length}}, bounds_checker)) { - return false; - } +{# Computes the serialized size for the specified struct. + |struct| is the struct definition. + |input_field_pattern| should be a pattern that contains one string + placeholder, for example, "input->%s", "p_%s". The placeholder will be + substituted with struct field names to refer to the input fields. + This macro is expanded to compute seriailized size for both: + - user-defined structs: the input is an instance of the corresponding struct + wrapper class. + - method parameters/response parameters: the input is a list of + arguments. + It declares |size| of type size_t to store the resulting size. #} +{%- macro get_serialized_size(struct, input_field_pattern) -%} + size_t size = sizeof(internal::{{struct.name}}_Data); +{%- for pf in struct.packed.packed_fields_in_ordinal_order if pf.field.kind|is_object_kind %} + size += GetSerializedSize_({{input_field_pattern|format(pf.field.name)}}); +{%- endfor %} +{%- endmacro -%} - const {{class_name}}* object = static_cast<const {{class_name}}*>(data); - MOJO_ALLOW_UNUSED_LOCAL(object); +{# Serializes the specified struct. + |struct| is the struct definition. + |struct_display_name| is the display name for the struct that can be showed + in error/log messages, for example, "FooStruct", "FooMethod request". + |input_field_pattern| should be a pattern that contains one string + placeholder, for example, "input->%s", "p_%s". The placeholder will be + substituted with struct field names to refer to the input fields. + |output| is the name of the output struct instance. + |buffer| is the name of the Buffer instance used. + This macro is expanded to do serialization for both: + - user-defined structs: the input is an instance of the corresponding struct + wrapper class. + - method parameters/response parameters: the input is a list of + arguments. #} +{%- macro serialize(struct, struct_display_name, input_field_pattern, output, buffer) -%} + internal::{{struct.name}}_Data* {{output}} = + internal::{{struct.name}}_Data::New({{buffer}}); +{%- for pf in struct.packed.packed_fields_in_ordinal_order %} +{%- set input_field = input_field_pattern|format(pf.field.name) %} +{%- set name = pf.field.name %} +{%- set kind = pf.field.kind %} +{%- if kind|is_object_kind %} +{%- if kind|is_array_kind %} + mojo::SerializeArray_<{{kind|get_array_validate_params|indent(24)}}>( + mojo::internal::Forward({{input_field}}), {{buffer}}, &{{output}}->{{name}}.ptr); +{%- elif kind|is_map_kind %} + mojo::SerializeMap_<{{kind.value_kind|get_map_validate_params|indent(24)}}>( + mojo::internal::Forward({{input_field}}), {{buffer}}, &{{output}}->{{name}}.ptr); +{%- else %} + Serialize_(mojo::internal::Forward({{input_field}}), {{buffer}}, &{{output}}->{{name}}.ptr); +{%- endif %} +{%- if not kind|is_nullable_kind %} + MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( + !{{output}}->{{name}}.ptr, + mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, + "null {{name}} in {{struct_display_name}}"); +{%- endif %} +{%- elif kind|is_any_handle_kind %} +{%- if kind|is_interface_kind or kind|is_interface_request_kind %} + {{output}}->{{name}} = {{input_field}}.PassMessagePipe().release(); +{%- else %} + {{output}}->{{name}} = {{input_field}}.release(); +{%- endif %} +{%- if not kind|is_nullable_kind %} + MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( + !{{output}}->{{name}}.is_valid(), + mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, + "invalid {{name}} in {{struct_display_name}}"); +{%- endif %} +{%- else %} + {{output}}->{{name}} = {{input_field}}; +{%- endif %} +{%- endfor %} +{%- endmacro -%} -{%- for packed_field in struct.packed.packed_fields %} -{%- set name = packed_field.field.name %} -{%- set kind = packed_field.field.kind %} +{# Deserializes the specified struct. + |struct| is the struct definition. + |input| is the name of the input struct instance. + |output_field_pattern| should be a pattern that contains one string + placeholder, for example, "result->%s", "p_%s". The placeholder will be + substituted with struct field names to refer to the output fields. + This macro is expanded to do deserialization for both: + - user-defined structs: the output is an instance of the corresponding + struct wrapper class. + - method parameters/response parameters: the output is a list of + arguments. #} +{%- macro deserialize(struct, input, output_field_pattern) -%} + do { + // NOTE: The memory backing |{{input}}| may has be smaller than + // |sizeof(*{{input}})| if the message comes from an older version. +{#- Before deserialize fields introduced at a certain version, we need to add + a version check, which makes sure we skip further deserialization if + |input| is from an earlier version. |last_checked_version| records the + last version that we have added such version check. #} +{%- set last_checked_version = 0 %} +{%- for pf in struct.packed.packed_fields_in_ordinal_order %} +{%- set output_field = output_field_pattern|format(pf.field.name) %} +{%- set name = pf.field.name %} +{%- set kind = pf.field.kind %} +{%- if pf.min_version > last_checked_version %} +{%- set last_checked_version = pf.min_version %} + if ({{input}}->header_.version < {{pf.min_version}}) + break; +{%- endif %} {%- if kind|is_object_kind %} -{%- set wrapper_type = kind|cpp_wrapper_type %} -{%- if not kind|is_nullable_kind %} - if (!object->{{name}}.offset) { - ReportValidationError( - mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, - "null {{name}} field in {{struct.name}} struct"); - return false; - } -{%- endif %} - if (!mojo::internal::ValidateEncodedPointer(&object->{{name}}.offset)) { - ReportValidationError(mojo::internal::VALIDATION_ERROR_ILLEGAL_POINTER); - return false; - } -{%- if kind|is_array_kind or kind|is_string_kind %} - if (!{{wrapper_type}}::Data_::Validate< - {{kind|get_array_validate_params|indent(10)}}>( - mojo::internal::DecodePointerRaw(&object->{{name}}.offset), - bounds_checker)) { -{%- elif kind|is_map_kind %} - if (!{{wrapper_type}}::Data_::Validate< - {{kind.value_kind|get_map_validate_params|indent(10)}}>( - mojo::internal::DecodePointerRaw(&object->{{name}}.offset), - bounds_checker)) { -{%- elif kind|is_struct_kind %} - if (!{{kind|get_name_for_kind}}::Data_::Validate( - mojo::internal::DecodePointerRaw(&object->{{name}}.offset), - bounds_checker)) { -{%- else %} - if (!{{wrapper_type}}::Data_::Validate( - mojo::internal::DecodePointerRaw(&object->{{name}}.offset), - bounds_checker)) { -{%- endif %} - return false; - } + Deserialize_({{input}}->{{name}}.ptr, &{{output_field}}); +{%- elif kind|is_interface_kind or kind|is_interface_request_kind %} + {{output_field}}.Bind(mojo::MakeScopedHandle(mojo::internal::FetchAndReset(&{{input}}->{{name}}))); {%- elif kind|is_any_handle_kind %} -{%- if not kind|is_nullable_kind %} - if (object->{{name}}.value() == mojo::internal::kEncodedInvalidHandleValue) { - ReportValidationError( - mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, - "invalid {{name}} field in {{struct.name}} struct"); - return false; - } -{%- endif %} - if (!bounds_checker->ClaimHandle(object->{{name}})) { - ReportValidationError(mojo::internal::VALIDATION_ERROR_ILLEGAL_HANDLE); - return false; - } + {{output_field}}.reset(mojo::internal::FetchAndReset(&{{input}}->{{name}})); +{%- elif kind|is_enum_kind %} + {{output_field}} = static_cast<{{kind|cpp_wrapper_type}}>({{input}}->{{name}}); +{%- else %} + {{output_field}} = {{input}}->{{name}}; {%- endif %} {%- endfor %} - - return true; + } while (false); {%- endmacro %} - -{%- macro field_line(field) %} -{%- set type = field.kind|cpp_field_type %} -{%- set name = field.name -%} -{%- if field.kind.spec == 'b' -%} - uint8_t {{name}} : 1; -{%- elif field.kind|is_enum_kind -%} - int32_t {{name}}; -{%- else -%} - {{type}} {{name}}; -{%- endif %} -{%- endmacro %} - -{%- macro fields(struct) %} -{%- for packed_field in struct.packed.packed_fields %} - {{field_line(packed_field.field)}} -{%- if not loop.last %} -{%- set next_pf = struct.packed.packed_fields[loop.index0 + 1] %} -{%- set pad = next_pf.offset - (packed_field.offset + packed_field.size) %} -{%- if pad > 0 %} - uint8_t pad{{loop.index0}}_[{{pad}}]; -{%- endif %} -{%- endif %} -{%- endfor -%} - -{%- set num_fields = struct.packed.packed_fields|length %} -{%- if num_fields > 0 %} -{%- set last_field = struct.packed.packed_fields[num_fields - 1] %} -{%- set offset = last_field.offset + last_field.size %} -{%- set pad = offset|get_pad(8) -%} -{%- if pad > 0 %} - uint8_t padfinal_[{{pad}}]; -{%- endif %} -{%- endif %} -{%- endmacro %} - -{%- macro encodes(struct) -%} -{%- for pf in struct.packed.packed_fields %} -{%- if pf.field.kind|is_object_kind %} -mojo::internal::Encode(&{{pf.field.name}}, handles); -{%- elif pf.field.kind|is_any_handle_kind %} -mojo::internal::EncodeHandle(&{{pf.field.name}}, handles); -{%- endif %} -{%- endfor %} -{%- endmacro -%} - -{%- macro decodes(struct) -%} -{%- for pf in struct.packed.packed_fields %} -{%- if pf.field.kind|is_object_kind %} -mojo::internal::Decode(&{{pf.field.name}}, handles); -{%- elif pf.field.kind|is_any_handle_kind %} -mojo::internal::DecodeHandle(&{{pf.field.name}}, handles); -{%- endif %} -{%- endfor %} -{%- endmacro -%}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl index 1612bbec..fe25553 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl
@@ -1,51 +1,15 @@ +{%- import "struct_macros.tmpl" as struct_macros %} size_t GetSerializedSize_(const {{struct.name}}Ptr& input) { if (!input) return 0; - size_t size = sizeof(internal::{{struct.name}}_Data); -{%- for pf in struct.packed.packed_fields if pf.field.kind|is_object_kind %} - size += GetSerializedSize_(input->{{pf.field.name}}); -{%- endfor %} + {{struct_macros.get_serialized_size(struct, "input->%s")}} return size; } void Serialize_({{struct.name}}Ptr input, mojo::internal::Buffer* buf, internal::{{struct.name}}_Data** output) { if (input) { - internal::{{struct.name}}_Data* result = - internal::{{struct.name}}_Data::New(buf); -{%- for pf in struct.packed.packed_fields %} -{%- if pf.field.kind|is_object_kind %} -{%- if pf.field.kind|is_array_kind %} - mojo::SerializeArray_<{{pf.field.kind|get_array_validate_params|indent(26)}}>( - mojo::internal::Forward(input->{{pf.field.name}}), buf, &result->{{pf.field.name}}.ptr); -{%- elif pf.field.kind|is_map_kind %} - mojo::SerializeMap_<{{pf.field.kind.value_kind|get_map_validate_params|indent(26)}}>( - mojo::internal::Forward(input->{{pf.field.name}}), buf, &result->{{pf.field.name}}.ptr); -{%- else %} - Serialize_(mojo::internal::Forward(input->{{pf.field.name}}), buf, &result->{{pf.field.name}}.ptr); -{%- endif %} -{%- if not pf.field.kind|is_nullable_kind %} - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - !result->{{pf.field.name}}.ptr, - mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, - "null {{pf.field.name}} field in {{struct.name}} struct"); -{%- endif %} -{%- elif pf.field.kind|is_any_handle_kind %} -{%- if pf.field.kind|is_interface_kind %} - result->{{pf.field.name}} = input->{{pf.field.name}}.PassMessagePipe().release(); -{%- else %} - result->{{pf.field.name}} = input->{{pf.field.name}}.release(); -{%- endif %} -{%- if not pf.field.kind|is_nullable_kind %} - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - !result->{{pf.field.name}}.is_valid(), - mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, - "invalid {{pf.field.name}} field in {{struct.name}} struct"); -{%- endif %} -{%- else %} - result->{{pf.field.name}} = input->{{pf.field.name}}; -{%- endif %} -{%- endfor %} + {{struct_macros.serialize(struct, struct.name ~ " struct", "input->%s", "result", "buf")|indent(2)}} *output = result; } else { *output = nullptr; @@ -56,21 +20,7 @@ {{struct.name}}Ptr* output) { if (input) { {{struct.name}}Ptr result({{struct.name}}::New()); -{%- for pf in struct.packed.packed_fields %} -{%- if pf.field.kind|is_object_kind %} - Deserialize_(input->{{pf.field.name}}.ptr, &result->{{pf.field.name}}); -{%- elif pf.field.kind|is_interface_kind %} - if (input->{{pf.field.name}}.is_valid()) - result->{{pf.field.name}}.Bind(mojo::MakeScopedHandle(mojo::internal::FetchAndReset(&input->{{pf.field.name}}))); -{%- elif pf.field.kind|is_any_handle_kind %} - result->{{pf.field.name}}.reset(mojo::internal::FetchAndReset(&input->{{pf.field.name}})); -{%- elif pf.field.kind|is_enum_kind %} - result->{{pf.field.name}} = static_cast<{{pf.field.kind|cpp_wrapper_type}}>( - input->{{pf.field.name}}); -{%- else %} - result->{{pf.field.name}} = input->{{pf.field.name}}; -{%- endif %} -{%- endfor %} + {{struct_macros.deserialize(struct, "input", "result->%s")|indent(2)}} *output = result.Pass(); } else { output->reset();
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl index ebcba7b..6242be4 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
@@ -32,7 +32,7 @@ {%- endif %} bool Equals(const {{struct.name}}& other) const; -{#--- Getters #} +{#--- Struct members #} {% for field in struct.fields %} {%- set type = field.kind|cpp_wrapper_type %} {%- set name = field.name %}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl index a73ad8e3..cbd39ef 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl
@@ -2,30 +2,10 @@ const int k{{interface|name}}_{{method|name}}_name = {{method.ordinal}}; {%- endfor %} -abstract class {{interface|name}} implements core.Listener { - static const String name = '{{namespace|replace(".","::")}}::{{interface|name}}'; - {{interface|name}}Stub stub; +const String {{interface|name}}Name = + '{{namespace|replace(".","::")}}::{{interface|name}}'; - {{interface|name}}(core.MojoMessagePipeEndpoint endpoint) : - stub = new {{interface|name}}Stub(endpoint); - - {{interface|name}}.fromHandle(core.MojoHandle handle) : - stub = new {{interface|name}}Stub.fromHandle(handle); - - {{interface|name}}.fromStub(this.stub); - - {{interface|name}}.unbound() : - stub = new {{interface|name}}Stub.unbound(); - - void close({bool nodefer : false}) => stub.close(nodefer: nodefer); - - StreamSubscription<int> listen() => stub.listen(); - - {{interface|name}} get delegate => stub.delegate; - set delegate({{interface|name}} d) { - stub.delegate = d; - } - +abstract class {{interface|name}} { {%- for method in interface.methods %} {%- if method.response_parameters == None %} void {{method|name}}( @@ -42,21 +22,34 @@ [Function responseFactory = null]); {%- endif %} {%- endfor %} + +{#--- Interface Constants #} +{% for constant in interface.constants %} + static final {{constant|name}} = {{constant.value|expression_to_text}}; +{%- endfor %} + +{#--- Interface Enums #} +{%- from "enum_definition.tmpl" import enum_def -%} +{%- for enum in interface.enums %} + {{ enum_def(" static ", enum) }} +{%- endfor %} } -class {{interface|name}}Proxy extends bindings.Proxy implements {{interface|name}} { - {{interface|name}}Proxy(core.MojoMessagePipeEndpoint endpoint) : super(endpoint); - {{interface|name}}Proxy.fromHandle(core.MojoHandle handle) : +class {{interface|name}}ProxyImpl extends bindings.Proxy { + {{interface|name}}ProxyImpl.fromEndpoint( + core.MojoMessagePipeEndpoint endpoint) : super(endpoint); + + {{interface|name}}ProxyImpl.fromHandle(core.MojoHandle handle) : super.fromHandle(handle); - {{interface|name}}Proxy.unbound() : super.unbound(); + {{interface|name}}ProxyImpl.unbound() : super.unbound(); - String get name => {{interface|name}}.name; - - static {{interface|name}}Proxy newFromEndpoint( + static {{interface|name}}ProxyImpl newFromEndpoint( core.MojoMessagePipeEndpoint endpoint) => - new {{interface|name}}Proxy(endpoint); + new {{interface|name}}ProxyImpl.fromEndpoint(endpoint); + + String get name => {{interface|name}}Name; void handleResponse(bindings.ServiceMessage message) { switch (message.header.type) { @@ -80,47 +73,89 @@ break; } } - -{%- for method in interface.methods %} -{%- if method.response_parameters == None %} - void {{method|name}}( -{%- for parameter in method.parameters -%} - {{parameter.kind|dart_type}} {{parameter|name}}{% if not loop.last %}, {% endif %} -{%- endfor -%} -{%- set request_struct = method|struct_from_method -%} - ) { - var params = new {{request_struct|name}}(); -{%- for parameter in method.parameters %} - params.{{parameter|name}} = {{parameter|name}}; -{%- endfor %} - sendMessage(params, k{{interface|name}}_{{method|name}}_name); - } -{% else %} -{%- set response_struct = method|response_struct_from_method %} -{%- set request_struct = method|struct_from_method %} - Future<{{response_struct|name}}> {{method|name}}( -{%- for parameter in method.parameters -%} - {{parameter.kind|dart_type}} {{parameter|name}}, -{%- endfor -%} - [Function responseFactory = null]) { - var params = new {{request_struct|name}}(); -{%- for parameter in method.parameters %} - params.{{parameter|name}} = {{parameter|name}}; -{%- endfor %} - return sendMessageWithRequestId( - params, - k{{interface|name}}_{{method|name}}_name, - -1, - bindings.MessageHeader.kMessageExpectsResponse); - } -{%- endif %} -{%- endfor %} } + +class _{{interface|name}}ProxyCalls implements {{interface|name}} { + {{interface|name}}ProxyImpl _proxyImpl; + + _{{interface|name}}ProxyCalls(this._proxyImpl); + + {%- for method in interface.methods %} + {%- if method.response_parameters == None %} + void {{method|name}}( + {%- for parameter in method.parameters -%} + {{parameter.kind|dart_type}} {{parameter|name}}{% if not loop.last %}, {% endif %} + {%- endfor -%} + {%- set request_struct = method|struct_from_method -%} + ) { + var params = new {{request_struct|name}}(); + {%- for parameter in method.parameters %} + params.{{parameter|name}} = {{parameter|name}}; + {%- endfor %} + _proxyImpl.sendMessage(params, k{{interface|name}}_{{method|name}}_name); + } + {% else %} + {%- set response_struct = method|response_struct_from_method %} + {%- set request_struct = method|struct_from_method %} + Future<{{response_struct|name}}> {{method|name}}( + {%- for parameter in method.parameters -%} + {{parameter.kind|dart_type}} {{parameter|name}}, + {%- endfor -%} + [Function responseFactory = null]) { + var params = new {{request_struct|name}}(); + {%- for parameter in method.parameters %} + params.{{parameter|name}} = {{parameter|name}}; + {%- endfor %} + return _proxyImpl.sendMessageWithRequestId( + params, + k{{interface|name}}_{{method|name}}_name, + -1, + bindings.MessageHeader.kMessageExpectsResponse); + } + {%- endif %} + {%- endfor %} +} + + +class {{interface|name}}Proxy implements bindings.ProxyBase { + final bindings.Proxy impl; + {{interface|name}} ptr; + final String name = {{interface|name}}Name; + + {{interface|name}}Proxy({{interface|name}}ProxyImpl proxyImpl) : + impl = proxyImpl, + ptr = new _{{interface|name}}ProxyCalls(proxyImpl); + + {{interface|name}}Proxy.fromEndpoint( + core.MojoMessagePipeEndpoint endpoint) : + impl = new {{interface|name}}ProxyImpl.fromEndpoint(endpoint) { + ptr = new _{{interface|name}}ProxyCalls(impl); + } + + {{interface|name}}Proxy.fromHandle(core.MojoHandle handle) : + impl = new {{interface|name}}ProxyImpl.fromHandle(handle) { + ptr = new _{{interface|name}}ProxyCalls(impl); + } + + {{interface|name}}Proxy.unbound() : + impl = new {{interface|name}}ProxyImpl.unbound() { + ptr = new _{{interface|name}}ProxyCalls(impl); + } + + static {{interface|name}}Proxy newFromEndpoint( + core.MojoMessagePipeEndpoint endpoint) => + new {{interface|name}}Proxy.fromEndpoint(endpoint); + + void close() => impl.close(); +} + + class {{interface|name}}Stub extends bindings.Stub { {{interface|name}} _delegate = null; - {{interface|name}}Stub(core.MojoMessagePipeEndpoint endpoint) : super(endpoint); + {{interface|name}}Stub.fromEndpoint(core.MojoMessagePipeEndpoint endpoint) : + super(endpoint); {{interface|name}}Stub.fromHandle(core.MojoHandle handle) : super.fromHandle(handle); @@ -129,9 +164,9 @@ static {{interface|name}}Stub newFromEndpoint( core.MojoMessagePipeEndpoint endpoint) => - new {{interface|name}}Stub(endpoint); + new {{interface|name}}Stub.fromEndpoint(endpoint); - static const String name = {{interface|name}}.name; + static const String name = {{interface|name}}Name; {% for method in interface.methods %} {%- if method.response_parameters != None %} @@ -195,19 +230,3 @@ _delegate = d; } } - - -{#--- TODO(zra): Validation #} - - -{#--- Interface Constants #} -{% for constant in interface.constants %} -final {{constant|name}} = {{constant.value|expression_to_text}}; -{%- endfor %} - - -{#--- Interface Enums #} -{%- from "enum_definition.tmpl" import enum_def -%} -{%- for enum in interface.enums %} - {{ enum_def("", enum) }} -{%- endfor %}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/module.lib.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/module.lib.tmpl index 35124804..6ac3e65 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/module.lib.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/module.lib.tmpl
@@ -5,8 +5,8 @@ library {{module.name}}; import 'dart:async'; -import 'dart:mojo_bindings' as bindings; -import 'dart:mojo_core' as core; +import 'mojo:bindings' as bindings; +import 'mojo:core' as core; {%- for import in imports %} import 'package:{{import.module.path}}.dart' as {{import.unique_name}};
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl index 93a3e42..7538e8bf5 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl
@@ -12,7 +12,7 @@ {%- endif %} var encoder{{level + 1}} = encoder{{level}}.encodePointerArray({{variable}}.length, {{offset}}, {{kind|array_expected_length}}); for (int i{{level}} = 0; i{{level}} < {{variable}}.length; ++i{{level}}) { - {{encode(variable~'[i'~level~']', sub_kind, 'bindings.DataHeader.kHeaderSize + bindings.kPointerSize * i'~level, 0, level+1)|indent(4)}} + {{encode(variable~'[i'~level~']', sub_kind, 'bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize * i'~level, 0, level+1)|indent(4)}} } } {%- elif kind|is_map_kind %} @@ -23,8 +23,8 @@ int size{{level}} = {{variable}}.length; var keys{{level}} = {{variable}}.keys.toList(); var values{{level}} = {{variable}}.values.toList(); - {{encode('keys'~level, kind.key_kind|array, 'bindings.DataHeader.kHeaderSize', 0, level+1, False)|indent(2)}} - {{encode('values'~level, kind.value_kind|array, 'bindings.DataHeader.kHeaderSize + bindings.kPointerSize', 0, level+1, False)|indent(2)}} + {{encode('keys'~level, kind.key_kind|array, 'bindings.ArrayDataHeader.kHeaderSize', 0, level+1, False)|indent(2)}} + {{encode('values'~level, kind.value_kind|array, 'bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize', 0, level+1, False)|indent(2)}} } {%- else %} encoder{{level}}.{{kind|encode_method(variable, offset, bit)}}; @@ -50,18 +50,18 @@ List<{{kind.key_kind|dart_type}}> keys{{level}}; List<{{kind.value_kind|dart_type}}> values{{level}}; { - {{decode('keys'~level, kind.key_kind|array, 'bindings.DataHeader.kHeaderSize', 0, level+1)|indent(4)}} + {{decode('keys'~level, kind.key_kind|array, 'bindings.ArrayDataHeader.kHeaderSize', 0, level+1)|indent(4)}} } { - {{decode('values'~level, kind.value_kind|array('keys'~level~'.length'), 'bindings.DataHeader.kHeaderSize + bindings.kPointerSize', 0, level+1)|indent(4)}} + {{decode('values'~level, kind.value_kind|array('keys'~level~'.length'), 'bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize', 0, level+1)|indent(4)}} } {{variable}} = new Map<{{kind.key_kind|dart_type}}, {{kind.value_kind|dart_type}}>.fromIterables( keys{{level}}, values{{level}}); {%- else %} var si{{level+1}} = decoder{{level+1}}.decodeDataHeaderForPointerArray({{kind|array_expected_length}}); - {{variable}} = new {{kind|dart_type}}(si{{level+1}}.numFields); - for (int i{{level+1}} = 0; i{{level+1}} < si{{level+1}}.numFields; ++i{{level+1}}) { - {{decode(variable~'[i'~(level+1)~']', kind.kind, 'bindings.DataHeader.kHeaderSize + bindings.kPointerSize * i'~(level+1), 0, level+1)|indent(4)}} + {{variable}} = new {{kind|dart_type}}(si{{level+1}}.numElements); + for (int i{{level+1}} = 0; i{{level+1}} < si{{level+1}}.numElements; ++i{{level+1}}) { + {{decode(variable~'[i'~(level+1)~']', kind.kind, 'bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize * i'~(level+1), 0, level+1)|indent(4)}} } {%- endif %} } @@ -75,8 +75,8 @@ {%- macro struct_def(struct) %} class {{struct|name}} extends bindings.Struct { static const int kStructSize = {{struct.versions[-1].num_bytes}}; - static const bindings.DataHeader kDefaultStructInfo = - const bindings.DataHeader(kStructSize, {{struct.packed.packed_fields|length}}); + static const bindings.StructDataHeader kDefaultStructInfo = + const bindings.StructDataHeader(kStructSize, {{struct.versions[-1].version}}); {#--- Enums #} {%- from "enum_definition.tmpl" import enum_def %} @@ -107,15 +107,15 @@ } {{struct|name}} result = new {{struct|name}}(); - var mainDataHeader = decoder0.decodeDataHeader(); + var mainDataHeader = decoder0.decodeStructDataHeader(); if ((mainDataHeader.size < kStructSize) || - (mainDataHeader.numFields < {{struct.packed.packed_fields|length}})) { + (mainDataHeader.version < {{struct.versions[-1].version}})) { throw new bindings.MojoCodecError('Malformed header'); } {%- for byte in struct.bytes %} {%- for packed_field in byte.packed_fields %} - if (mainDataHeader.numFields > {{packed_field.ordinal}}) { + { {{decode('result.' ~ packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(6)}} } {%- endfor %} @@ -125,9 +125,9 @@ void encode(bindings.Encoder encoder) { {%- if not struct.bytes %} - encoder.getEncoderAtOffset(kDefaultStructInfo); + encoder.getStructEncoderAtOffset(kDefaultStructInfo); {%- else %} - var encoder0 = encoder.getEncoderAtOffset(kDefaultStructInfo); + var encoder0 = encoder.getStructEncoderAtOffset(kDefaultStructInfo); {%- endif %} {%- for byte in struct.bytes %} {%- for packed_field in byte.packed_fields %}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/interface.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/interface.tmpl index 484845d..32ba383 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/interface.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/interface.tmpl
@@ -4,11 +4,162 @@ {% import "struct.tmpl" as struct_macros %} +{%- macro declare_params(struct) %} +{%- for field in struct.fields -%} + {{field|name(False)}} {{field.kind|go_type}}{% if not loop.last %}, {% endif %} +{%- endfor %} +{%- endmacro %} + + + +{% macro declare_request_params(method) %} +({{declare_params(method|struct_from_method)}}) +{%- if method.response_parameters|is_none_or_empty -%} + {{' (err error)'}} +{%- else -%} + {{' '}}({{declare_params(method|response_struct_from_method)}}, err error) +{%- endif -%} +{% endmacro %} + + + +{%- macro flags(response_parameters, is_renponse) -%} +{%- if not response_parameters -%} + bindings.MessageNoFlag +{%- elif is_parameter: -%} + bindings.MessageExpectsResponseFlag +{%- else -%} + bindings.MessageIsResponseFlag +{%- endif -%} +{%- endmacro -%} + + + {% macro define(interface) %} +type {{interface|name}} interface { +{% for method in interface.methods %} + {{method|name}}{{declare_request_params(method)}} +{% endfor %} +} + +type {{interface|name}}Request bindings.InterfaceRequest +type {{interface|name}}Pointer bindings.InterfacePointer + +{% for method in interface.methods %} +const {{interface|name(False)}}_{{method|name}}_Name = {{method.ordinal}} +{% endfor %} + +type {{interface|name}}Proxy struct { + router *bindings.Router + ids *bindings.Counter +} + +func New{{interface|name}}Proxy(p {{interface|name}}Pointer, waiter bindings.AsyncWaiter) *{{interface|name}}Proxy { + return &{{interface|name}}Proxy{ + bindings.NewRouter(p.PassMessagePipe(), waiter), + &bindings.Counter{}, + } +} + +func (p *{{interface|name}}Proxy) Close_proxy() { + p.router.Close() +} + {% for method in interface.methods %} {{struct_macros.define(method|struct_from_method, False)}} {%- if method.response_parameters %} {{struct_macros.define(method|response_struct_from_method, False)}} +{%- endif %} +func (p *{{interface|name}}Proxy) {{method|name}}{{declare_request_params(method)}} { + payload := &{{method|struct_from_method|name(False)}}{ +{% for field in (method|struct_from_method).fields %} + {{field|name(False)}}, +{% endfor %} + } + header := bindings.MessageHeader{ + Type: {{interface|name(False)}}_{{method|name}}_Name, + Flags: {{flags(method.response_parameters, False)}}, +{% if method.response_parameters %} + RequestId: p.ids.Next(), +{% endif %} + } + var message *bindings.Message + if message, err = bindings.EncodeMessage(header, payload); err != nil { + err = fmt.Errorf("can't encode request: %v", err.Error()) + return + } +{% if method.response_parameters %} + readResult := <-p.router.AcceptWithResponse(message) + if err = readResult.Error; err != nil { + return + } + var response {{method|response_struct_from_method|name(False)}} + if err = readResult.Message.DecodePayload(&response); err != nil { + err = fmt.Errorf("can't decode response: %v", err.Error()) + return + } +{% for field in (method|response_struct_from_method).fields %} + {{field|name(False)}} = response.{{field|name(False)}} +{% endfor %} +{% else %} + err = p.router.Accept(message) +{% endif %} + return +} + +{% endfor %} +type {{interface|name(False)}}Stub struct { + connector *bindings.Connector + impl {{interface|name}} +} + +func New{{interface|name}}Stub(r {{interface|name}}Request, impl {{interface|name}}, waiter bindings.AsyncWaiter) *bindings.Stub { + connector := bindings.NewConnector(r.PassMessagePipe(), waiter) + return bindings.NewStub(connector, &{{interface|name(False)}}Stub{connector, impl}) +} + +func (s *{{interface|name(False)}}Stub) Accept(message *bindings.Message) (err error) { + switch message.Header.Type { +{% for method in interface.methods %} + case {{interface|name(False)}}_{{method|name}}_Name: + var request {{method|struct_from_method|name(False)}} + if err := message.DecodePayload(&request); err != nil { + return fmt.Errorf("can't decode request: %v", err.Error()) + } +{% if method.response_parameters %} + var response {{method|response_struct_from_method|name(False)}} +{% endif %} +{% if method.response_parameters|is_none_or_empty %} + err = s.impl.{{method|name}}( +{%- else -%} +{% for field in (method|response_struct_from_method).fields %} + response.{{field|name(False)}}{{', '}} +{%- endfor -%}err = s.impl.{{method|name}}( +{%- endif -%} +{%- for field in (method|struct_from_method).fields -%} + request.{{field|name(False)}}{% if not loop.last %}, {% endif %} +{%- endfor -%} + ) + if err != nil { + return + } +{% if method.response_parameters %} + header := bindings.MessageHeader{ + Type: {{interface|name(False)}}_{{method|name}}_Name, + Flags: {{flags(method.response_parameters, True)}}, + RequestId: message.Header.RequestId, + } + message, err = bindings.EncodeMessage(header, &response) + if err != nil { + return fmt.Errorf("can't encode response: %v", err.Error()) + } + return s.connector.WriteMessage(message) {% endif %} {% endfor %} -{% endmacro %} \ No newline at end of file + default: + return fmt.Errorf("unsupported request type %v", message.Header.Type); + } + return +} + +{% endmacro %}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/source.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/source.tmpl index 3769585..b697cdf 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/source.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/source.tmpl
@@ -12,14 +12,12 @@ import ( "fmt" - - "mojo/public/go/bindings" - "mojo/public/go/system" +{% for i in imports %} + {{i}} +{% endfor %} ) var _ = fmt.Errorf -var _ = bindings.NewEncoder -var _ = system.GetCore {% import "enum.tmpl" as enum_macros %} {% import "interface.tmpl" as interface_macros %}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/struct.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/struct.tmpl index eb6b121..457e3394 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/struct.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/struct.tmpl
@@ -4,13 +4,14 @@ {% macro define(struct, exported=True) %} type {{struct|name(exported)}} struct { -{% for packed_field in struct.packed.packed_fields %} - {{packed_field.field|name(exported)}} {{packed_field.field.kind|go_type}} +{% for field in struct.fields %} + {{field|name(exported)}} {{field.kind|go_type}} {% endfor %} } func (s *{{struct|name(exported)}}) Encode(encoder *bindings.Encoder) error { - encoder.StartStruct({{struct.versions[-1].num_bytes}}, {{struct.packed.packed_fields|length}}) +{% set HEADER_SIZE = 8 %} + encoder.StartStruct({{struct.versions[-1].num_bytes - HEADER_SIZE}}, {{struct.versions[-1].version}}) {% for byte in struct.bytes %} {% for packed_field in byte.packed_fields %} {{encode('s.'~packed_field.field|name(exported), packed_field.field.kind)|tab_indent()}} @@ -24,7 +25,7 @@ func (s *{{struct|name(exported)}}) Decode(decoder *bindings.Decoder) error { {% if struct.bytes %} - numFields, err := decoder.StartStruct() + version, err := decoder.StartStruct() {% else %} _, err := decoder.StartStruct() {% endif %} @@ -33,7 +34,7 @@ } {% for byte in struct.bytes %} {% for packed_field in byte.packed_fields %} - if numFields > {{packed_field.ordinal}} { + if version >= {{packed_field.min_version}} { {{decode('s.'~packed_field.field|name(exported), packed_field.field.kind)|tab_indent(2)}} } {% endfor %} @@ -103,6 +104,10 @@ if err := encoder.WriteInt32(int32({{value}})); err != nil { return err } +{% elif kind|is_handle_owner %} +if err := encoder.WriteHandle({{value}}.PassMessagePipe()); err != nil { + return err +} {% else %} if err := encoder.Write{{kind|encode_suffix}}({{value}}); err != nil { return err @@ -137,7 +142,12 @@ return err } if handle{{level}}.IsValid() { +{% if kind|is_handle_owner %} + handleOwner := bindings.NewMessagePipeHandleOwner(handle{{level}}) + {{value}} = {% if kind|is_nullable %}&{% endif %}{{kind|go_type(False)}}{handleOwner} +{% else %} {{value}} = {% if kind|is_nullable %}&{% endif %}handle{{level}} +{% endif %} } else { {% if kind|is_nullable %} {{value}} = nil
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface.java.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface.java.tmpl index 10e5d7a..a13be3e 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface.java.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface.java.tmpl
@@ -1,4 +1,4 @@ {% from "interface_definition.tmpl" import interface_def %} {% include "header.java.tmpl" %} -{{ interface_def(interface, client) }} +{{ interface_def(interface) }}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl index 941fec77..e38c895 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl
@@ -36,14 +36,6 @@ {%- endif -%} {%- endmacro -%} -{%- macro super_class(client, with_generic=True) -%} -{%- if client -%} -org.chromium.mojo.bindings.InterfaceWithClient{% if with_generic %}<{{client|java_type}}>{% endif %} -{%- else -%} -org.chromium.mojo.bindings.Interface -{%- endif -%} -{%- endmacro -%} - {%- macro flags_for_method(method, is_parameter) -%} {{flags(method.response_parameters, is_parameter)}} {%- endmacro -%} @@ -58,15 +50,13 @@ {%- endif -%} {%- endmacro -%} -{%- macro manager_class(interface, client, fully_qualified=False) -%} -{% if fully_qualified %}{{super_class(client, False)}}.{% endif %}Manager<{{interface|name}}, {{interface|name}}.Proxy -{%- if client -%}, {{client|java_type}}{%- endif -%} -> +{%- macro manager_class(interface, fully_qualified=False) -%} +{% if fully_qualified %}org.chromium.mojo.bindings.Interface.{% endif %}Manager<{{interface|name}}, {{interface|name}}.Proxy> {%- endmacro -%} -{%- macro manager_def(interface, client) -%} -public static final {{manager_class(interface, client, True)}} MANAGER = - new {{manager_class(interface, client, True)}}() { +{%- macro manager_def(interface) -%} +public static final {{manager_class(interface, True)}} MANAGER = + new {{manager_class(interface, True)}}() { public String getName() { return "{{namespace|replace(".","::")}}::{{interface.name}}"; @@ -84,12 +74,6 @@ public {{interface|name}}[] buildArray(int size) { return new {{interface|name}}[size]; } -{% if client %} - - protected org.chromium.mojo.bindings.Interface.Manager<{{client|java_type}}, ?> getClientManager() { - return {{client|java_type}}.MANAGER; - } -{% endif %} }; {%- endmacro -%} @@ -134,8 +118,8 @@ {% endif %} {%- endmacro -%} -{% macro interface_def(interface, client) %} -public interface {{interface|name}} extends {{super_class(client)}} { +{% macro interface_def(interface) %} +public interface {{interface|name}} extends org.chromium.mojo.bindings.Interface { {% for constant in interface.constants %} {{constant_def(constant)|indent(4)}} @@ -145,10 +129,10 @@ {{enum_def(enum, false)|indent(4)}} {% endfor %} - public interface Proxy extends {{interface|name}}, {{super_class(client, False)}}.Proxy{% if client %}<{{client|java_type}}>{% endif %} { + public interface Proxy extends {{interface|name}}, org.chromium.mojo.bindings.Interface.Proxy { } - {{manager_class(interface, client)}} MANAGER = {{interface|name}}_Internal.MANAGER; + {{manager_class(interface)}} MANAGER = {{interface|name}}_Internal.MANAGER; {% for method in interface.methods %} void {{method|name}}({{declare_request_params(method)}}); @@ -159,16 +143,16 @@ } {% endmacro %} -{% macro interface_internal_def(interface, client) %} +{% macro interface_internal_def(interface) %} class {{interface|name}}_Internal { - {{manager_def(interface, client)|indent(4)}} + {{manager_def(interface)|indent(4)}} {% for method in interface.methods %} private static final int {{method|method_ordinal_name}} = {{method.ordinal}}; {% endfor %} - static final class Proxy extends {% if client %}org.chromium.mojo.bindings.InterfaceWithClient.AbstractProxy<{{client|java_type}}>{% else %}org.chromium.mojo.bindings.Interface.AbstractProxy{% endif %} implements {{interface|name}}.Proxy { + static final class Proxy extends org.chromium.mojo.bindings.Interface.AbstractProxy implements {{interface|name}}.Proxy { Proxy(org.chromium.mojo.system.Core core, org.chromium.mojo.bindings.MessageReceiverWithResponder messageReceiver) {
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface_internal.java.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface_internal.java.tmpl index efb17f33..50c7a7b 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface_internal.java.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface_internal.java.tmpl
@@ -1,4 +1,4 @@ {% from "interface_definition.tmpl" import interface_internal_def %} {% include "header.java.tmpl" %} -{{ interface_internal_def(interface, client) }} +{{ interface_internal_def(interface) }}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/struct_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/struct_definition.tmpl index 333e0da..f0cb9829 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/struct_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/struct_definition.tmpl
@@ -95,8 +95,8 @@ } {% else %} DataHeader si{{level+1}} = decoder{{level+1}}.readDataHeaderForPointerArray({{kind|array_expected_length}}); - {{variable}} = {{kind|new_array('si'~(level+1)~'.numFields')}}; - for (int i{{level+1}} = 0; i{{level+1}} < si{{level+1}}.numFields; ++i{{level+1}}) { + {{variable}} = {{kind|new_array('si'~(level+1)~'.elementsOrVersion')}}; + for (int i{{level+1}} = 0; i{{level+1}} < si{{level+1}}.elementsOrVersion; ++i{{level+1}}) { {{decode(variable~'[i'~(level+1)~']', kind.kind, 'DataHeader.HEADER_SIZE + org.chromium.mojo.bindings.BindingsHelper.POINTER_SIZE * i'~(level+1), 0, level+1)|indent(8)}} } {% endif %} @@ -111,7 +111,12 @@ {{'static' if inner_class else 'public'}} final class {{struct|name}} extends org.chromium.mojo.bindings.Struct { private static final int STRUCT_SIZE = {{struct.versions[-1].num_bytes}}; - private static final DataHeader DEFAULT_STRUCT_INFO = new DataHeader(STRUCT_SIZE, {{struct.packed.packed_fields|length}}); + private static final DataHeader[] VERSION_ARRAY = new DataHeader[] { +{%- for version in struct.versions -%} + new DataHeader({{version.num_bytes}}, {{version.version}}){% if not loop.last %}, {% endif -%} +{%- endfor -%} + }; + private static final DataHeader DEFAULT_STRUCT_INFO = VERSION_ARRAY[{{struct.versions|length - 1}}]; {% for constant in struct.constants %} {{constant_def(constant)|indent(4)}} @@ -149,13 +154,13 @@ } {{struct|name}} result = new {{struct|name}}(); {% if not struct.bytes %} - decoder0.readDataHeader(); + decoder0.readAndValidateDataHeader(VERSION_ARRAY); {% else %} - DataHeader mainDataHeader = decoder0.readDataHeader(); + DataHeader mainDataHeader = decoder0.readAndValidateDataHeader(VERSION_ARRAY); {% endif %} {% for byte in struct.bytes %} {% for packed_field in byte.packed_fields %} - if (mainDataHeader.numFields > {{packed_field.ordinal}}) { + if (mainDataHeader.elementsOrVersion >= {{packed_field.min_version}}) { {{decode('result.' ~ packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(12)}} } {% endfor %}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_go_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_go_generator.py index 1196276..cb5a16e 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_go_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_go_generator.py
@@ -57,6 +57,8 @@ mojom.NULLABLE_STRING: KindInfo('string', 'String', 'String', 64), } +_imports = {} + def GetBitSize(kind): if isinstance(kind, (mojom.Array, mojom.Map, mojom.Struct)): return 64 @@ -66,26 +68,34 @@ kind = mojom.INT32 return _kind_infos[kind].bit_size +# Returns go type corresponding to provided kind. If |nullable| is true +# and kind is nullable adds an '*' to type (example: ?string -> *string). def GetGoType(kind, nullable = True): if nullable and mojom.IsNullableKind(kind): return '*%s' % GetNonNullableGoType(kind) return GetNonNullableGoType(kind) +# Returns go type corresponding to provided kind. Ignores nullability of +# top-level kind. def GetNonNullableGoType(kind): if mojom.IsStructKind(kind): - return '%s' % FormatName(kind.name) + return '%s' % GetFullName(kind) if mojom.IsArrayKind(kind): if kind.length: return '[%s]%s' % (kind.length, GetGoType(kind.kind)) return '[]%s' % GetGoType(kind.kind) if mojom.IsMapKind(kind): return 'map[%s]%s' % (GetGoType(kind.key_kind), GetGoType(kind.value_kind)) - if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind): - return GetGoType(mojom.MSGPIPE) + if mojom.IsInterfaceKind(kind): + return '%sPointer' % GetFullName(kind) + if mojom.IsInterfaceRequestKind(kind): + return '%sRequest' % GetFullName(kind.kind) if mojom.IsEnumKind(kind): return GetNameForNestedElement(kind) return _kind_infos[kind].go_type +# Splits name to lower-cased parts used for camel-casing +# (example: HTTPEntry2FooBar -> ['http', 'entry2', 'foo', 'bar']). def NameToComponent(name): # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar -> # HTTP_Entry2_FooBar) @@ -98,24 +108,44 @@ def UpperCamelCase(name): return ''.join([x.capitalize() for x in NameToComponent(name)]) +# Formats a name. If |exported| is true makes name camel-cased with first +# letter capital, otherwise does no camel-casing and makes first letter +# lower-cased (which is used for making internal names more readable). def FormatName(name, exported=True): if exported: return UpperCamelCase(name) # Leave '_' symbols for unexported names. return name[0].lower() + name[1:] +# Returns full name of an imported element based on prebuilt dict |_imports|. +# If the |element| is not imported returns formatted name of it. +# |element| should have attr 'name'. |exported| argument is used to make +# |FormatName()| calls only. +def GetFullName(element, exported=True): + if not hasattr(element, 'imported_from') or not element.imported_from: + return FormatName(element.name, exported) + path = 'gen/mojom' + if element.imported_from['namespace']: + path = '/'.join([path] + element.imported_from['namespace'].split('.')) + if path in _imports: + return '%s.%s' % (_imports[path], FormatName(element.name, exported)) + return FormatName(element.name, exported) + +# Returns a name for nested elements like enum field or constant. +# The returned name consists of camel-cased parts separated by '_'. def GetNameForNestedElement(element): if element.parent_kind: return "%s_%s" % (GetNameForElement(element.parent_kind), FormatName(element.name)) - return FormatName(element.name) + return GetFullName(element) def GetNameForElement(element, exported=True): - if (mojom.IsInterfaceKind(element) or mojom.IsStructKind(element) or - isinstance(element, (mojom.EnumField, - mojom.Field, - mojom.Method, - mojom.Parameter))): + if (mojom.IsInterfaceKind(element) or mojom.IsStructKind(element)): + return GetFullName(element, exported) + if isinstance(element, (mojom.EnumField, + mojom.Field, + mojom.Method, + mojom.Parameter)): return FormatName(element.name, exported) if isinstance(element, (mojom.Enum, mojom.Constant, @@ -147,14 +177,14 @@ return EncodeSuffix(mojom.MSGPIPE) return _kind_infos[kind].encode_suffix -def GetPackage(module): - if module.namespace: - return module.namespace.split('.')[-1] +def GetPackage(namespace): + if namespace: + return namespace.split('.')[-1] return 'mojom' -def GetPackagePath(module): +def GetPackagePath(namespace): path = 'mojom' - for i in module.namespace.split('.'): + for i in namespace.split('.'): path = os.path.join(path, i) return path @@ -182,6 +212,78 @@ struct.versions = pack.GetVersionInfo(struct.packed) return struct +def GetAllConstants(module): + data = [module] + module.structs + module.interfaces + constants = [x.constants for x in data] + return [i for i in chain.from_iterable(constants)] + +def GetAllEnums(module): + data = [module] + module.structs + module.interfaces + enums = [x.enums for x in data] + return [i for i in chain.from_iterable(enums)] + +# Adds an import required to use the provided |element|. +# The required import is stored at '_imports'. +def AddImport(module, element): + if (isinstance(element, mojom.Kind) and + mojom.IsNonInterfaceHandleKind(element)): + _imports['mojo/public/go/system'] = 'system' + return + if isinstance(element, mojom.Kind) and mojom.IsInterfaceRequestKind(element): + AddImport(module, element.kind) + return + if not hasattr(element, 'imported_from') or not element.imported_from: + return + imported = element.imported_from + if imported['namespace'] == module.namespace: + return + path = 'gen/mojom' + name = 'mojom' + if imported['namespace']: + path = '/'.join([path] + imported['namespace'].split('.')) + name = '_'.join([name] + imported['namespace'].split('.')) + while (name in _imports.values() and _imports[path] != path): + name += '_' + _imports[path] = name + +# Scans |module| for elements that require imports and adds all found imports +# to '_imports' dict. Returns a list of imports that should include the +# generated go file. +def GetImports(module): + # Imports can only be used in structs, constants, enums, interfaces. + all_structs = list(module.structs) + for i in module.interfaces: + for method in i.methods: + all_structs.append(GetStructFromMethod(method)) + if method.response_parameters: + all_structs.append(GetResponseStructFromMethod(method)) + + if len(all_structs) > 0 or len(module.interfaces) > 0: + _imports['mojo/public/go/bindings'] = 'bindings' + for struct in all_structs: + for field in struct.fields: + AddImport(module, field.kind) +# TODO(rogulenko): add these after generating constants and struct defaults. +# if field.default: +# AddImport(module, field.default) + + for enum in GetAllEnums(module): + for field in enum.fields: + if field.value: + AddImport(module, field.value) + +# TODO(rogulenko): add these after generating constants and struct defaults. +# for constant in GetAllConstants(module): +# AddImport(module, constant.value) + + imports_list = [] + for i in _imports: + if i.split('/')[-1] == _imports[i]: + imports_list.append('"%s"' % i) + else: + imports_list.append('%s "%s"' % (_imports[i], i)) + return sorted(imports_list) + class Generator(generator.Generator): go_filters = { 'array': lambda kind: mojom.Array(kind), @@ -193,6 +295,8 @@ 'is_array': mojom.IsArrayKind, 'is_enum': mojom.IsEnumKind, 'is_handle': mojom.IsAnyHandleKind, + 'is_handle_owner': lambda kind: + mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind), 'is_map': mojom.IsMapKind, 'is_none_or_empty': lambda array: array == None or len(array) == 0, 'is_nullable': mojom.IsNullableKind, @@ -204,16 +308,12 @@ 'tab_indent': lambda s, size = 1: ('\n' + '\t' * size).join(s.splitlines()) } - def GetAllEnums(self): - data = [self.module] + self.GetStructs() + self.module.interfaces - enums = [x.enums for x in data] - return [i for i in chain.from_iterable(enums)] - def GetParameters(self): return { - 'enums': self.GetAllEnums(), + 'enums': GetAllEnums(self.module), + 'imports': GetImports(self.module), 'interfaces': self.module.interfaces, - 'package': GetPackage(self.module), + 'package': GetPackage(self.module.namespace), 'structs': self.GetStructs(), } @@ -223,7 +323,7 @@ def GenerateFiles(self, args): self.Write(self.GenerateSource(), os.path.join("go", "src", "gen", - GetPackagePath(self.module), '%s.go' % self.module.name)) + GetPackagePath(self.module.namespace), '%s.go' % self.module.name)) def GetJinjaParameters(self): return {
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py index f279ef893..d6712f3 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py
@@ -422,15 +422,6 @@ def GetJinjaExportsForInterface(self, interface): exports = self.GetJinjaExports() exports.update({'interface': interface}) - if interface.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/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_python_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_python_generator.py index d4d4ed7e..cbb19627 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_python_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_python_generator.py
@@ -176,7 +176,7 @@ arguments = [ '%r' % GetNameForElement(field) ] arguments.append(GetFieldType(field.kind, field)) arguments.append(str(packed_field.index)) - arguments.append(str(packed_field.ordinal)) + arguments.append(str(packed_field.min_version)) if field.default: if mojom.IsStructKind(field.kind): arguments.append('default_value=True')
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni b/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni index 3b2874f..00a61a8 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni +++ b/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni
@@ -16,7 +16,7 @@ # # Parameters: # -# sources (required) +# sources (optional if one of the deps sets listed below is present) # List of source .mojom files to compile. # # deps (optional) @@ -42,98 +42,103 @@ # # visibility (optional) template("mojom") { - assert(defined(invoker.sources), - "\"sources\" must be defined for the $target_name template.") + assert( + defined(invoker.sources) || defined(invoker.deps) || + defined(invoker.public_deps) || defined(invoker.mojo_sdk_deps) || + defined(invoker.mojo_sdk_public_deps), + "\"sources\" or \"deps\" must be defined for the $target_name template.") - generator_root = rebase_path("mojo/public/tools/bindings", ".", mojo_root) - generator_script = "$generator_root/mojom_bindings_generator.py" - generator_sources = [ - generator_script, - "$generator_root/generators/cpp_templates/enum_declaration.tmpl", - "$generator_root/generators/cpp_templates/interface_declaration.tmpl", - "$generator_root/generators/cpp_templates/interface_definition.tmpl", - "$generator_root/generators/cpp_templates/interface_macros.tmpl", - "$generator_root/generators/cpp_templates/interface_proxy_declaration.tmpl", - "$generator_root/generators/cpp_templates/interface_request_validator_declaration.tmpl", - "$generator_root/generators/cpp_templates/interface_response_validator_declaration.tmpl", - "$generator_root/generators/cpp_templates/interface_stub_declaration.tmpl", - "$generator_root/generators/cpp_templates/module.cc.tmpl", - "$generator_root/generators/cpp_templates/module.h.tmpl", - "$generator_root/generators/cpp_templates/module-internal.h.tmpl", - "$generator_root/generators/cpp_templates/params_definition.tmpl", - "$generator_root/generators/cpp_templates/serialization_macros.tmpl", - "$generator_root/generators/cpp_templates/struct_declaration.tmpl", - "$generator_root/generators/cpp_templates/struct_definition.tmpl", - "$generator_root/generators/cpp_templates/struct_serialization_definition.tmpl", - "$generator_root/generators/cpp_templates/struct_macros.tmpl", - "$generator_root/generators/cpp_templates/wrapper_class_declaration.tmpl", - "$generator_root/generators/cpp_templates/wrapper_class_definition.tmpl", - "$generator_root/generators/cpp_templates/union_declaration.tmpl", - "$generator_root/generators/cpp_templates/union_definition.tmpl", - "$generator_root/generators/cpp_templates/union_serialization_definition.tmpl", - "$generator_root/generators/cpp_templates/validation_macros.tmpl", - "$generator_root/generators/cpp_templates/wrapper_union_class_declaration.tmpl", - "$generator_root/generators/cpp_templates/wrapper_union_class_definition.tmpl", - "$generator_root/generators/dart_templates/enum_definition.tmpl", - "$generator_root/generators/dart_templates/interface_definition.tmpl", - "$generator_root/generators/dart_templates/module.lib.tmpl", - "$generator_root/generators/dart_templates/module_definition.tmpl", - "$generator_root/generators/dart_templates/struct_definition.tmpl", - "$generator_root/generators/go_templates/enum.tmpl", - "$generator_root/generators/go_templates/interface.tmpl", - "$generator_root/generators/go_templates/source.tmpl", - "$generator_root/generators/go_templates/struct.tmpl", - "$generator_root/generators/java_templates/constant_definition.tmpl", - "$generator_root/generators/java_templates/constants.java.tmpl", - "$generator_root/generators/java_templates/enum.java.tmpl", - "$generator_root/generators/java_templates/enum_definition.tmpl", - "$generator_root/generators/java_templates/header.java.tmpl", - "$generator_root/generators/java_templates/interface.java.tmpl", - "$generator_root/generators/java_templates/interface_definition.tmpl", - "$generator_root/generators/java_templates/interface_internal.java.tmpl", - "$generator_root/generators/java_templates/struct.java.tmpl", - "$generator_root/generators/java_templates/struct_definition.tmpl", - "$generator_root/generators/js_templates/enum_definition.tmpl", - "$generator_root/generators/js_templates/interface_definition.tmpl", - "$generator_root/generators/js_templates/module.amd.tmpl", - "$generator_root/generators/js_templates/module.sky.tmpl", - "$generator_root/generators/js_templates/module_definition.tmpl", - "$generator_root/generators/js_templates/struct_definition.tmpl", - "$generator_root/generators/python_templates/module_macros.tmpl", - "$generator_root/generators/python_templates/module.py.tmpl", - "$generator_root/generators/mojom_cpp_generator.py", - "$generator_root/generators/mojom_dart_generator.py", - "$generator_root/generators/mojom_go_generator.py", - "$generator_root/generators/mojom_js_generator.py", - "$generator_root/generators/mojom_java_generator.py", - "$generator_root/generators/mojom_python_generator.py", - "$generator_root/pylib/mojom/__init__.py", - "$generator_root/pylib/mojom/error.py", - "$generator_root/pylib/mojom/generate/__init__.py", - "$generator_root/pylib/mojom/generate/data.py", - "$generator_root/pylib/mojom/generate/generator.py", - "$generator_root/pylib/mojom/generate/module.py", - "$generator_root/pylib/mojom/generate/pack.py", - "$generator_root/pylib/mojom/generate/template_expander.py", - "$generator_root/pylib/mojom/parse/__init__.py", - "$generator_root/pylib/mojom/parse/ast.py", - "$generator_root/pylib/mojom/parse/lexer.py", - "$generator_root/pylib/mojom/parse/parser.py", - "$generator_root/pylib/mojom/parse/translate.py", - ] - generator_cpp_outputs = [ - "{{source_gen_dir}}/{{source_name_part}}.mojom.cc", - "{{source_gen_dir}}/{{source_name_part}}.mojom.h", - "{{source_gen_dir}}/{{source_name_part}}.mojom-internal.h", - ] - generator_dart_outputs = - [ "{{source_gen_dir}}/{{source_name_part}}.mojom.dart" ] + if (defined(invoker.sources)) { + generator_root = rebase_path("mojo/public/tools/bindings", ".", mojo_root) + generator_script = "$generator_root/mojom_bindings_generator.py" + generator_sources = [ + generator_script, + "$generator_root/generators/cpp_templates/enum_declaration.tmpl", + "$generator_root/generators/cpp_templates/interface_declaration.tmpl", + "$generator_root/generators/cpp_templates/interface_definition.tmpl", + "$generator_root/generators/cpp_templates/interface_macros.tmpl", + "$generator_root/generators/cpp_templates/interface_proxy_declaration.tmpl", + "$generator_root/generators/cpp_templates/interface_request_validator_declaration.tmpl", + "$generator_root/generators/cpp_templates/interface_response_validator_declaration.tmpl", + "$generator_root/generators/cpp_templates/interface_stub_declaration.tmpl", + "$generator_root/generators/cpp_templates/module.cc.tmpl", + "$generator_root/generators/cpp_templates/module.h.tmpl", + "$generator_root/generators/cpp_templates/module-internal.h.tmpl", + "$generator_root/generators/cpp_templates/serialization_macros.tmpl", + "$generator_root/generators/cpp_templates/struct_declaration.tmpl", + "$generator_root/generators/cpp_templates/struct_definition.tmpl", + "$generator_root/generators/cpp_templates/struct_serialization_definition.tmpl", + "$generator_root/generators/cpp_templates/struct_macros.tmpl", + "$generator_root/generators/cpp_templates/wrapper_class_declaration.tmpl", + "$generator_root/generators/cpp_templates/wrapper_class_definition.tmpl", + "$generator_root/generators/cpp_templates/union_declaration.tmpl", + "$generator_root/generators/cpp_templates/union_definition.tmpl", + "$generator_root/generators/cpp_templates/union_serialization_definition.tmpl", + "$generator_root/generators/cpp_templates/validation_macros.tmpl", + "$generator_root/generators/cpp_templates/wrapper_union_class_declaration.tmpl", + "$generator_root/generators/cpp_templates/wrapper_union_class_definition.tmpl", + "$generator_root/generators/dart_templates/enum_definition.tmpl", + "$generator_root/generators/dart_templates/interface_definition.tmpl", + "$generator_root/generators/dart_templates/module.lib.tmpl", + "$generator_root/generators/dart_templates/module_definition.tmpl", + "$generator_root/generators/dart_templates/struct_definition.tmpl", + "$generator_root/generators/go_templates/enum.tmpl", + "$generator_root/generators/go_templates/interface.tmpl", + "$generator_root/generators/go_templates/source.tmpl", + "$generator_root/generators/go_templates/struct.tmpl", + "$generator_root/generators/java_templates/constant_definition.tmpl", + "$generator_root/generators/java_templates/constants.java.tmpl", + "$generator_root/generators/java_templates/enum.java.tmpl", + "$generator_root/generators/java_templates/enum_definition.tmpl", + "$generator_root/generators/java_templates/header.java.tmpl", + "$generator_root/generators/java_templates/interface.java.tmpl", + "$generator_root/generators/java_templates/interface_definition.tmpl", + "$generator_root/generators/java_templates/interface_internal.java.tmpl", + "$generator_root/generators/java_templates/struct.java.tmpl", + "$generator_root/generators/java_templates/struct_definition.tmpl", + "$generator_root/generators/js_templates/enum_definition.tmpl", + "$generator_root/generators/js_templates/interface_definition.tmpl", + "$generator_root/generators/js_templates/module.amd.tmpl", + "$generator_root/generators/js_templates/module.sky.tmpl", + "$generator_root/generators/js_templates/module_definition.tmpl", + "$generator_root/generators/js_templates/struct_definition.tmpl", + "$generator_root/generators/python_templates/module_macros.tmpl", + "$generator_root/generators/python_templates/module.py.tmpl", + "$generator_root/generators/mojom_cpp_generator.py", + "$generator_root/generators/mojom_dart_generator.py", + "$generator_root/generators/mojom_go_generator.py", + "$generator_root/generators/mojom_js_generator.py", + "$generator_root/generators/mojom_java_generator.py", + "$generator_root/generators/mojom_python_generator.py", + "$generator_root/pylib/mojom/__init__.py", + "$generator_root/pylib/mojom/error.py", + "$generator_root/pylib/mojom/generate/__init__.py", + "$generator_root/pylib/mojom/generate/data.py", + "$generator_root/pylib/mojom/generate/generator.py", + "$generator_root/pylib/mojom/generate/module.py", + "$generator_root/pylib/mojom/generate/pack.py", + "$generator_root/pylib/mojom/generate/template_expander.py", + "$generator_root/pylib/mojom/parse/__init__.py", + "$generator_root/pylib/mojom/parse/ast.py", + "$generator_root/pylib/mojom/parse/lexer.py", + "$generator_root/pylib/mojom/parse/parser.py", + "$generator_root/pylib/mojom/parse/translate.py", + ] + generator_cpp_outputs = [ + "{{source_gen_dir}}/{{source_name_part}}.mojom.cc", + "{{source_gen_dir}}/{{source_name_part}}.mojom.h", + "{{source_gen_dir}}/{{source_name_part}}.mojom-internal.h", + ] + generator_js_outputs = + [ "{{source_gen_dir}}/{{source_name_part}}.mojom.js" ] + generator_dart_outputs = + [ "{{source_gen_dir}}/{{source_name_part}}.mojom.dart" ] + generator_python_outputs = + [ "{{source_gen_dir}}/{{source_name_part}}_mojom.py" ] + generator_java_outputs = + [ "{{source_gen_dir}}/{{source_name_part}}.mojom.srcjar" ] + } generator_dart_zip_output = "$target_out_dir/$target_name.dartzip" - generator_java_outputs = - [ "{{source_gen_dir}}/{{source_name_part}}.mojom.srcjar" ] - generator_js_outputs = [ "{{source_gen_dir}}/{{source_name_part}}.mojom.js" ] - generator_python_outputs = - [ "{{source_gen_dir}}/{{source_name_part}}_mojom.py" ] generator_python_zip_output = "$target_out_dir/$target_name.pyzip" rebased_mojo_sdk_public_deps = [] @@ -161,36 +166,38 @@ target_visibility = [ ":$target_name" ] } - generator_target_name = target_name + "__generator" - action_foreach(generator_target_name) { - if (defined(invoker.visibility)) { - visibility = target_visibility + invoker.visibility - } - script = generator_script - inputs = generator_sources - sources = invoker.sources - outputs = - generator_cpp_outputs + generator_dart_outputs + - generator_java_outputs + generator_js_outputs + generator_python_outputs - args = [ - "{{source}}", - "--use_bundled_pylibs", - "-d", - rebase_path("//", root_build_dir), - "-I", - rebase_path("//", root_build_dir), - "-I", - rebase_path(mojo_root, root_build_dir), - "-o", - rebase_path(root_gen_dir), - ] + if (defined(invoker.sources)) { + generator_target_name = target_name + "__generator" + action_foreach(generator_target_name) { + if (defined(invoker.visibility)) { + visibility = target_visibility + invoker.visibility + } + script = generator_script + inputs = generator_sources + sources = invoker.sources + outputs = generator_cpp_outputs + generator_dart_outputs + + generator_java_outputs + generator_js_outputs + + generator_python_outputs + args = [ + "{{source}}", + "--use_bundled_pylibs", + "-d", + rebase_path("//", root_build_dir), + "-I", + rebase_path("//", root_build_dir), + "-I", + rebase_path(mojo_root, root_build_dir), + "-o", + rebase_path(root_gen_dir), + ] - if (defined(invoker.import_dirs)) { - foreach(import_dir, invoker.import_dirs) { - args += [ - "-I", - rebase_path(import_dir, root_build_dir), - ] + if (defined(invoker.import_dirs)) { + foreach(import_dir, invoker.import_dirs) { + args += [ + "-I", + rebase_path(import_dir, root_build_dir), + ] + } } } } @@ -202,8 +209,10 @@ if (defined(invoker.testonly)) { testonly = invoker.testonly } - sources = process_file_template(invoker.sources, generator_cpp_outputs) - data = process_file_template(invoker.sources, generator_js_outputs) + if (defined(invoker.sources)) { + sources = process_file_template(invoker.sources, generator_cpp_outputs) + data = process_file_template(invoker.sources, generator_js_outputs) + } public_configs = rebase_path([ "mojo/public/build/config:mojo_sdk" ], ".", mojo_root) @@ -214,9 +223,10 @@ public_deps += invoker.public_deps } - deps = [ - ":$generator_target_name", - ] + deps = [] + if (defined(invoker.sources)) { + deps += [ ":$generator_target_name" ] + } deps += rebased_mojo_sdk_deps if (defined(invoker.deps)) { deps += invoker.deps @@ -259,7 +269,9 @@ action("${target_name}_python") { script = rebase_path("mojo/public/tools/gn/zip.py", ".", mojo_root) - inputs = process_file_template(invoker.sources, generator_python_outputs) + if (defined(invoker.sources)) { + inputs = process_file_template(invoker.sources, generator_python_outputs) + } deps = [] zip_inputs = [] @@ -281,21 +293,27 @@ ] rebase_base_dir = rebase_path(target_gen_dir, root_build_dir) - rebase_inputs = rebase_path(inputs, root_build_dir) + if (defined(invoker.sources)) { + rebase_inputs = rebase_path(inputs, root_build_dir) + } rebase_zip_inputs = rebase_path(zip_inputs, root_build_dir) rebase_output = rebase_path(output, root_build_dir) args = [ "--base-dir=$rebase_base_dir", - "--inputs=$rebase_inputs", "--zip-inputs=$rebase_zip_inputs", "--output=$rebase_output", ] + if (defined(invoker.sources)) { + args += [ "--inputs=$rebase_inputs" ] + } } action("${target_name}_dart") { script = rebase_path("mojo/public/tools/gn/zip.py", ".", mojo_root) - inputs = process_file_template(invoker.sources, generator_dart_outputs) + if (defined(invoker.sources)) { + inputs = process_file_template(invoker.sources, generator_dart_outputs) + } deps = [] zip_inputs = [] @@ -317,15 +335,19 @@ ] rebase_base_dir = rebase_path("$root_build_dir/gen/", root_build_dir) - rebase_inputs = rebase_path(inputs, root_build_dir) + if (defined(invoker.sources)) { + rebase_inputs = rebase_path(inputs, root_build_dir) + } rebase_zip_inputs = rebase_path(zip_inputs, root_build_dir) rebase_output = rebase_path(output, root_build_dir) args = [ "--base-dir=$rebase_base_dir", - "--inputs=$rebase_inputs", "--zip-inputs=$rebase_zip_inputs", "--output=$rebase_output", ] + if (defined(invoker.sources)) { + args += [ "--inputs=$rebase_inputs" ] + } } if (is_android) { @@ -348,7 +370,9 @@ deps += [ "${full_name}_java" ] } - srcjars = process_file_template(invoker.sources, generator_java_outputs) + if (defined(invoker.sources)) { + srcjars = process_file_template(invoker.sources, generator_java_outputs) + } } } }
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/module.py index c2e59a69..8d052d9d 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/module.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/module.py
@@ -131,7 +131,6 @@ ATTRIBUTE_MIN_VERSION = 'MinVersion' -ATTRIBUTE_CLIENT = 'Client' class NamedValue(object): @@ -271,16 +270,16 @@ 'm[' + key_kind.spec + '][' + value_kind.spec + ']') if IsNullableKind(key_kind): - raise Exception("Nullable kinds can not be keys in maps.") + raise Exception("Nullable kinds cannot be keys in maps.") if IsStructKind(key_kind): # TODO(erg): It would sometimes be nice if we could key on struct # values. However, what happens if the struct has a handle in it? Or # non-copyable data like an array? - raise Exception("Structs can not be keys in maps.") + raise Exception("Structs cannot be keys in maps.") if IsAnyHandleKind(key_kind): - raise Exception("Handles can not be keys in maps.") + raise Exception("Handles cannot be keys in maps.") if IsArrayKind(key_kind): - raise Exception("Arrays can not be keys in maps.") + raise Exception("Arrays cannot be keys in maps.") else: ReferenceKind.__init__(self) @@ -370,9 +369,10 @@ self.methods.append(method) return method + # TODO(451323): Remove when the language backends no longer rely on this. @property def client(self): - return self.attributes.get(ATTRIBUTE_CLIENT) if self.attributes else None + return None class EnumField(object):
diff --git a/third_party/mojo/src/mojo/public/tools/dart_analyze.py b/third_party/mojo/src/mojo/public/tools/dart_analyze.py new file mode 100755 index 0000000..8b8117e --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/dart_analyze.py
@@ -0,0 +1,67 @@ +#!/usr/bin/python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# To integrate dartanalyze with out build system, we take an input file, run +# the analyzer on it, and write a stamp file if it passed. +# +# The first argument to this script is a reference to this build's gen +# directory, which we treat as the package root. The second is the stamp file +# to touch if we succeed. The rest are passed to the analyzer verbatim. + +import os +import subprocess +import sys +import re + +_ANALYZING_PATTERN = re.compile(r'^Analyzing \[') +_FINAL_REPORT_PATTERN = re.compile(r'^[0-9]+ errors and [0-9]+ warnings found.') + +_NATIVE_ERROR_PATTERN = re.compile( + r'^\[error\] Native functions can only be declared in the SDK and code that ' + r'is loaded through native extensions') +_WARNING_PATTERN = re.compile(r'^\[warning\]') +_THAT_ONE_BROKEN_CLOSE_IN_WEB_SOCKETS_PATTERN = re.compile( + r'^\[error\] The name \'close\' is already defined') + +def main(args): + cmd = [ + "../../third_party/dart-sdk/dart-sdk/bin/dartanalyzer", + ] + + gen_dir = args.pop(0) + stamp_file = args.pop(0) + cmd.extend(args) + cmd.append("--package-root=%s" % gen_dir) + + passed = True + try: + subprocess.check_output(cmd, shell=False, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + # Perform post processing on the output. Filter out non-error messages and + # known problem patterns that we're working on. + raw_lines = e.output.split('\n') + # Remove the last empty line + raw_lines.pop() + filtered_lines = [i for i in raw_lines if ( + not re.match(_ANALYZING_PATTERN, i) and + not re.match(_FINAL_REPORT_PATTERN, i) and + # TODO(erg): Remove the rest of these as fixes land: + not re.match(_WARNING_PATTERN, i) and + not re.match(_NATIVE_ERROR_PATTERN, i) and + not re.match(_THAT_ONE_BROKEN_CLOSE_IN_WEB_SOCKETS_PATTERN, i))] + for line in filtered_lines: + passed = False + print >> sys.stderr, line + + if passed: + # We passed cleanly, so touch the stamp file so that we don't run again. + with open(stamp_file, 'a'): + os.utime(stamp_file, None) + return 0 + else: + return -2 + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:]))
diff --git a/third_party/mojo/src/mojo/public/tools/download_network_service.py b/third_party/mojo/src/mojo/public/tools/download_network_service.py new file mode 100755 index 0000000..43b1172 --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/download_network_service.py
@@ -0,0 +1,89 @@ +#!/usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import argparse +import os +import sys +import tempfile +import zipfile + +_PLATFORMS = ["linux-x64", "android-arm"] +_APPS = ["network_service", "network_service_apptests"] +_CURRENT_PATH = os.path.dirname(os.path.realpath(__file__)) +sys.path.insert(0, os.path.join(_CURRENT_PATH, "pylib")) +import gs + +if not sys.platform.startswith("linux"): + print "Not supported for your platform" + sys.exit(0) + +script_dir = os.path.dirname(os.path.realpath(__file__)) + + +def download_app(app, version, tools_directory): + prebuilt_directory = os.path.join(script_dir, "prebuilt/%s" % app) + stamp_path = os.path.join(prebuilt_directory, "VERSION") + + try: + with open(stamp_path) as stamp_file: + current_version = stamp_file.read().strip() + if current_version == version: + return # Already have the right version. + except IOError: + pass # If the stamp file does not exist we need to download a new binary. + + for platform in _PLATFORMS: + download_app_for_platform(app, version, platform, tools_directory) + + with open(stamp_path, 'w') as stamp_file: + stamp_file.write(version) + +def download_app_for_platform(app, version, platform, tools_directory): + find_depot_tools_path = os.path.join(_CURRENT_PATH, tools_directory) + sys.path.insert(0, find_depot_tools_path) + # pylint: disable=F0401 + import find_depot_tools + depot_tools_path = find_depot_tools.add_depot_tools_to_path() + + binary_name = app + ".mojo" + gs_path = "gs://mojo/%s/%s/%s/%s.zip" % (app, version, platform, binary_name) + output_directory = os.path.join(script_dir, + "prebuilt/%s/%s" % (app, platform)) + + with tempfile.NamedTemporaryFile() as temp_zip_file: + gs.download_from_public_bucket(gs_path, temp_zip_file.name, + depot_tools_path) + with zipfile.ZipFile(temp_zip_file.name) as z: + zi = z.getinfo(binary_name) + mode = zi.external_attr >> 16 + z.extract(zi, output_directory) + os.chmod(os.path.join(output_directory, binary_name), mode) + +def main(): + parser = argparse.ArgumentParser( + description="Download prebuilt network service binaries from google " + + "storage") + parser.add_argument("--tools-directory", + dest="tools_directory", + metavar="<tools-directory>", + type=str, + required=True, + help="Path to the directory containing " + "find_depot_tools.py, specified as a relative path " + "from the location of this file.") + args = parser.parse_args() + + version_path = os.path.join(script_dir, "NETWORK_SERVICE_VERSION") + with open(version_path) as version_file: + version = version_file.read().strip() + + for app in _APPS: + download_app(app, version, args.tools_directory) + + return 0 + + +if __name__ == "__main__": + sys.exit(main())
diff --git a/third_party/mojo/src/mojo/public/tools/download_shell_binary.py b/third_party/mojo/src/mojo/public/tools/download_shell_binary.py index ee74231..c8f0f40 100755 --- a/third_party/mojo/src/mojo/public/tools/download_shell_binary.py +++ b/third_party/mojo/src/mojo/public/tools/download_shell_binary.py
@@ -20,13 +20,16 @@ sys.exit(0) CURRENT_PATH = os.path.dirname(os.path.realpath(__file__)) -PREBUILT_FILE_PATH = os.path.join(CURRENT_PATH, "prebuilt") +sys.path.insert(0, os.path.join(CURRENT_PATH, "pylib")) +import gs + +PREBUILT_FILE_PATH = os.path.join(CURRENT_PATH, "prebuilt", "shell") -def download(tools_directory): +def download(tools_directory, version_file): stamp_path = os.path.join(PREBUILT_FILE_PATH, "VERSION") - version_path = os.path.join(CURRENT_PATH, "../VERSION") + version_path = os.path.join(CURRENT_PATH, version_file) with open(version_path) as version_file: version = version_file.read().strip() @@ -50,44 +53,21 @@ sys.path.insert(0, find_depot_tools_path) # pylint: disable=F0401 import find_depot_tools + depot_tools_path = find_depot_tools.add_depot_tools_to_path() basename = platform + ".zip" gs_path = "gs://mojo/shell/" + version + "/" + basename - depot_tools_path = find_depot_tools.add_depot_tools_to_path() - gsutil_exe = os.path.join(depot_tools_path, "third_party", "gsutil", "gsutil") - with tempfile.NamedTemporaryFile() as temp_zip_file: - # We're downloading from a public bucket which does not need authentication, - # but the user might have busted credential files somewhere such as ~/.boto - # that the gsutil script will try (and fail) to use. Setting these - # environment variables convinces gsutil not to attempt to use these, but - # also generates a useless warning about failing to load the file. We want - # to discard this warning but still preserve all output in the case of an - # actual failure. So, we run the script and capture all output and then - # throw the output away if the script succeeds (return code 0). - env = os.environ.copy() - env["AWS_CREDENTIAL_FILE"] = "" - env["BOTO_CONFIG"] = "" - try: - subprocess.check_output( - [gsutil_exe, - "--bypass_prodaccess", - "cp", - gs_path, - temp_zip_file.name], - stderr=subprocess.STDOUT, - env=env) - except subprocess.CalledProcessError as e: - print e.output - sys.exit(1) - + gs.download_from_public_bucket(gs_path, temp_zip_file.name, + depot_tools_path) binary_name = BINARY_FOR_PLATFORM[platform] + output_dir = os.path.join(PREBUILT_FILE_PATH, platform) with zipfile.ZipFile(temp_zip_file.name) as z: zi = z.getinfo(binary_name) mode = zi.external_attr >> 16 - z.extract(zi, PREBUILT_FILE_PATH) - os.chmod(os.path.join(PREBUILT_FILE_PATH, binary_name), mode) + z.extract(zi, output_dir) + os.chmod(os.path.join(output_dir, binary_name), mode) def main(): @@ -97,14 +77,21 @@ dest="tools_directory", metavar="<tools-directory>", type=str, - help="Path to the directory containing" - " find_depot_tools.py, specified as a relative path" - " from the location of this file.") + required=True, + help="Path to the directory containing " + "find_depot_tools.py, specified as a relative path " + "from the location of this file.") + parser.add_argument("--version-file", + dest="version_file", + metavar="<version-file>", + type=str, + default="../VERSION", + help="Path to the file containing the version of the " + "shell to be fetched, specified as a relative path " + "from the location of this file (default: " + "%(default)s).") args = parser.parse_args() - if not args.tools_directory: - print "Must specify --tools_directory; please see help message." - sys.exit(1) - return download(args.tools_directory) + return download(args.tools_directory, args.version_file) if __name__ == "__main__": sys.exit(main())
diff --git a/third_party/mojo/src/mojo/public/tools/gn/zip.py b/third_party/mojo/src/mojo/public/tools/gn/zip.py index c703144..506eb9e 100755 --- a/third_party/mojo/src/mojo/public/tools/gn/zip.py +++ b/third_party/mojo/src/mojo/public/tools/gn/zip.py
@@ -41,7 +41,9 @@ options, _ = parser.parse_args() - inputs = ast.literal_eval(options.inputs) + inputs = [] + if (options.inputs): + inputs = ast.literal_eval(options.inputs) zip_inputs = [] if options.zip_inputs: zip_inputs = ast.literal_eval(options.zip_inputs)
diff --git a/third_party/mojo/src/mojo/public/tools/pylib/gs.py b/third_party/mojo/src/mojo/public/tools/pylib/gs.py new file mode 100644 index 0000000..f8761b5 --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/pylib/gs.py
@@ -0,0 +1,34 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import subprocess +import sys + +def download_from_public_bucket(gs_path, output_path, depot_tools_path): + gsutil_exe = os.path.join(depot_tools_path, "third_party", "gsutil", "gsutil") + + # We're downloading from a public bucket which does not need authentication, + # but the user might have busted credential files somewhere such as ~/.boto + # that the gsutil script will try (and fail) to use. Setting these + # environment variables convinces gsutil not to attempt to use these, but + # also generates a useless warning about failing to load the file. We want + # to discard this warning but still preserve all output in the case of an + # actual failure. So, we run the script and capture all output and then + # throw the output away if the script succeeds (return code 0). + env = os.environ.copy() + env["AWS_CREDENTIAL_FILE"] = "" + env["BOTO_CONFIG"] = "" + try: + subprocess.check_output( + [gsutil_exe, + "--bypass_prodaccess", + "cp", + gs_path, + output_path], + stderr=subprocess.STDOUT, + env=env) + except subprocess.CalledProcessError as e: + print e.output + sys.exit(1)
diff --git a/third_party/mojo/src/nacl_bindings/BUILD.gn b/third_party/mojo/src/nacl_bindings/BUILD.gn new file mode 100644 index 0000000..84920ee --- /dev/null +++ b/third_party/mojo/src/nacl_bindings/BUILD.gn
@@ -0,0 +1,42 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Trusted code +if (!is_nacl) { + # A library for launching a NaCl sandbox connected to a Mojo embedder. + source_set("monacl_sel") { + sources = [ + "mojo_syscall_internal.h", + "mojo_syscall.cc", + "monacl_sel_main.cc", + ] + deps = [ + "../mojo/public/c/system", + + # This target makes sure we have all the pre-processor defines needed to + # use NaCl's headers. + "//native_client/build/config/nacl:nacl_base", + "//native_client/src/trusted/desc:nrd_xfer", + "//native_client/src/trusted/service_runtime:sel_main_chrome", + ] + } +} + +# Untrusted code +if (is_nacl) { + executable("irt_mojo") { + cflags_c = [ "-std=c99" ] + sources = [ + "../mojo/public/platform/nacl/mojo_irt.h", + "irt_entry_mojo.c", + "mojo_irt.c", + ] + deps = [ + "../mojo/public/c/system", + "//native_client/build/config/nacl:nacl_base", + "//native_client/src/untrusted/irt:irt_core_lib", + "//native_client/src/untrusted/nacl:imc_syscalls", + ] + } +}
diff --git a/third_party/mojo/src/nacl_bindings/irt_entry_mojo.c b/third_party/mojo/src/nacl_bindings/irt_entry_mojo.c new file mode 100644 index 0000000..5c413dd --- /dev/null +++ b/third_party/mojo/src/nacl_bindings/irt_entry_mojo.c
@@ -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 "mojo/public/platform/nacl/mojo_irt.h" +#include "native_client/src/public/irt_core.h" + +static size_t irt_query(const char* interface_ident, + void* table, size_t tablesize) { + // TODO(teravest): Add query for the Mojo IRT interface, when introduced. + size_t rc = mojo_irt_query(interface_ident, table, tablesize); + if (rc != 0) + return rc; + + return nacl_irt_query_core(interface_ident, table, tablesize); +} + +void nacl_irt_start(uint32_t* info) { + nacl_irt_init(info); + nacl_irt_enter_user_code(info, irt_query); +}
diff --git a/third_party/mojo/src/nacl_bindings/mojo_irt.c b/third_party/mojo/src/nacl_bindings/mojo_irt.c new file mode 100644 index 0000000..3595f0b --- /dev/null +++ b/third_party/mojo/src/nacl_bindings/mojo_irt.c
@@ -0,0 +1,357 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// WARNING this file was generated by generate_nacl_bindings.py +// Do not edit by hand. + +#include <stdio.h> +#include <string.h> + +#include "mojo/public/c/system/core.h" +#include "mojo/public/platform/nacl/mojo_irt.h" +#include "native_client/src/public/chrome_main.h" +#include "native_client/src/public/imc_syscalls.h" +#include "native_client/src/public/imc_types.h" +#include "native_client/src/public/irt_core.h" + +#define NACL_MOJO_DESC (NACL_CHROME_DESC_BASE + 3) + +static void DoMojoCall(uint32_t params[], nacl_abi_size_t num_params) { + struct NaClAbiNaClImcMsgIoVec iov[1] = { + {params, num_params} + }; + struct NaClAbiNaClImcMsgHdr msgh = {iov, 1, NULL, 0}; + // Note: return value unchecked. We're relying on the result parameter being + // unmodified - if the syscall fails, the Mojo function will return whatever + // the result parameter was initialized to before this function was called. + imc_sendmsg(NACL_MOJO_DESC, &msgh, 0); +} + +static MojoResult irt_MojoCreateSharedBuffer( + const struct MojoCreateSharedBufferOptions* options, + uint64_t num_bytes, + MojoHandle* shared_buffer_handle) { + uint32_t params[5]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 0; + params[1] = (uint32_t)(options); + params[2] = (uint32_t)(&num_bytes); + params[3] = (uint32_t)(shared_buffer_handle); + params[4] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoDuplicateBufferHandle( + MojoHandle buffer_handle, + const struct MojoDuplicateBufferHandleOptions* options, + MojoHandle* new_buffer_handle) { + uint32_t params[5]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 1; + params[1] = (uint32_t)(&buffer_handle); + params[2] = (uint32_t)(options); + params[3] = (uint32_t)(new_buffer_handle); + params[4] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoMapBuffer( + MojoHandle buffer_handle, + uint64_t offset, + uint64_t num_bytes, + void** buffer, + MojoMapBufferFlags flags) { + uint32_t params[7]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 2; + params[1] = (uint32_t)(&buffer_handle); + params[2] = (uint32_t)(&offset); + params[3] = (uint32_t)(&num_bytes); + params[4] = (uint32_t)(buffer); + params[5] = (uint32_t)(&flags); + params[6] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoUnmapBuffer(void* buffer) { + uint32_t params[3]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 3; + params[1] = (uint32_t)(&buffer); + params[2] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoCreateDataPipe( + const struct MojoCreateDataPipeOptions* options, + MojoHandle* data_pipe_producer_handle, + MojoHandle* data_pipe_consumer_handle) { + uint32_t params[5]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 4; + params[1] = (uint32_t)(options); + params[2] = (uint32_t)(data_pipe_producer_handle); + params[3] = (uint32_t)(data_pipe_consumer_handle); + params[4] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoWriteData( + MojoHandle data_pipe_producer_handle, + const void* elements, + uint32_t* num_bytes, + MojoWriteDataFlags flags) { + uint32_t params[6]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 5; + params[1] = (uint32_t)(&data_pipe_producer_handle); + params[2] = (uint32_t)(elements); + params[3] = (uint32_t)(num_bytes); + params[4] = (uint32_t)(&flags); + params[5] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoBeginWriteData( + MojoHandle data_pipe_producer_handle, + void** buffer, + uint32_t* buffer_num_bytes, + MojoWriteDataFlags flags) { + uint32_t params[6]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 6; + params[1] = (uint32_t)(&data_pipe_producer_handle); + params[2] = (uint32_t)(buffer); + params[3] = (uint32_t)(buffer_num_bytes); + params[4] = (uint32_t)(&flags); + params[5] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoEndWriteData( + MojoHandle data_pipe_producer_handle, + uint32_t num_bytes_written) { + uint32_t params[4]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 7; + params[1] = (uint32_t)(&data_pipe_producer_handle); + params[2] = (uint32_t)(&num_bytes_written); + params[3] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoReadData( + MojoHandle data_pipe_consumer_handle, + void* elements, + uint32_t* num_bytes, + MojoReadDataFlags flags) { + uint32_t params[6]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 8; + params[1] = (uint32_t)(&data_pipe_consumer_handle); + params[2] = (uint32_t)(elements); + params[3] = (uint32_t)(num_bytes); + params[4] = (uint32_t)(&flags); + params[5] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoBeginReadData( + MojoHandle data_pipe_consumer_handle, + const void** buffer, + uint32_t* buffer_num_bytes, + MojoReadDataFlags flags) { + uint32_t params[6]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 9; + params[1] = (uint32_t)(&data_pipe_consumer_handle); + params[2] = (uint32_t)(buffer); + params[3] = (uint32_t)(buffer_num_bytes); + params[4] = (uint32_t)(&flags); + params[5] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoEndReadData( + MojoHandle data_pipe_consumer_handle, + uint32_t num_bytes_read) { + uint32_t params[4]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 10; + params[1] = (uint32_t)(&data_pipe_consumer_handle); + params[2] = (uint32_t)(&num_bytes_read); + params[3] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoTimeTicks irt_MojoGetTimeTicksNow() { + uint32_t params[2]; + MojoTimeTicks result = 0; + params[0] = 11; + params[1] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoClose(MojoHandle handle) { + uint32_t params[3]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 12; + params[1] = (uint32_t)(&handle); + params[2] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoWait( + MojoHandle handle, + MojoHandleSignals signals, + MojoDeadline deadline, + struct MojoHandleSignalsState* signals_state) { + uint32_t params[6]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 13; + params[1] = (uint32_t)(&handle); + params[2] = (uint32_t)(&signals); + params[3] = (uint32_t)(&deadline); + params[4] = (uint32_t)(signals_state); + params[5] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoWaitMany( + const MojoHandle* handles, + const MojoHandleSignals* signals, + uint32_t num_handles, + MojoDeadline deadline, + uint32_t* result_index, + struct MojoHandleSignalsState* signals_states) { + uint32_t params[8]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 14; + params[1] = (uint32_t)(handles); + params[2] = (uint32_t)(signals); + params[3] = (uint32_t)(&num_handles); + params[4] = (uint32_t)(&deadline); + params[5] = (uint32_t)(result_index); + params[6] = (uint32_t)(signals_states); + params[7] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoCreateMessagePipe( + const struct MojoCreateMessagePipeOptions* options, + MojoHandle* message_pipe_handle0, + MojoHandle* message_pipe_handle1) { + uint32_t params[5]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 15; + params[1] = (uint32_t)(options); + params[2] = (uint32_t)(message_pipe_handle0); + params[3] = (uint32_t)(message_pipe_handle1); + params[4] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoWriteMessage( + MojoHandle message_pipe_handle, + const void* bytes, + uint32_t num_bytes, + const MojoHandle* handles, + uint32_t num_handles, + MojoWriteMessageFlags flags) { + uint32_t params[8]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 16; + params[1] = (uint32_t)(&message_pipe_handle); + params[2] = (uint32_t)(bytes); + params[3] = (uint32_t)(&num_bytes); + params[4] = (uint32_t)(handles); + params[5] = (uint32_t)(&num_handles); + params[6] = (uint32_t)(&flags); + params[7] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt_MojoReadMessage( + MojoHandle message_pipe_handle, + void* bytes, + uint32_t* num_bytes, + MojoHandle* handles, + uint32_t* num_handles, + MojoReadMessageFlags flags) { + uint32_t params[8]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 17; + params[1] = (uint32_t)(&message_pipe_handle); + params[2] = (uint32_t)(bytes); + params[3] = (uint32_t)(num_bytes); + params[4] = (uint32_t)(handles); + params[5] = (uint32_t)(num_handles); + params[6] = (uint32_t)(&flags); + params[7] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +static MojoResult irt__MojoGetInitialHandle(MojoHandle* handle) { + uint32_t params[3]; + MojoResult result = MOJO_RESULT_INVALID_ARGUMENT; + params[0] = 18; + params[1] = (uint32_t)(handle); + params[2] = (uint32_t)(&result); + DoMojoCall(params, sizeof(params)); + return result; +}; + +struct nacl_irt_mojo kIrtMojo = { + &irt_MojoCreateSharedBuffer, + &irt_MojoDuplicateBufferHandle, + &irt_MojoMapBuffer, + &irt_MojoUnmapBuffer, + &irt_MojoCreateDataPipe, + &irt_MojoWriteData, + &irt_MojoBeginWriteData, + &irt_MojoEndWriteData, + &irt_MojoReadData, + &irt_MojoBeginReadData, + &irt_MojoEndReadData, + &irt_MojoGetTimeTicksNow, + &irt_MojoClose, + &irt_MojoWait, + &irt_MojoWaitMany, + &irt_MojoCreateMessagePipe, + &irt_MojoWriteMessage, + &irt_MojoReadMessage, + &irt__MojoGetInitialHandle, +}; + + +size_t mojo_irt_query(const char* interface_ident, + void* table, + size_t tablesize) { + static const size_t size = sizeof(kIrtMojo); + if (0 == strcmp(interface_ident, NACL_IRT_MOJO_v0_1)) { + if (size <= tablesize) { + memcpy(table, &kIrtMojo, size); + return size; + } + } + return 0; +}
diff --git a/third_party/mojo/src/nacl_bindings/mojo_syscall.cc b/third_party/mojo/src/nacl_bindings/mojo_syscall.cc new file mode 100644 index 0000000..34fcccb --- /dev/null +++ b/third_party/mojo/src/nacl_bindings/mojo_syscall.cc
@@ -0,0 +1,879 @@ +// 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. + +// WARNING this file was generated by generate_nacl_bindings.py +// Do not edit by hand. + +#include "nacl_bindings/mojo_syscall.h" + +#include <stdio.h> + +#include "mojo/public/c/system/core.h" +#include "nacl_bindings/mojo_syscall_internal.h" +#include "native_client/src/public/chrome_main.h" +#include "native_client/src/public/nacl_app.h" +#include "native_client/src/trusted/desc/nacl_desc_custom.h" + +MojoHandle g_mojo_handle = MOJO_HANDLE_INVALID; + +namespace { + +MojoResult _MojoGetInitialHandle(MojoHandle* handle) { + *handle = g_mojo_handle; + return MOJO_RESULT_OK; +} + +void MojoDescDestroy(void* handle) { +} + +ssize_t MojoDescSendMsg(void* handle, + const struct NaClImcTypedMsgHdr* msg, + int flags) { + struct NaClApp* nap = static_cast<struct NaClApp*>(handle); + + if (msg->iov_length != 1 || msg->ndesc_length != 0) { + return -1; + } + + uint32_t volatile* params = static_cast<uint32_t volatile*>(msg->iov[0].base); + size_t num_params = msg->iov[0].length / sizeof(*params); + + if (num_params < 1) { + return -1; + } + + uint32_t msg_type = params[0]; + switch (msg_type) { + case 0: { + if (num_params != 5) { + return -1; + } + const struct MojoCreateSharedBufferOptions* options; + uint64_t num_bytes_value; + MojoHandle volatile* shared_buffer_handle_ptr; + MojoHandle shared_buffer_handle_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertExtensibleStructInput(nap, params[1], true, &options)) { + return -1; + } + if (!ConvertScalarInput(nap, params[2], &num_bytes_value)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[3], false, + &shared_buffer_handle_value, + &shared_buffer_handle_ptr)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[4], false, &result_ptr)) { + return -1; + } + } + + result_value = MojoCreateSharedBuffer(options, num_bytes_value, + &shared_buffer_handle_value); + + { + ScopedCopyLock copy_lock(nap); + *shared_buffer_handle_ptr = shared_buffer_handle_value; + *result_ptr = result_value; + } + + return 0; + } + case 1: { + if (num_params != 5) { + return -1; + } + MojoHandle buffer_handle_value; + const struct MojoDuplicateBufferHandleOptions* options; + MojoHandle volatile* new_buffer_handle_ptr; + MojoHandle new_buffer_handle_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], &buffer_handle_value)) { + return -1; + } + if (!ConvertExtensibleStructInput(nap, params[2], true, &options)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[3], false, &new_buffer_handle_value, + &new_buffer_handle_ptr)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[4], false, &result_ptr)) { + return -1; + } + } + + result_value = MojoDuplicateBufferHandle(buffer_handle_value, options, + &new_buffer_handle_value); + + { + ScopedCopyLock copy_lock(nap); + *new_buffer_handle_ptr = new_buffer_handle_value; + *result_ptr = result_value; + } + + return 0; + } + case 2: { + if (num_params != 7) { + return -1; + } + MojoHandle buffer_handle_value; + uint64_t offset_value; + uint64_t num_bytes_value; + void* volatile* buffer_ptr; + void* buffer_value; + MojoMapBufferFlags flags_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], &buffer_handle_value)) { + return -1; + } + if (!ConvertScalarInput(nap, params[2], &offset_value)) { + return -1; + } + if (!ConvertScalarInput(nap, params[3], &num_bytes_value)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[4], false, &buffer_value, + &buffer_ptr)) { + return -1; + } + if (!ConvertScalarInput(nap, params[5], &flags_value)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[6], false, &result_ptr)) { + return -1; + } + } + + result_value = MojoMapBuffer(buffer_handle_value, offset_value, + num_bytes_value, &buffer_value, flags_value); + + { + ScopedCopyLock copy_lock(nap); + *buffer_ptr = buffer_value; + *result_ptr = result_value; + } + + return 0; + } + case 3: { + if (num_params != 3) { + return -1; + } + void* buffer_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], &buffer_value)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[2], false, &result_ptr)) { + return -1; + } + } + + result_value = MojoUnmapBuffer(buffer_value); + + { + ScopedCopyLock copy_lock(nap); + *result_ptr = result_value; + } + + return 0; + } + case 4: { + if (num_params != 5) { + return -1; + } + const struct MojoCreateDataPipeOptions* options; + MojoHandle volatile* data_pipe_producer_handle_ptr; + MojoHandle data_pipe_producer_handle_value; + MojoHandle volatile* data_pipe_consumer_handle_ptr; + MojoHandle data_pipe_consumer_handle_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertExtensibleStructInput(nap, params[1], true, &options)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[2], false, + &data_pipe_producer_handle_value, + &data_pipe_producer_handle_ptr)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[3], false, + &data_pipe_consumer_handle_value, + &data_pipe_consumer_handle_ptr)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[4], false, &result_ptr)) { + return -1; + } + } + + result_value = + MojoCreateDataPipe(options, &data_pipe_producer_handle_value, + &data_pipe_consumer_handle_value); + + { + ScopedCopyLock copy_lock(nap); + *data_pipe_producer_handle_ptr = data_pipe_producer_handle_value; + *data_pipe_consumer_handle_ptr = data_pipe_consumer_handle_value; + *result_ptr = result_value; + } + + return 0; + } + case 5: { + if (num_params != 6) { + return -1; + } + MojoHandle data_pipe_producer_handle_value; + const void* elements; + uint32_t volatile* num_bytes_ptr; + uint32_t num_bytes_value; + MojoWriteDataFlags flags_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], + &data_pipe_producer_handle_value)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[3], false, &num_bytes_value, + &num_bytes_ptr)) { + return -1; + } + if (!ConvertScalarInput(nap, params[4], &flags_value)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[5], false, &result_ptr)) { + return -1; + } + if (!ConvertArray(nap, params[2], num_bytes_value, 1, false, + &elements)) { + return -1; + } + } + + result_value = MojoWriteData(data_pipe_producer_handle_value, elements, + &num_bytes_value, flags_value); + + { + ScopedCopyLock copy_lock(nap); + *num_bytes_ptr = num_bytes_value; + *result_ptr = result_value; + } + + return 0; + } + case 6: { + if (num_params != 6) { + return -1; + } + MojoHandle data_pipe_producer_handle_value; + void* volatile* buffer_ptr; + void* buffer_value; + uint32_t volatile* buffer_num_bytes_ptr; + uint32_t buffer_num_bytes_value; + MojoWriteDataFlags flags_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], + &data_pipe_producer_handle_value)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[2], false, &buffer_value, + &buffer_ptr)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[3], false, &buffer_num_bytes_value, + &buffer_num_bytes_ptr)) { + return -1; + } + if (!ConvertScalarInput(nap, params[4], &flags_value)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[5], false, &result_ptr)) { + return -1; + } + } + + result_value = + MojoBeginWriteData(data_pipe_producer_handle_value, &buffer_value, + &buffer_num_bytes_value, flags_value); + + { + ScopedCopyLock copy_lock(nap); + *buffer_ptr = buffer_value; + *buffer_num_bytes_ptr = buffer_num_bytes_value; + *result_ptr = result_value; + } + + return 0; + } + case 7: { + if (num_params != 4) { + return -1; + } + MojoHandle data_pipe_producer_handle_value; + uint32_t num_bytes_written_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], + &data_pipe_producer_handle_value)) { + return -1; + } + if (!ConvertScalarInput(nap, params[2], &num_bytes_written_value)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[3], false, &result_ptr)) { + return -1; + } + } + + result_value = MojoEndWriteData(data_pipe_producer_handle_value, + num_bytes_written_value); + + { + ScopedCopyLock copy_lock(nap); + *result_ptr = result_value; + } + + return 0; + } + case 8: { + if (num_params != 6) { + return -1; + } + MojoHandle data_pipe_consumer_handle_value; + void* elements; + uint32_t volatile* num_bytes_ptr; + uint32_t num_bytes_value; + MojoReadDataFlags flags_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], + &data_pipe_consumer_handle_value)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[3], false, &num_bytes_value, + &num_bytes_ptr)) { + return -1; + } + if (!ConvertScalarInput(nap, params[4], &flags_value)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[5], false, &result_ptr)) { + return -1; + } + if (!ConvertArray(nap, params[2], num_bytes_value, 1, false, + &elements)) { + return -1; + } + } + + result_value = MojoReadData(data_pipe_consumer_handle_value, elements, + &num_bytes_value, flags_value); + + { + ScopedCopyLock copy_lock(nap); + *num_bytes_ptr = num_bytes_value; + *result_ptr = result_value; + } + + return 0; + } + case 9: { + if (num_params != 6) { + return -1; + } + MojoHandle data_pipe_consumer_handle_value; + const void* volatile* buffer_ptr; + const void* buffer_value; + uint32_t volatile* buffer_num_bytes_ptr; + uint32_t buffer_num_bytes_value; + MojoReadDataFlags flags_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], + &data_pipe_consumer_handle_value)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[2], false, &buffer_value, + &buffer_ptr)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[3], false, &buffer_num_bytes_value, + &buffer_num_bytes_ptr)) { + return -1; + } + if (!ConvertScalarInput(nap, params[4], &flags_value)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[5], false, &result_ptr)) { + return -1; + } + } + + result_value = + MojoBeginReadData(data_pipe_consumer_handle_value, &buffer_value, + &buffer_num_bytes_value, flags_value); + + { + ScopedCopyLock copy_lock(nap); + *buffer_ptr = buffer_value; + *buffer_num_bytes_ptr = buffer_num_bytes_value; + *result_ptr = result_value; + } + + return 0; + } + case 10: { + if (num_params != 4) { + return -1; + } + MojoHandle data_pipe_consumer_handle_value; + uint32_t num_bytes_read_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], + &data_pipe_consumer_handle_value)) { + return -1; + } + if (!ConvertScalarInput(nap, params[2], &num_bytes_read_value)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[3], false, &result_ptr)) { + return -1; + } + } + + result_value = MojoEndReadData(data_pipe_consumer_handle_value, + num_bytes_read_value); + + { + ScopedCopyLock copy_lock(nap); + *result_ptr = result_value; + } + + return 0; + } + case 11: { + if (num_params != 2) { + return -1; + } + MojoTimeTicks volatile* result_ptr; + MojoTimeTicks result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarOutput(nap, params[1], false, &result_ptr)) { + return -1; + } + } + + result_value = MojoGetTimeTicksNow(); + + { + ScopedCopyLock copy_lock(nap); + *result_ptr = result_value; + } + + return 0; + } + case 12: { + if (num_params != 3) { + return -1; + } + MojoHandle handle_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], &handle_value)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[2], false, &result_ptr)) { + return -1; + } + } + + result_value = MojoClose(handle_value); + + { + ScopedCopyLock copy_lock(nap); + *result_ptr = result_value; + } + + return 0; + } + case 13: { + if (num_params != 6) { + return -1; + } + MojoHandle handle_value; + MojoHandleSignals signals_value; + MojoDeadline deadline_value; + MojoHandleSignalsState volatile* signals_state_ptr; + MojoHandleSignalsState signals_state_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], &handle_value)) { + return -1; + } + if (!ConvertScalarInput(nap, params[2], &signals_value)) { + return -1; + } + if (!ConvertScalarInput(nap, params[3], &deadline_value)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[4], true, &signals_state_ptr)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[5], false, &result_ptr)) { + return -1; + } + } + + result_value = MojoWait(handle_value, signals_value, deadline_value, + signals_state_ptr ? &signals_state_value : NULL); + + { + ScopedCopyLock copy_lock(nap); + if (signals_state_ptr != NULL) { + memcpy_volatile_out(signals_state_ptr, &signals_state_value, + sizeof(MojoHandleSignalsState)); + } + *result_ptr = result_value; + } + + return 0; + } + case 14: { + if (num_params != 8) { + return -1; + } + const MojoHandle* handles; + const MojoHandleSignals* signals; + uint32_t num_handles_value; + MojoDeadline deadline_value; + uint32_t volatile* result_index_ptr; + uint32_t result_index_value; + struct MojoHandleSignalsState* signals_states; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[3], &num_handles_value)) { + return -1; + } + if (!ConvertScalarInput(nap, params[4], &deadline_value)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[5], true, &result_index_value, + &result_index_ptr)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[7], false, &result_ptr)) { + return -1; + } + if (!ConvertArray(nap, params[1], num_handles_value, sizeof(*handles), + false, &handles)) { + return -1; + } + if (!ConvertArray(nap, params[2], num_handles_value, sizeof(*signals), + false, &signals)) { + return -1; + } + if (!ConvertArray(nap, params[6], num_handles_value, + sizeof(*signals_states), true, &signals_states)) { + return -1; + } + } + + result_value = MojoWaitMany( + handles, signals, num_handles_value, deadline_value, + result_index_ptr ? &result_index_value : NULL, signals_states); + + { + ScopedCopyLock copy_lock(nap); + if (result_index_ptr != NULL) { + *result_index_ptr = result_index_value; + } + *result_ptr = result_value; + } + + return 0; + } + case 15: { + if (num_params != 5) { + return -1; + } + const struct MojoCreateMessagePipeOptions* options; + MojoHandle volatile* message_pipe_handle0_ptr; + MojoHandle message_pipe_handle0_value; + MojoHandle volatile* message_pipe_handle1_ptr; + MojoHandle message_pipe_handle1_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertExtensibleStructInput(nap, params[1], true, &options)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[2], false, + &message_pipe_handle0_value, + &message_pipe_handle0_ptr)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[3], false, + &message_pipe_handle1_value, + &message_pipe_handle1_ptr)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[4], false, &result_ptr)) { + return -1; + } + } + + result_value = MojoCreateMessagePipe(options, &message_pipe_handle0_value, + &message_pipe_handle1_value); + + { + ScopedCopyLock copy_lock(nap); + *message_pipe_handle0_ptr = message_pipe_handle0_value; + *message_pipe_handle1_ptr = message_pipe_handle1_value; + *result_ptr = result_value; + } + + return 0; + } + case 16: { + if (num_params != 8) { + return -1; + } + MojoHandle message_pipe_handle_value; + const void* bytes; + uint32_t num_bytes_value; + const MojoHandle* handles; + uint32_t num_handles_value; + MojoWriteMessageFlags flags_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], &message_pipe_handle_value)) { + return -1; + } + if (!ConvertScalarInput(nap, params[3], &num_bytes_value)) { + return -1; + } + if (!ConvertScalarInput(nap, params[5], &num_handles_value)) { + return -1; + } + if (!ConvertScalarInput(nap, params[6], &flags_value)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[7], false, &result_ptr)) { + return -1; + } + if (!ConvertArray(nap, params[2], num_bytes_value, 1, true, &bytes)) { + return -1; + } + if (!ConvertArray(nap, params[4], num_handles_value, sizeof(*handles), + true, &handles)) { + return -1; + } + } + + result_value = + MojoWriteMessage(message_pipe_handle_value, bytes, num_bytes_value, + handles, num_handles_value, flags_value); + + { + ScopedCopyLock copy_lock(nap); + *result_ptr = result_value; + } + + return 0; + } + case 17: { + if (num_params != 8) { + return -1; + } + MojoHandle message_pipe_handle_value; + void* bytes; + uint32_t volatile* num_bytes_ptr; + uint32_t num_bytes_value; + MojoHandle* handles; + uint32_t volatile* num_handles_ptr; + uint32_t num_handles_value; + MojoReadMessageFlags flags_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInput(nap, params[1], &message_pipe_handle_value)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[3], true, &num_bytes_value, + &num_bytes_ptr)) { + return -1; + } + if (!ConvertScalarInOut(nap, params[5], true, &num_handles_value, + &num_handles_ptr)) { + return -1; + } + if (!ConvertScalarInput(nap, params[6], &flags_value)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[7], false, &result_ptr)) { + return -1; + } + if (!ConvertArray(nap, params[2], num_bytes_value, 1, true, &bytes)) { + return -1; + } + if (!ConvertArray(nap, params[4], num_handles_value, sizeof(*handles), + true, &handles)) { + return -1; + } + } + + result_value = MojoReadMessage( + message_pipe_handle_value, bytes, + num_bytes_ptr ? &num_bytes_value : NULL, handles, + num_handles_ptr ? &num_handles_value : NULL, flags_value); + + { + ScopedCopyLock copy_lock(nap); + if (num_bytes_ptr != NULL) { + *num_bytes_ptr = num_bytes_value; + } + if (num_handles_ptr != NULL) { + *num_handles_ptr = num_handles_value; + } + *result_ptr = result_value; + } + + return 0; + } + case 18: { + if (num_params != 3) { + return -1; + } + MojoHandle volatile* handle_ptr; + MojoHandle handle_value; + MojoResult volatile* result_ptr; + MojoResult result_value; + { + ScopedCopyLock copy_lock(nap); + if (!ConvertScalarInOut(nap, params[1], false, &handle_value, + &handle_ptr)) { + return -1; + } + if (!ConvertScalarOutput(nap, params[2], false, &result_ptr)) { + return -1; + } + } + + result_value = _MojoGetInitialHandle(&handle_value); + + { + ScopedCopyLock copy_lock(nap); + *handle_ptr = handle_value; + *result_ptr = result_value; + } + + return 0; + } + } + + return -1; +} + +ssize_t MojoDescRecvMsg(void* handle, + struct NaClImcTypedMsgHdr* msg, + int flags) { + return -1; +} + +struct NaClDesc* MakeMojoDesc(struct NaClApp* nap) { + struct NaClDescCustomFuncs funcs = NACL_DESC_CUSTOM_FUNCS_INITIALIZER; + funcs.Destroy = MojoDescDestroy; + funcs.SendMsg = MojoDescSendMsg; + funcs.RecvMsg = MojoDescRecvMsg; + return NaClDescMakeCustomDesc(nap, &funcs); +} + +void MojoDisabledDescDestroy(void* handle) { +} + +ssize_t MojoDisabledDescSendMsg(void* handle, + const struct NaClImcTypedMsgHdr* msg, + int flags) { + fprintf(stderr, "Mojo is not currently supported."); + abort(); +} + +ssize_t MojoDisabledDescRecvMsg(void* handle, + struct NaClImcTypedMsgHdr* msg, + int flags) { + fprintf(stderr, "Mojo is not currently supported."); + abort(); +} + +struct NaClDesc* MakeDisabledMojoDesc(struct NaClApp* nap) { + struct NaClDescCustomFuncs funcs = NACL_DESC_CUSTOM_FUNCS_INITIALIZER; + funcs.Destroy = MojoDisabledDescDestroy; + funcs.SendMsg = MojoDisabledDescSendMsg; + funcs.RecvMsg = MojoDisabledDescRecvMsg; + return NaClDescMakeCustomDesc(nap, &funcs); +} + +} // namespace + +// The value for this FD must not conflict with uses inside Chromium. However, +// mojo/nacl doesn't depend on any Chromium headers, so we can't use a #define +// from there. +#define NACL_MOJO_DESC (NACL_CHROME_DESC_BASE + 3) + +void InjectMojo(struct NaClApp* nap) { + NaClAppSetDesc(nap, NACL_MOJO_DESC, MakeMojoDesc(nap)); + g_mojo_handle = MOJO_HANDLE_INVALID; +} + +void InjectMojo(struct NaClApp* nap, MojoHandle handle) { + NaClAppSetDesc(nap, NACL_MOJO_DESC, MakeMojoDesc(nap)); + g_mojo_handle = handle; +} + +void InjectDisabledMojo(struct NaClApp* nap) { + NaClAppSetDesc(nap, NACL_MOJO_DESC, MakeDisabledMojoDesc(nap)); +}
diff --git a/third_party/mojo/src/nacl_bindings/mojo_syscall.h b/third_party/mojo/src/nacl_bindings/mojo_syscall.h new file mode 100644 index 0000000..700d191 --- /dev/null +++ b/third_party/mojo/src/nacl_bindings/mojo_syscall.h
@@ -0,0 +1,26 @@ +// 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 MOJO_NACL_MOJO_SYSCALL_H_ +#define MOJO_NACL_MOJO_SYSCALL_H_ + +#include "mojo/public/c/system/types.h" + +// Injects a NaClDesc for Mojo support and sets a MojoHandle to be provided to +// untrusted code as a "service provider" MojoHandle. This provides the +// implementation of the Mojo system API outside the NaCl sandbox and allows +// untrusted code to communicate with Mojo interfaces outside the sandbox or in +// other processes. +void InjectMojo(struct NaClApp* nap, MojoHandle handle); + +// Injects a NaClDesc for Mojo support. This provides the implementation of the +// Mojo system API outside the NaCl sandbox. +// TODO(teravest): Remove this once it is no longer called. +void InjectMojo(struct NaClApp* nap); + +// Injects a "disabled" NaClDesc for Mojo support. This is to make debugging +// more straightforward in the case where Mojo is not enabled for NaCl plugins. +void InjectDisabledMojo(struct NaClApp* nap); + +#endif // MOJO_NACL_MOJO_SYSCALL_H_
diff --git a/third_party/mojo/src/nacl_bindings/mojo_syscall_internal.h b/third_party/mojo/src/nacl_bindings/mojo_syscall_internal.h new file mode 100644 index 0000000..9200c1a --- /dev/null +++ b/third_party/mojo/src/nacl_bindings/mojo_syscall_internal.h
@@ -0,0 +1,170 @@ +// 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 MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_ +#define MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_ + +#include "native_client/src/trusted/service_runtime/nacl_copy.h" +#include "native_client/src/trusted/service_runtime/sel_ldr.h" + +namespace { + +class ScopedCopyLock { + public: + explicit ScopedCopyLock(struct NaClApp* nap) : nap_(nap) { + NaClCopyTakeLock(nap_); + } + ~ScopedCopyLock() { NaClCopyDropLock(nap_); } + + private: + struct NaClApp* nap_; +}; + +static inline uintptr_t NaClUserToSysAddrArray(struct NaClApp* nap, + uint32_t uaddr, + size_t count, + size_t size) { + // TODO(ncbray): overflow checking + size_t range = count * size; + return NaClUserToSysAddrRange(nap, uaddr, range); +} + +// We don't use plain-old memcpy because reads and writes to the untrusted +// address space from trusted code must be volatile. Non-volatile memory +// operations are dangerous because a compiler would be free to materialize a +// second load from the same memory address or materialize a load from a memory +// address that was stored, and assume the materialized load would return the +// same value as the previous load or store. Data races could cause the +// materialized load to return a different value, however, which could lead to +// time of check vs. time of use problems, or worse. For this binding code in +// particular, where memcpy is being called with a constant size, it is entirely +// conceivable the function will be inlined, unrolled, and optimized. +static inline void memcpy_volatile_out(void volatile* dst, + const void* src, + size_t n) { + char volatile* c_dst = static_cast<char volatile*>(dst); + const char* c_src = static_cast<const char*>(src); + for (size_t i = 0; i < n; i++) { + c_dst[i] = c_src[i]; + } +} + +template <typename T> +bool ConvertScalarInput(struct NaClApp* nap, uint32_t user_ptr, T* value) { + if (user_ptr) { + uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T)); + if (temp != kNaClBadAddress) { + *value = *reinterpret_cast<T volatile*>(temp); + return true; + } + } + return false; +} + +template <typename T> +bool ConvertScalarOutput(struct NaClApp* nap, + uint32_t user_ptr, + bool optional, + T volatile** sys_ptr) { + if (user_ptr) { + uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T)); + if (temp != kNaClBadAddress) { + *sys_ptr = reinterpret_cast<T volatile*>(temp); + return true; + } + } else if (optional) { + *sys_ptr = 0; + return true; + } + *sys_ptr = 0; // Paranoia. + return false; +} + +template <typename T> +bool ConvertScalarInOut(struct NaClApp* nap, + uint32_t user_ptr, + bool optional, + T* value, + T volatile** sys_ptr) { + if (user_ptr) { + uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T)); + if (temp != kNaClBadAddress) { + T volatile* converted = reinterpret_cast<T volatile*>(temp); + *sys_ptr = converted; + *value = *converted; + return true; + } + } else if (optional) { + *sys_ptr = 0; + *value = static_cast<T>(0); // Paranoia. + return true; + } + *sys_ptr = 0; // Paranoia. + *value = static_cast<T>(0); // Paranoia. + return false; +} + +template <typename T> +bool ConvertArray(struct NaClApp* nap, + uint32_t user_ptr, + uint32_t length, + size_t element_size, + bool optional, + T** sys_ptr) { + if (user_ptr) { + uintptr_t temp = + NaClUserToSysAddrArray(nap, user_ptr, length, element_size); + if (temp != kNaClBadAddress) { + *sys_ptr = reinterpret_cast<T*>(temp); + return true; + } + } else if (optional) { + *sys_ptr = 0; + return true; + } + return false; +} + +template <typename T> +bool ConvertBytes(struct NaClApp* nap, + uint32_t user_ptr, + uint32_t length, + bool optional, + T** sys_ptr) { + if (user_ptr) { + uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, length); + if (temp != kNaClBadAddress) { + *sys_ptr = reinterpret_cast<T*>(temp); + return true; + } + } else if (optional) { + *sys_ptr = 0; + return true; + } + return false; +} + +// TODO(ncbray): size validation and complete copy. +// TODO(ncbray): ensure non-null / missized structs are covered by a test case. +template <typename T> +bool ConvertExtensibleStructInput(struct NaClApp* nap, + uint32_t user_ptr, + bool optional, + T** sys_ptr) { + if (user_ptr) { + uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T)); + if (temp != kNaClBadAddress) { + *sys_ptr = reinterpret_cast<T*>(temp); + return true; + } + } else if (optional) { + *sys_ptr = 0; + return true; + } + return false; +} + +} // namespace + +#endif // MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_
diff --git a/third_party/mojo/src/nacl_bindings/monacl_sel_main.cc b/third_party/mojo/src/nacl_bindings/monacl_sel_main.cc new file mode 100644 index 0000000..100f1610 --- /dev/null +++ b/third_party/mojo/src/nacl_bindings/monacl_sel_main.cc
@@ -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. + +#include "nacl_bindings/monacl_sel_main.h" + +#include "nacl_bindings/mojo_syscall.h" +#include "native_client/src/public/chrome_main.h" +#include "native_client/src/public/nacl_app.h" + +namespace mojo { + +int LaunchNaCl(NaClDesc* nexe_desc, + NaClDesc* irt_desc, + int app_argc, + char* app_argv[], + MojoHandle handle) { + NaClChromeMainInit(); + + struct NaClChromeMainArgs* args = NaClChromeMainArgsCreate(); + args->nexe_desc = nexe_desc; + args->irt_desc = irt_desc; + + args->argc = app_argc; + args->argv = app_argv; + + struct NaClApp* nap = NaClAppCreate(); + InjectMojo(nap, handle); + + int exit_status = 1; + NaClChromeMainStart(nap, args, &exit_status); + return exit_status; +} + +void NaClExit(int code) { + ::NaClExit(code); +} + +} // namespace mojo
diff --git a/third_party/mojo/src/nacl_bindings/monacl_sel_main.h b/third_party/mojo/src/nacl_bindings/monacl_sel_main.h new file mode 100644 index 0000000..d376f64 --- /dev/null +++ b/third_party/mojo/src/nacl_bindings/monacl_sel_main.h
@@ -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. + +#ifndef MOJO_NACL_MONACL_SEL_MAIN_H_ +#define MOJO_NACL_MONACL_SEL_MAIN_H_ + +#include "mojo/public/c/system/types.h" + +struct NaClDesc; + +namespace mojo { + +// Callee assumes ownership of |nexe_desc|, |irt_desc|, and |handle|. +int LaunchNaCl(NaClDesc* nexe_desc, + NaClDesc* irt_desc, + int app_argc, + char* app_argv[], + MojoHandle handle); + +void NaClExit(int code); + +} // namespace mojo + +#endif // MOJO_NACL_MONACL_SEL_MAIN_H_
diff --git a/third_party/mojo_services/src/input_events/public/interfaces/BUILD.gn b/third_party/mojo_services/src/input_events/public/interfaces/BUILD.gn index bf9b729a..e7a75f2 100644 --- a/third_party/mojo_services/src/input_events/public/interfaces/BUILD.gn +++ b/third_party/mojo_services/src/input_events/public/interfaces/BUILD.gn
@@ -7,8 +7,8 @@ mojom("interfaces") { sources = [ - "input_event_constants.mojom", "input_events.mojom", + "input_event_constants.mojom", "input_key_codes.mojom", ]
diff --git a/third_party/mojo_services/src/native_viewport/public/cpp/BUILD.gn b/third_party/mojo_services/src/native_viewport/public/cpp/BUILD.gn index af47d38..035ddfa6 100644 --- a/third_party/mojo_services/src/native_viewport/public/cpp/BUILD.gn +++ b/third_party/mojo_services/src/native_viewport/public/cpp/BUILD.gn
@@ -8,7 +8,7 @@ mojo_sdk_source_set("args") { public_configs = [ "../../../public/build/config:mojo_services" ] sources = [ - "args.h", "lib/args.cc", + "args.h", ] }
diff --git a/third_party/mojo_services/src/navigation/public/interfaces/navigation.mojom b/third_party/mojo_services/src/navigation/public/interfaces/navigation.mojom index 0d2656a..b461a2b 100644 --- a/third_party/mojo_services/src/navigation/public/interfaces/navigation.mojom +++ b/third_party/mojo_services/src/navigation/public/interfaces/navigation.mojom
@@ -21,6 +21,7 @@ // Embedders that support navigation of implement this interface. interface NavigatorHost { RequestNavigate(Target target, URLRequest request); + RequestNavigateHistory(int32 delta); // Applications call this to inform hosts of navigations they performed // locally. For example, pushState() navigations in an HTML application.
diff --git a/third_party/mojo_services/src/public/js/application.js b/third_party/mojo_services/src/public/js/application.js index aea60fd..cadba0f 100644 --- a/third_party/mojo_services/src/public/js/application.js +++ b/third_party/mojo_services/src/public/js/application.js
@@ -30,7 +30,7 @@ }; } - doInitialize(shellProxy, args) { + doInitialize(shellProxy, args, url) { this.shellProxy_ = shellProxy; this.shell = new Shell(shellProxy); this.initialize(args);
diff --git a/third_party/mojo_services/src/public/js/service_exchange.js b/third_party/mojo_services/src/public/js/service_exchange.js index a424c12..f23c0ef 100644 --- a/third_party/mojo_services/src/public/js/service_exchange.js +++ b/third_party/mojo_services/src/public/js/service_exchange.js
@@ -47,7 +47,7 @@ var provider = { service: service, // A JS bindings interface object. - factory: factory, // factory(clientProxy) => interface implemntation + factory: factory, // factory() => interface implemntation connections: [], }; this.providers_.set(service.name, provider); @@ -60,12 +60,10 @@ } // Outgoing requests - requestService(interfaceObject, clientImpl) { + requestService(interfaceObject) { checkServiceExchange(this); if (!interfaceObject.name) throw new Error("Invalid service parameter"); - if (!clientImpl && interfaceObject.client) - throw new Error("Client implementation must be provided"); var serviceProxy; var serviceHandle = connection.bindProxy(
diff --git a/third_party/mojo_services/src/public/js/shell.js b/third_party/mojo_services/src/public/js/shell.js index 358f272..e8bab6f 100644 --- a/third_party/mojo_services/src/public/js/shell.js +++ b/third_party/mojo_services/src/public/js/shell.js
@@ -41,8 +41,8 @@ return application; } - connectToService(url, service, client) { - return this.connectToApplication(url).requestService(service, client); + connectToService(url, service) { + return this.connectToApplication(url).requestService(service); }; close() {
diff --git a/third_party/mojo_services/src/surfaces/public/interfaces/quads.mojom b/third_party/mojo_services/src/surfaces/public/interfaces/quads.mojom index 58f85e0..2418d51 100644 --- a/third_party/mojo_services/src/surfaces/public/interfaces/quads.mojom +++ b/third_party/mojo_services/src/surfaces/public/interfaces/quads.mojom
@@ -79,7 +79,8 @@ enum YUVColorSpace { REC_601, // SDTV standard with restricted "studio swing" color range. - REC_601_JPEG, // Full color range [0, 255] variant of the above. + REC_709, // HDTV standard with restricted "studio swing" color range. + JPEG, // Full color range [0, 255] JPEG color space. }; struct YUVVideoQuadState {
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/BUILD.gn b/third_party/mojo_services/src/view_manager/public/cpp/BUILD.gn index b1a0bdb..d121021 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/BUILD.gn +++ b/third_party/mojo_services/src/view_manager/public/cpp/BUILD.gn
@@ -21,6 +21,7 @@ "view_manager.h", "view_manager_client_factory.h", "view_manager_context.h", + "view_manager_delegate.cc", "view_manager_delegate.h", "view_observer.h", "view_property.h", @@ -45,6 +46,7 @@ "mojo/public/c/gles2:headers", "mojo/public/cpp/application", "mojo/public/cpp/bindings:bindings", + "mojo/public/cpp/system", "mojo/public/interfaces/application", ] }
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/lib/view.cc b/third_party/mojo_services/src/view_manager/public/cpp/lib/view.cc index 1e8b2b0..9ed458c7 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/lib/view.cc +++ b/third_party/mojo_services/src/view_manager/public/cpp/lib/view.cc
@@ -77,7 +77,7 @@ private: ViewObserver::TreeChangeParams params_; - DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier); + MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier); }; void RemoveChildImpl(View* child, View::Children* children) { @@ -112,7 +112,7 @@ View* relative_view_; OrderDirection direction_; - DISALLOW_COPY_AND_ASSIGN(ScopedOrderChangedNotifier); + MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedOrderChangedNotifier); }; // Returns true if the order actually changed. @@ -168,7 +168,7 @@ const Rect old_bounds_; const Rect new_bounds_; - DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier); + MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier); }; // Some operations are only permitted in the connection that created the view. @@ -220,9 +220,7 @@ if (manager_) static_cast<ViewManagerClientImpl*>(manager_)->SetVisible(id_, value); - FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewVisibilityChanging(this)); - visible_ = value; - NotifyViewVisibilityChanged(this); + LocalSetVisible(value); } void View::SetSharedProperty(const std::string& name, @@ -531,6 +529,15 @@ FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDrawnChanged(this)); } +void View::LocalSetVisible(bool visible) { + if (visible_ == visible) + return; + + FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewVisibilityChanging(this)); + visible_ = visible; + NotifyViewVisibilityChanged(this); +} + void View::NotifyViewVisibilityChanged(View* target) { if (!NotifyViewVisibilityChangedDown(target)) { return; // |this| has been deleted.
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_factory.cc b/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_factory.cc index cfa2b7966..bb39fc9 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_factory.cc +++ b/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_factory.cc
@@ -19,17 +19,16 @@ } // static -scoped_ptr<ViewManagerClient> -ViewManagerClientFactory::WeakBindViewManagerToPipe( +ViewManagerClient* ViewManagerClientFactory::WeakBindViewManagerToPipe( InterfaceRequest<ViewManagerClient> request, ViewManagerServicePtr view_manager_service, Shell* shell, ViewManagerDelegate* delegate) { const bool delete_on_error = false; - scoped_ptr<ViewManagerClientImpl> client(new ViewManagerClientImpl( - delegate, shell, request.Pass(), delete_on_error)); + auto client = new ViewManagerClientImpl(delegate, shell, request.Pass(), + delete_on_error); client->SetViewManagerService(view_manager_service.Pass()); - return client.Pass(); + return client; } // InterfaceFactory<ViewManagerClient> implementation.
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_impl.cc b/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_impl.cc index 574d300..b0d4b33b 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_impl.cc +++ b/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_impl.cc
@@ -4,9 +4,6 @@ #include "view_manager/public/cpp/lib/view_manager_client_impl.h" -#include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "base/stl_util.h" #include "mojo/public/cpp/application/application_impl.h" #include "mojo/public/cpp/application/connect.h" #include "mojo/public/cpp/application/service_provider_impl.h" @@ -90,7 +87,7 @@ View* root_; - DISALLOW_COPY_AND_ASSIGN(RootObserver); + MOJO_DISALLOW_COPY_AND_ASSIGN(RootObserver); }; ViewManagerClientImpl::ViewManagerClientImpl( @@ -175,8 +172,8 @@ void ViewManagerClientImpl::SetFocus(Id view_id) { // In order for us to get here we had to have exposed a view, which implies we // got a connection. - DCHECK(window_manager_.get()); - window_manager_->FocusWindow(view_id, ActionCompletedCallback()); + DCHECK(service_); + service_->PerformAction(view_id, "focus", ActionCompletedCallback()); } void ViewManagerClientImpl::SetVisible(Id view_id, bool visible) { @@ -236,7 +233,9 @@ Id ViewManagerClientImpl::CreateViewOnServer() { DCHECK(service_); const Id view_id = MakeTransportId(connection_id_, ++next_id_); - service_->CreateView(view_id, ActionCompletedCallbackWithErrorCode()); + service_->CreateView(view_id, [this](ErrorCode code) { + OnActionCompleted(code == ERROR_CODE_NONE); + }); return view_id; } @@ -286,14 +285,21 @@ root_->AddObserver(new RootObserver(root_)); window_manager_.Bind(window_manager_pipe.Pass()); - // base::Unretained() is safe here as |window_manager_| is bound to our - // lifetime. WindowManagerObserverPtr observer; wm_observer_binding_.Bind(GetProxy(&observer)); + // binding to |this| is safe here as |window_manager_| is bound to our + // lifetime. window_manager_->GetFocusedAndActiveViews( observer.Pass(), - base::Bind(&ViewManagerClientImpl::OnGotFocusedAndActiveViews, - base::Unretained(this))); + [this](uint32_t capture_view_id, uint32_t focused_view_id, + uint32_t active_view_id) { + if (GetViewById(capture_view_id) != capture_view_) + OnCaptureChanged(capture_view_id); + if (GetViewById(focused_view_id) != focused_view_) + OnFocusChanged(focused_view_id); + if (GetViewById(active_view_id) != activated_view_) + OnActiveWindowChanged(active_view_id); + }); delegate_->OnEmbed(root_, services.Pass(), exposed_services.Pass()); } @@ -373,7 +379,7 @@ // Deal with this some how. View* view = GetViewById(view_id); if (view) - view->SetVisible(visible); + ViewPrivate(view).LocalSetVisible(visible); } void ViewManagerClientImpl::OnViewDrawnStateChanged(Id view_id, bool drawn) { @@ -412,6 +418,14 @@ ack_callback.Run(); } +void ViewManagerClientImpl::OnPerformAction( + Id view_id, + const String& name, + const Callback<void(bool)>& callback) { + View* view = GetViewById(view_id); + callback.Run(delegate_->OnPerformAction(view, name)); +} + //////////////////////////////////////////////////////////////////////////////// // ViewManagerClientImpl, WindowManagerObserver implementation: @@ -483,31 +497,8 @@ change_acked_callback_.Run(); } -void ViewManagerClientImpl::OnActionCompletedWithErrorCode(ErrorCode code) { - OnActionCompleted(code == ERROR_CODE_NONE); -} - -base::Callback<void(bool)> ViewManagerClientImpl::ActionCompletedCallback() { - return base::Bind(&ViewManagerClientImpl::OnActionCompleted, - base::Unretained(this)); -} - -base::Callback<void(ErrorCode)> - ViewManagerClientImpl::ActionCompletedCallbackWithErrorCode() { - return base::Bind(&ViewManagerClientImpl::OnActionCompletedWithErrorCode, - base::Unretained(this)); -} - -void ViewManagerClientImpl::OnGotFocusedAndActiveViews( - uint32_t capture_view_id, - uint32_t focused_view_id, - uint32_t active_view_id) { - if (GetViewById(capture_view_id) != capture_view_) - OnCaptureChanged(capture_view_id); - if (GetViewById(focused_view_id) != focused_view_) - OnFocusChanged(focused_view_id); - if (GetViewById(active_view_id) != activated_view_) - OnActiveWindowChanged(active_view_id); +Callback<void(bool)> ViewManagerClientImpl::ActionCompletedCallback() { + return [this](bool success) { OnActionCompleted(success); }; } } // namespace mojo
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_impl.h b/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_impl.h index c3a2ad5..3bdfd7f 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_impl.h +++ b/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_impl.h
@@ -5,9 +5,6 @@ #ifndef MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_LIB_VIEW_MANAGER_CLIENT_IMPL_H_ #define MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_LIB_VIEW_MANAGER_CLIENT_IMPL_H_ -#include "base/callback.h" -#include "base/memory/scoped_vector.h" -#include "base/memory/weak_ptr.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "view_manager/public/cpp/types.h" #include "view_manager/public/cpp/view.h" @@ -66,12 +63,10 @@ ServiceProviderPtr exposed_services); void Embed(Id view_id, ViewManagerClientPtr client); - void set_change_acked_callback(const base::Callback<void(void)>& callback) { + void set_change_acked_callback(const Callback<void(void)>& callback) { change_acked_callback_ = callback; } - void ClearChangeAckedCallback() { - change_acked_callback_ = base::Callback<void(void)>(); - } + void ClearChangeAckedCallback() { change_acked_callback_.reset(); } // Start/stop tracking views. While tracked, they can be retrieved via // ViewManager::GetViewById. @@ -124,6 +119,9 @@ void OnViewInputEvent(Id view_id, EventPtr event, const Callback<void()>& callback) override; + void OnPerformAction(Id view_id, + const String& name, + const Callback<void(bool)>& callback) override; // Overridden from WindowManagerObserver: void OnCaptureChanged(Id capture_view_id) override; @@ -136,22 +134,15 @@ void RootDestroyed(View* root); void OnActionCompleted(bool success); - void OnActionCompletedWithErrorCode(ErrorCode code); - base::Callback<void(bool)> ActionCompletedCallback(); - base::Callback<void(ErrorCode)> ActionCompletedCallbackWithErrorCode(); - - // Callback from server for initial request of capture/focused/active views. - void OnGotFocusedAndActiveViews(uint32_t capture_view_id, - uint32_t focused_view_id, - uint32_t active_view_id); + Callback<void(bool)> ActionCompletedCallback(); ConnectionSpecificId connection_id_; ConnectionSpecificId next_id_; std::string creator_url_; - base::Callback<void(void)> change_acked_callback_; + Callback<void(void)> change_acked_callback_; ViewManagerDelegate* delegate_; @@ -170,7 +161,7 @@ ViewManagerServicePtr service_; const bool delete_on_error_; - DISALLOW_COPY_AND_ASSIGN(ViewManagerClientImpl); + MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerClientImpl); }; } // namespace mojo
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_context.cc b/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_context.cc index a47f59af..d1c2fd0 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_context.cc +++ b/third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_context.cc
@@ -28,7 +28,9 @@ ViewManagerContext::ViewManagerContext(ApplicationImpl* application_impl) : state_(new InternalState(application_impl)) {} -ViewManagerContext::~ViewManagerContext() {} +ViewManagerContext::~ViewManagerContext() { + delete state_; +} void ViewManagerContext::Embed(const String& url) { Embed(url, nullptr, nullptr);
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/lib/view_observer.cc b/third_party/mojo_services/src/view_manager/public/cpp/lib/view_observer.cc index 456147cc..7e6acc0 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/lib/view_observer.cc +++ b/third_party/mojo_services/src/view_manager/public/cpp/lib/view_observer.cc
@@ -4,17 +4,16 @@ #include "view_manager/public/cpp/view_observer.h" -#include "base/basictypes.h" - namespace mojo { //////////////////////////////////////////////////////////////////////////////// // ViewObserver, public: ViewObserver::TreeChangeParams::TreeChangeParams() - : target(NULL), - old_parent(NULL), - new_parent(NULL), - receiver(NULL) {} + : target(nullptr), + old_parent(nullptr), + new_parent(nullptr), + receiver(nullptr) { +} } // namespace mojo
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/lib/view_private.h b/third_party/mojo_services/src/view_manager/public/cpp/lib/view_private.h index 1c54567..0b58280 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/lib/view_private.h +++ b/third_party/mojo_services/src/view_manager/public/cpp/lib/view_private.h
@@ -5,8 +5,6 @@ #ifndef MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_LIB_VIEW_PRIVATE_H_ #define MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_LIB_VIEW_PRIVATE_H_ -#include "base/basictypes.h" - #include "view_manager/public/cpp/view.h" namespace mojo { @@ -61,11 +59,12 @@ view_->LocalSetBounds(old_bounds, new_bounds); } void LocalSetDrawn(bool drawn) { view_->LocalSetDrawn(drawn); } + void LocalSetVisible(bool visible) { view_->LocalSetVisible(visible); } private: View* view_; - DISALLOW_COPY_AND_ASSIGN(ViewPrivate); + MOJO_DISALLOW_COPY_AND_ASSIGN(ViewPrivate); }; } // namespace mojo
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/tests/BUILD.gn b/third_party/mojo_services/src/view_manager/public/cpp/tests/BUILD.gn index 3414d33a..0adbb5d 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/tests/BUILD.gn +++ b/third_party/mojo_services/src/view_manager/public/cpp/tests/BUILD.gn
@@ -10,7 +10,6 @@ "run_all_unittests.cc", "view_manager_test_suite.cc", "view_manager_test_suite.h", - "view_manager_unittest.cc", "view_unittest.cc", ] @@ -18,11 +17,10 @@ "//base", "//base/test:test_support", "//mojo/public/cpp/application", + "//mojo/public/cpp/system", "//mojo/services/geometry/public/cpp", "//mojo/services/geometry/public/interfaces", "//mojo/services/view_manager/public/cpp", - "//mojo/services/view_manager/public/interfaces", - "//shell/application_manager", "//shell:test_support", "//testing/gtest", ]
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/tests/view_manager_test_suite.h b/third_party/mojo_services/src/view_manager/public/cpp/tests/view_manager_test_suite.h index ef81661..547efc2 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/tests/view_manager_test_suite.h +++ b/third_party/mojo_services/src/view_manager/public/cpp/tests/view_manager_test_suite.h
@@ -6,6 +6,7 @@ #define MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_SUITE_H_ #include "base/test/test_suite.h" +#include "mojo/public/cpp/system/macros.h" namespace mojo { @@ -18,7 +19,7 @@ void Initialize() override; private: - DISALLOW_COPY_AND_ASSIGN(ViewManagerTestSuite); + MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerTestSuite); }; } // namespace mojo
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/tests/view_manager_unittest.cc b/third_party/mojo_services/src/view_manager/public/cpp/tests/view_manager_unittest.cc deleted file mode 100644 index bc69464..0000000 --- a/third_party/mojo_services/src/view_manager/public/cpp/tests/view_manager_unittest.cc +++ /dev/null
@@ -1,652 +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 "mojo/services/view_manager/public/cpp/view_manager.h" - -#include "base/auto_reset.h" -#include "base/bind.h" -#include "base/logging.h" -#include "mojo/public/cpp/application/application_connection.h" -#include "mojo/public/cpp/application/application_delegate.h" -#include "mojo/public/cpp/application/application_impl.h" -#include "mojo/public/cpp/application/service_provider_impl.h" -#include "mojo/public/interfaces/application/service_provider.mojom.h" -#include "mojo/services/geometry/public/cpp/geometry_util.h" -#include "mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.h" -#include "mojo/services/view_manager/public/cpp/lib/view_private.h" -#include "mojo/services/view_manager/public/cpp/util.h" -#include "mojo/services/view_manager/public/cpp/view_manager_client_factory.h" -#include "mojo/services/view_manager/public/cpp/view_manager_delegate.h" -#include "mojo/services/view_manager/public/cpp/view_observer.h" -#include "shell/application_manager/application_manager.h" -#include "shell/shell_test_helper.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { - -namespace { - -const char kWindowManagerURL[] = "mojo:window_manager"; -const char kEmbeddedApp1URL[] = "mojo:embedded_app_1"; - -base::RunLoop* current_run_loop = NULL; - -void DoRunLoop() { - base::RunLoop run_loop; - current_run_loop = &run_loop; - current_run_loop->Run(); - current_run_loop = NULL; -} - -void QuitRunLoop() { - current_run_loop->Quit(); -} - -class ConnectApplicationLoader : public ApplicationLoader, - public ApplicationDelegate, - public ViewManagerDelegate { - public: - typedef base::Callback<void(View*)> LoadedCallback; - - explicit ConnectApplicationLoader(const LoadedCallback& callback) - : callback_(callback) {} - ~ConnectApplicationLoader() override {} - - private: - // Overridden from ApplicationDelegate: - void Initialize(ApplicationImpl* app) override { - view_manager_client_factory_.reset( - new ViewManagerClientFactory(app->shell(), this)); - } - - // Overridden from ApplicationLoader: - void Load(ApplicationManager* manager, - const GURL& url, - InterfaceRequest<Application> application_request, - LoadCallback callback) override { - ASSERT_TRUE(application_request.is_pending()); - scoped_ptr<ApplicationImpl> app( - new ApplicationImpl(this, application_request.Pass())); - apps_.push_back(app.release()); - } - - void OnApplicationError(ApplicationManager* manager, - const GURL& url) override {} - - bool ConfigureIncomingConnection(ApplicationConnection* connection) override { - connection->AddService(view_manager_client_factory_.get()); - return true; - } - - // Overridden from ViewManagerDelegate: - void OnEmbed(View* root, - InterfaceRequest<ServiceProvider> services, - ServiceProviderPtr exposed_services) override { - callback_.Run(root); - } - void OnViewManagerDisconnected(ViewManager* view_manager) override {} - - ScopedVector<ApplicationImpl> apps_; - LoadedCallback callback_; - scoped_ptr<ViewManagerClientFactory> view_manager_client_factory_; - - DISALLOW_COPY_AND_ASSIGN(ConnectApplicationLoader); -}; - -class BoundsChangeObserver : public ViewObserver { - public: - explicit BoundsChangeObserver(View* view) : view_(view) {} - ~BoundsChangeObserver() override {} - - private: - // Overridden from ViewObserver: - void OnViewBoundsChanged(View* view, - const Rect& old_bounds, - const Rect& new_bounds) override { - DCHECK_EQ(view, view_); - QuitRunLoop(); - } - - View* view_; - - DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver); -}; - -// Wait until the bounds of the supplied view change. -void WaitForBoundsToChange(View* view) { - BoundsChangeObserver observer(view); - view->AddObserver(&observer); - DoRunLoop(); - view->RemoveObserver(&observer); -} - -// Spins a runloop until the tree beginning at |root| has |tree_size| views -// (including |root|). -class TreeSizeMatchesObserver : public ViewObserver { - public: - TreeSizeMatchesObserver(View* tree, size_t tree_size) - : tree_(tree), - tree_size_(tree_size) {} - ~TreeSizeMatchesObserver() override {} - - bool IsTreeCorrectSize() { - return CountViews(tree_) == tree_size_; - } - - private: - // Overridden from ViewObserver: - void OnTreeChanged(const TreeChangeParams& params) override { - if (IsTreeCorrectSize()) - QuitRunLoop(); - } - - size_t CountViews(const View* view) const { - size_t count = 1; - View::Children::const_iterator it = view->children().begin(); - for (; it != view->children().end(); ++it) - count += CountViews(*it); - return count; - } - - View* tree_; - size_t tree_size_; - - DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver); -}; - -void WaitForTreeSizeToMatch(View* view, size_t tree_size) { - TreeSizeMatchesObserver observer(view, tree_size); - if (observer.IsTreeCorrectSize()) - return; - view->AddObserver(&observer); - DoRunLoop(); - view->RemoveObserver(&observer); -} - -// Utility class that waits for the destruction of some number of views and -// views. -class DestructionObserver : public ViewObserver { - public: - // |views| or |views| can be NULL. - explicit DestructionObserver(std::set<Id>* views) : views_(views) {} - - private: - // Overridden from ViewObserver: - void OnViewDestroyed(View* view) override { - std::set<Id>::iterator it = views_->find(view->id()); - if (it != views_->end()) - views_->erase(it); - if (CanQuit()) - QuitRunLoop(); - } - - bool CanQuit() { - return !views_ || views_->empty(); - } - - std::set<Id>* views_; - - DISALLOW_COPY_AND_ASSIGN(DestructionObserver); -}; - -void WaitForDestruction(ViewManager* view_manager, std::set<Id>* views) { - DestructionObserver observer(views); - DCHECK(views); - if (views) { - for (std::set<Id>::const_iterator it = views->begin(); - it != views->end(); ++it) { - view_manager->GetViewById(*it)->AddObserver(&observer); - } - } - DoRunLoop(); -} - -class OrderChangeObserver : public ViewObserver { - public: - OrderChangeObserver(View* view) : view_(view) { - view_->AddObserver(this); - } - ~OrderChangeObserver() override { view_->RemoveObserver(this); } - - private: - // Overridden from ViewObserver: - void OnViewReordered(View* view, - View* relative_view, - OrderDirection direction) override { - DCHECK_EQ(view, view_); - QuitRunLoop(); - } - - View* view_; - - DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver); -}; - -void WaitForOrderChange(ViewManager* view_manager, View* view) { - OrderChangeObserver observer(view); - DoRunLoop(); -} - -// Tracks a view's destruction. Query is_valid() for current state. -class ViewTracker : public ViewObserver { - public: - explicit ViewTracker(View* view) : view_(view) { - view_->AddObserver(this); - } - ~ViewTracker() override { - if (view_) - view_->RemoveObserver(this); - } - - bool is_valid() const { return !!view_; } - - private: - // Overridden from ViewObserver: - void OnViewDestroyed(View* view) override { - DCHECK_EQ(view, view_); - view_ = NULL; - } - - int id_; - View* view_; - - DISALLOW_COPY_AND_ASSIGN(ViewTracker); -}; - -} // namespace - -// ViewManager ----------------------------------------------------------------- - -// These tests model synchronization of two peer connections to the view manager -// service, that are given access to some root view. - -class ViewManagerTest : public testing::Test { - public: - ViewManagerTest() - : connect_loop_(NULL), - loaded_view_manager_(NULL), - window_manager_(NULL), - commit_count_(0) {} - - protected: - ViewManager* window_manager() { return window_manager_; } - - View* CreateViewInParent(View* parent) { - ViewManager* parent_manager = parent->view_manager(); - View* view = parent_manager->CreateView(); - view->SetVisible(true); - parent->AddChild(view); - return view; - } - - // Embeds another version of the test app @ view. - ViewManager* Embed(ViewManager* view_manager, View* view) { - DCHECK_EQ(view_manager, view->view_manager()); - view->Embed(kEmbeddedApp1URL); - RunRunLoop(); - return GetLoadedViewManager(); - } - - ViewManager* GetLoadedViewManager() { - ViewManager* view_manager = loaded_view_manager_; - loaded_view_manager_ = NULL; - return view_manager; - } - - void UnloadApplication(const GURL& url) { - test_helper_.SetLoaderForURL(scoped_ptr<ApplicationLoader>(), url); - } - - private: - // Overridden from testing::Test: - void SetUp() override { - ConnectApplicationLoader::LoadedCallback ready_callback = base::Bind( - &ViewManagerTest::OnViewManagerLoaded, base::Unretained(this)); - test_helper_.Init(); - test_helper_.SetLoaderForURL( - scoped_ptr<ApplicationLoader>( - new ConnectApplicationLoader(ready_callback)), - GURL(kWindowManagerURL)); - test_helper_.SetLoaderForURL( - scoped_ptr<ApplicationLoader>( - new ConnectApplicationLoader(ready_callback)), - GURL(kEmbeddedApp1URL)); - - // TODO(sky): resolve this. Need to establish initial connection. - } - - void OnViewManagerLoaded(View* root) { - loaded_view_manager_ = root->view_manager(); - connect_loop_->Quit(); - } - - void RunRunLoop() { - base::RunLoop run_loop; - connect_loop_ = &run_loop; - connect_loop_->Run(); - connect_loop_ = NULL; - } - - base::RunLoop* connect_loop_; - shell::ShellTestHelper test_helper_; - // Used to receive the most recent view manager loaded by an embed action. - ViewManager* loaded_view_manager_; - // The View Manager connection held by the window manager (app running at the - // root view). - ViewManager* window_manager_; - int commit_count_; - - DISALLOW_COPY_AND_ASSIGN(ViewManagerTest); -}; - -// TODO(sky): all of these tests are disabled as each test triggers running -// ViewsInit, which tries to register the same set of paths with the -// PathService, triggering a DCHECK. -TEST_F(ViewManagerTest, DISABLED_SetUp) {} - -TEST_F(ViewManagerTest, DISABLED_Embed) { - View* view = window_manager()->CreateView(); - view->SetVisible(true); - window_manager()->GetRoot()->AddChild(view); - ViewManager* embedded = Embed(window_manager(), view); - EXPECT_TRUE(NULL != embedded); - - View* view_in_embedded = embedded->GetRoot(); - EXPECT_EQ(view->parent(), window_manager()->GetRoot()); - EXPECT_EQ(NULL, view_in_embedded->parent()); -} - -// Window manager has two views, N1 and N11. Embeds A at N1. A should not see -// N11. -// TODO(sky): Update client lib to match server. -TEST_F(ViewManagerTest, DISABLED_EmbeddedDoesntSeeChild) { - View* view = window_manager()->CreateView(); - view->SetVisible(true); - window_manager()->GetRoot()->AddChild(view); - View* nested = window_manager()->CreateView(); - nested->SetVisible(true); - view->AddChild(nested); - - ViewManager* embedded = Embed(window_manager(), view); - EXPECT_EQ(embedded->GetRoot()->children().front()->id(), - nested->id()); - EXPECT_TRUE(embedded->GetRoot()->children().empty()); - EXPECT_TRUE(nested->parent() == NULL); -} - -// http://crbug.com/396300 -TEST_F(ViewManagerTest, DISABLED_ViewManagerDestroyed_CleanupView) { - View* view = window_manager()->CreateView(); - view->SetVisible(true); - window_manager()->GetRoot()->AddChild(view); - ViewManager* embedded = Embed(window_manager(), view); - - Id view_id = view->id(); - - UnloadApplication(GURL(kWindowManagerURL)); - - std::set<Id> views; - views.insert(view_id); - WaitForDestruction(embedded, &views); - - EXPECT_EQ(nullptr, embedded->GetRoot()); -} - -// TODO(beng): write a replacement test for the one that once existed here: -// This test validates the following scenario: -// - a view originating from one connection -// - a view originating from a second connection -// + the connection originating the view is destroyed -// -> the view should still exist (since the second connection is live) but -// should be disconnected from any views. -// http://crbug.com/396300 -// -// TODO(beng): The new test should validate the scenario as described above -// except that the second connection still has a valid tree. - -// Verifies that bounds changes applied to a view hierarchy in one connection -// are reflected to another. -TEST_F(ViewManagerTest, DISABLED_SetBounds) { - View* view = window_manager()->CreateView(); - view->SetVisible(true); - window_manager()->GetRoot()->AddChild(view); - ViewManager* embedded = Embed(window_manager(), view); - - View* view_in_embedded = embedded->GetViewById(view->id()); - EXPECT_EQ(view->bounds(), view_in_embedded->bounds()); - - Rect rect; - rect.width = rect.height = 100; - view->SetBounds(rect); - EXPECT_NE(view->bounds(), view_in_embedded->bounds()); - WaitForBoundsToChange(view_in_embedded); - EXPECT_EQ(view->bounds(), view_in_embedded->bounds()); -} - -// Verifies that bounds changes applied to a view owned by a different -// connection are refused. -TEST_F(ViewManagerTest, DISABLED_SetBoundsSecurity) { - View* view = window_manager()->CreateView(); - view->SetVisible(true); - window_manager()->GetRoot()->AddChild(view); - ViewManager* embedded = Embed(window_manager(), view); - - View* view_in_embedded = embedded->GetViewById(view->id()); - Rect rect; - rect.width = 800; - rect.height = 600; - view->SetBounds(rect); - WaitForBoundsToChange(view_in_embedded); - - rect.width = 1024; - rect.height = 768; - view_in_embedded->SetBounds(rect); - // Bounds change should have been rejected. - EXPECT_EQ(view->bounds(), view_in_embedded->bounds()); -} - -// Verifies that a view can only be destroyed by the connection that created it. -TEST_F(ViewManagerTest, DISABLED_DestroySecurity) { - View* view = window_manager()->CreateView(); - view->SetVisible(true); - window_manager()->GetRoot()->AddChild(view); - ViewManager* embedded = Embed(window_manager(), view); - - View* view_in_embedded = embedded->GetViewById(view->id()); - - ViewTracker tracker2(view_in_embedded); - view_in_embedded->Destroy(); - // View should not have been destroyed. - EXPECT_TRUE(tracker2.is_valid()); - - ViewTracker tracker1(view); - view->Destroy(); - EXPECT_FALSE(tracker1.is_valid()); -} - -TEST_F(ViewManagerTest, DISABLED_MultiRoots) { - View* view1 = window_manager()->CreateView(); - view1->SetVisible(true); - window_manager()->GetRoot()->AddChild(view1); - View* view2 = window_manager()->CreateView(); - view2->SetVisible(true); - window_manager()->GetRoot()->AddChild(view2); - ViewManager* embedded1 = Embed(window_manager(), view1); - ViewManager* embedded2 = Embed(window_manager(), view2); - EXPECT_EQ(embedded1, embedded2); -} - -TEST_F(ViewManagerTest, DISABLED_EmbeddingIdentity) { - View* view = window_manager()->CreateView(); - view->SetVisible(true); - window_manager()->GetRoot()->AddChild(view); - ViewManager* embedded = Embed(window_manager(), view); - EXPECT_EQ(kWindowManagerURL, embedded->GetEmbedderURL()); -} - -TEST_F(ViewManagerTest, DISABLED_Reorder) { - View* view1 = window_manager()->CreateView(); - view1->SetVisible(true); - window_manager()->GetRoot()->AddChild(view1); - - ViewManager* embedded = Embed(window_manager(), view1); - - View* view11 = embedded->CreateView(); - view11->SetVisible(true); - embedded->GetRoot()->AddChild(view11); - View* view12 = embedded->CreateView(); - view12->SetVisible(true); - embedded->GetRoot()->AddChild(view12); - - View* view1_in_wm = window_manager()->GetViewById(view1->id()); - - { - WaitForTreeSizeToMatch(view1, 2u); - view11->MoveToFront(); - WaitForOrderChange(window_manager(), - window_manager()->GetViewById(view11->id())); - - EXPECT_EQ(view1_in_wm->children().front(), - window_manager()->GetViewById(view12->id())); - EXPECT_EQ(view1_in_wm->children().back(), - window_manager()->GetViewById(view11->id())); - } - - { - view11->MoveToBack(); - WaitForOrderChange(window_manager(), - window_manager()->GetViewById(view11->id())); - - EXPECT_EQ(view1_in_wm->children().front(), - window_manager()->GetViewById(view11->id())); - EXPECT_EQ(view1_in_wm->children().back(), - window_manager()->GetViewById(view12->id())); - } -} - -namespace { - -class VisibilityChangeObserver : public ViewObserver { - public: - explicit VisibilityChangeObserver(View* view) : view_(view) { - view_->AddObserver(this); - } - ~VisibilityChangeObserver() override { view_->RemoveObserver(this); } - - private: - // Overridden from ViewObserver: - void OnViewVisibilityChanged(View* view) override { - EXPECT_EQ(view, view_); - QuitRunLoop(); - } - - View* view_; - - DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver); -}; - -} // namespace - -TEST_F(ViewManagerTest, DISABLED_Visible) { - View* view1 = window_manager()->CreateView(); - view1->SetVisible(true); - window_manager()->GetRoot()->AddChild(view1); - - // Embed another app and verify initial state. - ViewManager* embedded = Embed(window_manager(), view1); - ASSERT_NE(nullptr, embedded->GetRoot()); - View* embedded_root = embedded->GetRoot(); - EXPECT_TRUE(embedded_root->visible()); - EXPECT_TRUE(embedded_root->IsDrawn()); - - // Change the visible state from the first connection and verify its mirrored - // correctly to the embedded app. - { - VisibilityChangeObserver observer(embedded_root); - view1->SetVisible(false); - DoRunLoop(); - } - - EXPECT_FALSE(view1->visible()); - EXPECT_FALSE(view1->IsDrawn()); - - EXPECT_FALSE(embedded_root->visible()); - EXPECT_FALSE(embedded_root->IsDrawn()); - - // Make the node visible again. - { - VisibilityChangeObserver observer(embedded_root); - view1->SetVisible(true); - DoRunLoop(); - } - - EXPECT_TRUE(view1->visible()); - EXPECT_TRUE(view1->IsDrawn()); - - EXPECT_TRUE(embedded_root->visible()); - EXPECT_TRUE(embedded_root->IsDrawn()); -} - -namespace { - -class DrawnChangeObserver : public ViewObserver { - public: - explicit DrawnChangeObserver(View* view) : view_(view) { - view_->AddObserver(this); - } - ~DrawnChangeObserver() override { view_->RemoveObserver(this); } - - private: - // Overridden from ViewObserver: - void OnViewDrawnChanged(View* view) override { - EXPECT_EQ(view, view_); - QuitRunLoop(); - } - - View* view_; - - DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver); -}; - -} // namespace - -TEST_F(ViewManagerTest, DISABLED_Drawn) { - View* view1 = window_manager()->CreateView(); - view1->SetVisible(true); - window_manager()->GetRoot()->AddChild(view1); - - // Embed another app and verify initial state. - ViewManager* embedded = Embed(window_manager(), view1); - ASSERT_NE(nullptr, embedded->GetRoot()); - View* embedded_root = embedded->GetRoot(); - EXPECT_TRUE(embedded_root->visible()); - EXPECT_TRUE(embedded_root->IsDrawn()); - - // Change the visibility of the root, this should propagate a drawn state - // change to |embedded|. - { - DrawnChangeObserver observer(embedded_root); - window_manager()->GetRoot()->SetVisible(false); - DoRunLoop(); - } - - EXPECT_TRUE(view1->visible()); - EXPECT_FALSE(view1->IsDrawn()); - - EXPECT_TRUE(embedded_root->visible()); - EXPECT_FALSE(embedded_root->IsDrawn()); -} - -// TODO(beng): tests for view event dispatcher. -// - verify that we see events for all views. - -// TODO(beng): tests for focus: -// - focus between two views known to a connection -// - focus between views unknown to one of the connections. -// - focus between views unknown to either connection. - -// TODO(sky): need test of root being destroyed with existing views. See -// 434555 for specific case. - -} // namespace mojo
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/tests/view_unittest.cc b/third_party/mojo_services/src/view_manager/public/cpp/tests/view_unittest.cc index 149eb3a..abbd7125 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/tests/view_unittest.cc +++ b/third_party/mojo_services/src/view_manager/public/cpp/tests/view_unittest.cc
@@ -27,7 +27,7 @@ ~TestView() {} private: - DISALLOW_COPY_AND_ASSIGN(TestView); + MOJO_DISALLOW_COPY_AND_ASSIGN(TestView); }; TEST_F(ViewTest, AddChild) { @@ -148,7 +148,7 @@ private: static TestProperty* last_deleted_; - DISALLOW_COPY_AND_ASSIGN(TestProperty); + MOJO_DISALLOW_COPY_AND_ASSIGN(TestProperty); }; TestProperty* TestProperty::last_deleted_ = NULL; @@ -222,7 +222,7 @@ View* observee_; std::vector<TreeChangeParams> received_params_; - DISALLOW_COPY_AND_ASSIGN(TreeChangeObserver); + MOJO_DISALLOW_COPY_AND_ASSIGN(TreeChangeObserver); }; // Adds/Removes v11 to v1. @@ -463,7 +463,7 @@ View* observee_; Changes changes_; - DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver); + MOJO_DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver); }; } // namespace @@ -613,7 +613,7 @@ View* view_; Changes changes_; - DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver); + MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver); }; } // namespace @@ -669,7 +669,7 @@ View* view_; Changes changes_; - DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver); + MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver); }; } // namespace @@ -775,7 +775,7 @@ View* view_; Changes changes_; - DISALLOW_COPY_AND_ASSIGN(SharedPropertyChangeObserver); + MOJO_DISALLOW_COPY_AND_ASSIGN(SharedPropertyChangeObserver); }; } // namespace @@ -856,7 +856,7 @@ const void* property_key_; intptr_t old_property_value_; - DISALLOW_COPY_AND_ASSIGN(LocalPropertyChangeObserver); + MOJO_DISALLOW_COPY_AND_ASSIGN(LocalPropertyChangeObserver); }; } // namespace
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/view.h b/third_party/mojo_services/src/view_manager/public/cpp/view.h index d888ef0..fcb49bc 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/view.h +++ b/third_party/mojo_services/src/view_manager/public/cpp/view.h
@@ -5,12 +5,13 @@ #ifndef MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_VIEW_H_ #define MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_VIEW_H_ +#include <stdint.h> #include <vector> -#include "base/basictypes.h" #include "base/observer_list.h" #include "geometry/public/interfaces/geometry.mojom.h" #include "mojo/public/cpp/bindings/array.h" +#include "mojo/public/cpp/system/macros.h" #include "mojo/public/interfaces/application/service_provider.mojom.h" #include "surfaces/public/interfaces/surface_id.mojom.h" #include "view_manager/public/cpp/types.h" @@ -87,7 +88,7 @@ void ClearLocalProperty(const ViewProperty<T>* property); // Type of a function to delete a property that this view owns. - typedef void (*PropertyDeallocator)(int64 value); + typedef void (*PropertyDeallocator)(int64_t value); // A View is drawn if the View and all its ancestors are visible and the // View is attached to the root. @@ -141,12 +142,13 @@ View(ViewManager* manager, Id id); // Called by the public {Set,Get,Clear}Property functions. - int64 SetLocalPropertyInternal(const void* key, - const char* name, - PropertyDeallocator deallocator, - int64 value, - int64 default_value); - int64 GetLocalPropertyInternal(const void* key, int64 default_value) const; + int64_t SetLocalPropertyInternal(const void* key, + const char* name, + PropertyDeallocator deallocator, + int64_t value, + int64_t default_value); + int64_t GetLocalPropertyInternal(const void* key, + int64_t default_value) const; void LocalDestroy(); void LocalAddChild(View* child); @@ -157,6 +159,7 @@ void LocalSetViewportMetrics(const ViewportMetrics& old_metrics, const ViewportMetrics& new_metrics); void LocalSetDrawn(bool drawn); + void LocalSetVisible(bool visible); // Methods implementing visibility change notifications. See ViewObserver // for more details. @@ -193,13 +196,13 @@ // WindowProperty<>. struct Value { const char* name; - int64 value; + int64_t value; PropertyDeallocator deallocator; }; std::map<const void*, Value> prop_map_; - DISALLOW_COPY_AND_ASSIGN(View); + MOJO_DISALLOW_COPY_AND_ASSIGN(View); }; } // namespace mojo
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/view_manager_client_factory.h b/third_party/mojo_services/src/view_manager/public/cpp/view_manager_client_factory.h index edb5ca3..e47da3d5 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/view_manager_client_factory.h +++ b/third_party/mojo_services/src/view_manager/public/cpp/view_manager_client_factory.h
@@ -5,7 +5,6 @@ #ifndef MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_VIEW_MANAGER_CLIENT_FACTORY_H_ #define MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_VIEW_MANAGER_CLIENT_FACTORY_H_ -#include "base/memory/scoped_ptr.h" #include "mojo/public/cpp/application/interface_factory.h" #include "view_manager/public/interfaces/view_manager.mojom.h" @@ -22,8 +21,9 @@ ViewManagerClientFactory(Shell* shell, ViewManagerDelegate* delegate); ~ViewManagerClientFactory() override; - // Creates a ViewManagerClient from the supplied arguments. - static scoped_ptr<ViewManagerClient> WeakBindViewManagerToPipe( + // Creates a ViewManagerClient from the supplied arguments. Returns ownership + // to the caller. + static ViewManagerClient* WeakBindViewManagerToPipe( InterfaceRequest<ViewManagerClient> request, ViewManagerServicePtr view_manager_service, Shell* shell,
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/view_manager_context.h b/third_party/mojo_services/src/view_manager/public/cpp/view_manager_context.h index 1976598..de7b84be 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/view_manager_context.h +++ b/third_party/mojo_services/src/view_manager/public/cpp/view_manager_context.h
@@ -8,9 +8,8 @@ #include <string> #include <vector> -#include "base/bind.h" -#include "base/memory/scoped_ptr.h" #include "mojo/public/cpp/application/service_provider_impl.h" +#include "mojo/public/cpp/system/macros.h" namespace mojo { class ApplicationImpl; @@ -37,7 +36,7 @@ private: class InternalState; - scoped_ptr<InternalState> state_; + InternalState* state_; MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerContext); };
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/view_manager_delegate.cc b/third_party/mojo_services/src/view_manager/public/cpp/view_manager_delegate.cc new file mode 100644 index 0000000..4ae64a7b --- /dev/null +++ b/third_party/mojo_services/src/view_manager/public/cpp/view_manager_delegate.cc
@@ -0,0 +1,14 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "view_manager/public/cpp/view_manager_delegate.h" + +namespace mojo { + +bool ViewManagerDelegate::OnPerformAction(View* view, + const std::string& action) { + return false; +} + +} // namespace mojo
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/view_manager_delegate.h b/third_party/mojo_services/src/view_manager/public/cpp/view_manager_delegate.h index e78e9250..1590a591 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/view_manager_delegate.h +++ b/third_party/mojo_services/src/view_manager/public/cpp/view_manager_delegate.h
@@ -5,6 +5,8 @@ #ifndef MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_VIEW_MANAGER_DELEGATE_H_ #define MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_VIEW_MANAGER_DELEGATE_H_ +#include <string> + #include "mojo/public/interfaces/application/service_provider.mojom.h" namespace mojo { @@ -37,6 +39,10 @@ // |view_manager| is not valid after this function returns. virtual void OnViewManagerDisconnected(ViewManager* view_manager) = 0; + // Asks the delegate to perform the specified action. + // TODO(sky): nuke! See comments in view_manager.mojom for details. + virtual bool OnPerformAction(View* view, const std::string& action); + protected: virtual ~ViewManagerDelegate() {} };
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/view_observer.h b/third_party/mojo_services/src/view_manager/public/cpp/view_observer.h index f059e113..341a4f00 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/view_observer.h +++ b/third_party/mojo_services/src/view_manager/public/cpp/view_observer.h
@@ -7,8 +7,6 @@ #include <vector> -#include "base/basictypes.h" - #include "input_events/public/interfaces/input_events.mojom.h" #include "view_manager/public/cpp/view.h"
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/view_property.h b/third_party/mojo_services/src/view_manager/public/cpp/view_property.h index d3a345f..2dbd317b 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/view_property.h +++ b/third_party/mojo_services/src/view_manager/public/cpp/view_property.h
@@ -5,7 +5,7 @@ #ifndef MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_VIEW_PROPERTY_H_ #define MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_VIEW_PROPERTY_H_ -#include "base/basictypes.h" +#include <stdint.h> // This header should be included by code that defines ViewProperties. It // should not be included by code that only gets and sets ViewProperties. @@ -43,27 +43,27 @@ namespace mojo { namespace { -// No single new-style cast works for every conversion to/from int64, so we +// No single new-style cast works for every conversion to/from int64_t, so we // need this helper class. A third specialization is needed for bool because // MSVC warning C4800 (forcing value to bool) is not suppressed by an explicit // cast (!). template <typename T> class ViewPropertyCaster { public: - static int64 ToInt64(T x) { return static_cast<int64>(x); } - static T FromInt64(int64 x) { return static_cast<T>(x); } + static int64_t ToInt64(T x) { return static_cast<int64_t>(x); } + static T FromInt64(int64_t x) { return static_cast<T>(x); } }; template <typename T> class ViewPropertyCaster<T*> { public: - static int64 ToInt64(T* x) { return reinterpret_cast<int64>(x); } - static T* FromInt64(int64 x) { return reinterpret_cast<T*>(x); } + static int64_t ToInt64(T* x) { return reinterpret_cast<int64_t>(x); } + static T* FromInt64(int64_t x) { return reinterpret_cast<T*>(x); } }; template <> class ViewPropertyCaster<bool> { public: - static int64 ToInt64(bool x) { return static_cast<int64>(x); } - static bool FromInt64(int64 x) { return x != 0; } + static int64_t ToInt64(bool x) { return static_cast<int64_t>(x); } + static bool FromInt64(int64_t x) { return x != 0; } }; } // namespace @@ -77,7 +77,7 @@ template <typename T> void View::SetLocalProperty(const ViewProperty<T>* property, T value) { - int64 old = SetLocalPropertyInternal( + int64_t old = SetLocalPropertyInternal( property, property->name, value == property->default_value ? nullptr : property->deallocator, ViewPropertyCaster<T>::ToInt64(value), @@ -111,23 +111,23 @@ const mojo::ViewProperty<T>*); #define DECLARE_VIEW_PROPERTY_TYPE(T) DECLARE_EXPORTED_VIEW_PROPERTY_TYPE(, T) -#define DEFINE_VIEW_PROPERTY_KEY(TYPE, NAME, DEFAULT) \ - COMPILE_ASSERT(sizeof(TYPE) <= sizeof(int64), property_type_too_large); \ - namespace { \ - const mojo::ViewProperty<TYPE> NAME##_Value = {DEFAULT, #NAME, nullptr}; \ - } \ +#define DEFINE_VIEW_PROPERTY_KEY(TYPE, NAME, DEFAULT) \ + COMPILE_ASSERT(sizeof(TYPE) <= sizeof(int64_t), property_type_too_large); \ + namespace { \ + const mojo::ViewProperty<TYPE> NAME##_Value = {DEFAULT, #NAME, nullptr}; \ + } \ const mojo::ViewProperty<TYPE>* const NAME = &NAME##_Value; -#define DEFINE_LOCAL_VIEW_PROPERTY_KEY(TYPE, NAME, DEFAULT) \ - COMPILE_ASSERT(sizeof(TYPE) <= sizeof(int64), property_type_too_large); \ - namespace { \ - const mojo::ViewProperty<TYPE> NAME##_Value = {DEFAULT, #NAME, nullptr}; \ - const mojo::ViewProperty<TYPE>* const NAME = &NAME##_Value; \ +#define DEFINE_LOCAL_VIEW_PROPERTY_KEY(TYPE, NAME, DEFAULT) \ + COMPILE_ASSERT(sizeof(TYPE) <= sizeof(int64_t), property_type_too_large); \ + namespace { \ + const mojo::ViewProperty<TYPE> NAME##_Value = {DEFAULT, #NAME, nullptr}; \ + const mojo::ViewProperty<TYPE>* const NAME = &NAME##_Value; \ } #define DEFINE_OWNED_VIEW_PROPERTY_KEY(TYPE, NAME, DEFAULT) \ namespace { \ - void Deallocator##NAME(int64 p) { \ + void Deallocator##NAME(int64_t p) { \ enum { type_must_be_complete = sizeof(TYPE) }; \ delete mojo::ViewPropertyCaster<TYPE*>::FromInt64(p); \ } \
diff --git a/third_party/mojo_services/src/view_manager/public/cpp/view_tracker.h b/third_party/mojo_services/src/view_manager/public/cpp/view_tracker.h index 05325b7..1d6bf14d 100644 --- a/third_party/mojo_services/src/view_manager/public/cpp/view_tracker.h +++ b/third_party/mojo_services/src/view_manager/public/cpp/view_tracker.h
@@ -5,10 +5,10 @@ #ifndef MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_VIEW_TRACKER_H_ #define MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_VIEW_TRACKER_H_ +#include <stdint.h> #include <set> -#include "base/basictypes.h" -#include "base/compiler_specific.h" +#include "mojo/public/cpp/system/macros.h" #include "view_manager/public/cpp/view_observer.h" namespace mojo { @@ -39,7 +39,7 @@ private: Views views_; - DISALLOW_COPY_AND_ASSIGN(ViewTracker); + MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTracker); }; } // namespace mojo
diff --git a/third_party/mojo_services/src/view_manager/public/interfaces/view_manager.mojom b/third_party/mojo_services/src/view_manager/public/interfaces/view_manager.mojom index 3bd8f1e..0a2564e 100644 --- a/third_party/mojo_services/src/view_manager/public/interfaces/view_manager.mojom +++ b/third_party/mojo_services/src/view_manager/public/interfaces/view_manager.mojom
@@ -142,6 +142,14 @@ ServiceProvider&? services, ServiceProvider? exposed_services) => (bool success); Embed(uint32 view_id, ViewManagerClient client) => (bool success); + + // Requests the WindowManager to perform an action on the specified view. + // It's up to the WindowManager to decide what |action| is. + // + // TODO(sky): nuke this. This is here to guarantee the state of the + // WindowManager matches that of the ViewManager at the time the client + // invokes the function. When we can enforce ordering this won't be necessary. + PerformAction(uint32 view_id, string action) => (bool success); }; // Changes to views are not sent to the connection that originated the @@ -214,4 +222,9 @@ // Invoked when an event is targeted at the specified view. OnViewInputEvent(uint32 view, mojo.Event event) => (); + + // Invoked solely on the WindowManager. See comments in PerformAction() above + // for details. + // TODO(sky): nuke this. + OnPerformAction(uint32 view_id, string action) => (bool success); };
diff --git a/third_party/protobuf/BUILD.gn b/third_party/protobuf/BUILD.gn index 7c036ee..d94a4cb 100644 --- a/third_party/protobuf/BUILD.gn +++ b/third_party/protobuf/BUILD.gn
@@ -264,3 +264,68 @@ deps += [ "//build/config/sanitizers:deps" ] } } + +copy("copy_google") { + sources = [ + "__init__.py", + ] + outputs = [ + "$root_gen_dir/google/{{source_file_part}}", + ] +} + +copy("copy_google_protobuf") { + sources = [ + "python/google/protobuf/__init__.py", + "python/google/protobuf/descriptor.py", + "python/google/protobuf/descriptor_database.py", + "python/google/protobuf/descriptor_pool.py", + "python/google/protobuf/message.py", + "python/google/protobuf/message_factory.py", + "python/google/protobuf/reflection.py", + "python/google/protobuf/service.py", + "python/google/protobuf/service_reflection.py", + "python/google/protobuf/text_format.py", + + # TODO(ncarter): protoc"s python generator treats + # descriptor.proto specially, but it's not possible to trigger + # the special treatment unless you run protoc from ./src/src + # (the treatment is based on the path to the .proto file + # matching a constant exactly). I'm not sure how to convince + # gyp to execute a rule from a different directory. Until this + # is resolved, use a copy of descriptor_pb2.py that I manually + # generated. + "descriptor_pb2.py", + ] + outputs = [ + "$root_gen_dir/google/protobuf/{{source_file_part}}", + ] +} + +copy("copy_google_protobuf_internal") { + sources = [ + "python/google/protobuf/internal/__init__.py", + "python/google/protobuf/internal/api_implementation.py", + "python/google/protobuf/internal/containers.py", + "python/google/protobuf/internal/cpp_message.py", + "python/google/protobuf/internal/decoder.py", + "python/google/protobuf/internal/encoder.py", + "python/google/protobuf/internal/enum_type_wrapper.py", + "python/google/protobuf/internal/generator_test.py", + "python/google/protobuf/internal/message_listener.py", + "python/google/protobuf/internal/python_message.py", + "python/google/protobuf/internal/type_checkers.py", + "python/google/protobuf/internal/wire_format.py", + ] + outputs = [ + "$root_gen_dir/google/protobuf/internal/{{source_file_part}}", + ] +} + +group("py_proto") { + public_deps = [ + ":copy_google", + ":copy_google_protobuf", + ":copy_google_protobuf_internal", + ] +}
diff --git a/tools/auto_bisect/bisect_perf_regression.py b/tools/auto_bisect/bisect_perf_regression.py index 71f701c..746952eb 100755 --- a/tools/auto_bisect/bisect_perf_regression.py +++ b/tools/auto_bisect/bisect_perf_regression.py
@@ -2645,7 +2645,8 @@ '(default), Release_x64 or "Debug".') group.add_argument('--builder_type', default=fetch_build.PERF_BUILDER, choices=[fetch_build.PERF_BUILDER, - fetch_build.FULL_BUILDER, ''], + fetch_build.FULL_BUILDER, + fetch_build.ANDROID_CHROME_PERF_BUILDER, ''], help='Type of builder to get build from. This ' 'determines both the bot that builds and the ' 'place where archived builds are downloaded from. '
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py b/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py index 318c9def..c54af10 100644 --- a/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py
@@ -16,9 +16,6 @@ def Name(cls): return 'chrome_proxy_benchmark.latency.top_20' - def CustomizeBrowserOptions(self, options): - options.AppendExtraBrowserArgs('--enable-spdy-proxy-auth') - class ChromeProxyLatencyDirect(benchmark.Benchmark): tag = 'latency_direct' @@ -55,9 +52,6 @@ def Name(cls): return 'chrome_proxy_benchmark.data_saving.top_20' - def CustomizeBrowserOptions(self, options): - options.AppendExtraBrowserArgs('--enable-spdy-proxy-auth') - class ChromeProxyDataSavingDirect(benchmark.Benchmark): tag = 'data_saving_direct' @@ -115,6 +109,16 @@ return 'chrome_proxy_benchmark.client_type.client_type' +class ChromeProxyLoFi(benchmark.Benchmark): + tag = 'lo_fi' + test = measurements.ChromeProxyLoFi + page_set = pagesets.LoFiPageSet + + @classmethod + def Name(cls): + return 'chrome_proxy_benchmark.lo_fi.lo_fi' + + class ChromeProxyBypass(benchmark.Benchmark): tag = 'bypass' test = measurements.ChromeProxyBypass
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py b/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py index 10ed99b..7fe40df1 100644 --- a/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py
@@ -18,6 +18,9 @@ def __init__(self, *args, **kwargs): super(ChromeProxyLatency, self).__init__(*args, **kwargs) + def CustomizeBrowserOptions(self, options): + options.AppendExtraBrowserArgs('--enable-spdy-proxy-auth') + def WillNavigateToPage(self, page, tab): tab.ClearCache(force=True) @@ -28,11 +31,14 @@ class ChromeProxyDataSaving(page_test.PageTest): - """Chrome proxy data daving measurement.""" + """Chrome proxy data saving measurement.""" def __init__(self, *args, **kwargs): super(ChromeProxyDataSaving, self).__init__(*args, **kwargs) self._metrics = metrics.ChromeProxyMetric() + def CustomizeBrowserOptions(self, options): + options.AppendExtraBrowserArgs('--enable-spdy-proxy-auth') + def WillNavigateToPage(self, page, tab): tab.ClearCache(force=True) self._metrics.Start(page, tab) @@ -87,7 +93,7 @@ if self._expect_timeout: raise metrics.ChromeProxyMetricException, ( 'Timeout was expected, but did not occur') - except exceptions.DevtoolsTargetCrashException, e: + except exceptions.TimeoutException as e: if self._expect_timeout: logging.warning('Navigation timeout on page %s', page.name if page.name else page.url) @@ -205,17 +211,17 @@ """ def __init__(self): - super(ChromeProxyHTTPFallbackProbeURL, self).__init__() + super(ChromeProxyHTTPFallbackProbeURL, self).__init__( + restart_after_each_page=True) def CustomizeBrowserOptions(self, options): super(ChromeProxyHTTPFallbackProbeURL, self).CustomizeBrowserOptions(options) # Use the test server probe URL which returns the response # body as specified by respBody. - probe_url = GetResponseOverrideURL( - respBody='not OK') + probe_url = GetResponseOverrideURL(respBody='not OK') options.AppendExtraBrowserArgs( - '--data-reduction-proxy-probe-url=%s' % probe_url) + '--data-reduction-proxy-secure-proxy-check-url=%s' % probe_url) def AddResults(self, tab, results): self._metrics.AddResultsForHTTPFallback(tab, results) @@ -287,6 +293,20 @@ self._page.bypass_for_client_type) +class ChromeProxyLoFi(ChromeProxyValidation): + """Correctness measurement for Lo-Fi in Chrome-Proxy header.""" + + def __init__(self): + super(ChromeProxyLoFi, self).__init__(restart_after_each_page=True) + + def CustomizeBrowserOptions(self, options): + super(ChromeProxyLoFi, self).CustomizeBrowserOptions(options) + options.AppendExtraBrowserArgs('--enable-data-reduction-proxy-lo-fi') + + def AddResults(self, tab, results): + self._metrics.AddResultsForLoFi(tab, results) + + class ChromeProxyHTTPToDirectFallback(ChromeProxyValidation): """Correctness measurement for HTTP proxy fallback to direct."""
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py b/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py index a8cac704..6513376 100644 --- a/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py
@@ -71,6 +71,15 @@ return kvp[1].strip() return None + def HasChromeProxyLoFi(self): + if 'Chrome-Proxy' not in self.response.request_headers: + return False + chrome_proxy_request_header = self.response.request_headers['Chrome-Proxy'] + values = [v.strip() for v in chrome_proxy_request_header.split(',')] + for value in values: + if len(value) == 5 and value == 'q=low': + return True + return False class ChromeProxyMetric(network_metrics.NetworkMetric): """A Chrome proxy timeline metric.""" @@ -180,6 +189,39 @@ results.AddValue(scalar.ScalarValue( results.current_page, 'bypass', 'count', bypass_count)) + def AddResultsForLoFi(self, tab, results): + lo_fi_count = 0 + + for resp in self.IterResponses(tab): + if resp.HasChromeProxyViaHeader(): + lo_fi_count += 1 + else: + r = resp.response + raise ChromeProxyMetricException, ( + '%s: LoFi not in request header.' % (r.url)) + + cl = resp.content_length + resource = resp.response.url + results.AddValue(scalar.ScalarValue( + results.current_page, 'lo_fi', 'count', lo_fi_count)) + + for resp in self.IterResponses(tab): + r = resp.response + cl = resp.content_length + ocl = resp.original_content_length + saving = resp.data_saving_rate * 100 + if cl > 100: + raise ChromeProxyMetricException, ( + 'Image %s is %d bytes. Expecting less than 100 bytes.' % + (resource, cl)) + + results.AddValue(scalar.ScalarValue( + results.current_page, 'content_length', 'bytes', cl)) + results.AddValue(scalar.ScalarValue( + results.current_page, 'original_content_length', 'bytes', ocl)) + results.AddValue(scalar.ScalarValue( + results.current_page, 'data_saving', 'percent', saving)) + def AddResultsForBypass(self, tab, results): bypass_count = 0
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/lo_fi.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/lo_fi.py new file mode 100644 index 0000000..431098f --- /dev/null +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/lo_fi.py
@@ -0,0 +1,30 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from telemetry.page import page as page_module +from telemetry.page import page_set as page_set_module + + +class LoFiPage(page_module.Page): + """ + A test page for the chrome proxy Lo-Fi tests. + Checks that the compressed image is below a certain threshold. + """ + + def __init__(self, url, page_set): + super(LoFiPage, self).__init__(url=url, page_set=page_set) + + +class LoFiPageSet(page_set_module.PageSet): + """ Chrome proxy test sites """ + + def __init__(self): + super(LoFiPageSet, self).__init__() + + urls_list = [ + 'http://aws1.mdw.la/fw/buddy.jpg', + ] + + for url in urls_list: + self.AddUserStory(LoFiPage(url, self))
diff --git a/tools/chrome_proxy/integration_tests/network_metrics.py b/tools/chrome_proxy/integration_tests/network_metrics.py index 9c41dcc..1af1260 100644 --- a/tools/chrome_proxy/integration_tests/network_metrics.py +++ b/tools/chrome_proxy/integration_tests/network_metrics.py
@@ -98,9 +98,10 @@ try: cl = self.GetContentLengthFromBody() except Exception, e: - resp = self.response logging.warning('Fail to get content length for %s from body: %s', - resp.url[:100], e) + self.response.url[:100], e) + if cl == 0: + resp = self.response cl_header = resp.GetHeader('Content-Length') if cl_header: cl = int(cl_header) @@ -170,7 +171,7 @@ ocl = resp.original_content_length if ocl < cl: logging.warning('original content length (%d) is less than content ' - 'lenght(%d) for resource %s', ocl, cl, resource) + 'length (%d) for resource %s', ocl, cl, resource) if self.add_result_for_resource: results.AddValue(scalar.ScalarValue( results.current_page,
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp index fb87ce8..2d221d7 100644 --- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp +++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
@@ -315,6 +315,20 @@ return true; } + bool VisitUnresolvedMemberExpr(UnresolvedMemberExpr* member) { + for (Decl* decl : member->decls()) { + if (CXXMethodDecl* method = dyn_cast<CXXMethodDecl>(decl)) { + if (method->getParent() == receiver_->record() && + Config::GetTraceMethodType(method) == + Config::TRACE_AFTER_DISPATCH_METHOD) { + dispatched_to_receiver_ = true; + return true; + } + } + } + return true; + } + private: RecordInfo* receiver_; bool dispatched_to_receiver_; @@ -325,8 +339,12 @@ // - A base is traced if a base-qualified call to a trace method is found. class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { public: - CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info) - : trace_(trace), info_(info), delegates_to_traceimpl_(false) {} + CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info, RecordCache* cache) + : trace_(trace), + info_(info), + cache_(cache), + delegates_to_traceimpl_(false) { + } bool delegates_to_traceimpl() const { return delegates_to_traceimpl_; } @@ -370,17 +388,8 @@ if (CheckTraceBaseCall(call)) return true; - // If we find a call to registerWeakMembers which is unresolved we - // unsoundly consider all weak members as traced. - // TODO: Find out how to validate weak member tracing for unresolved call. - if (expr->getMemberName().getAsString() == kRegisterWeakMembersName) { - for (RecordInfo::Fields::iterator it = info_->GetFields().begin(); - it != info_->GetFields().end(); - ++it) { - if (it->second.edge()->IsWeakMember()) - it->second.MarkTraced(); - } - } + if (expr->getMemberName().getAsString() == kRegisterWeakMembersName) + MarkAllWeakMembersTraced(); QualType base = expr->getBaseType(); if (!base->isPointerType()) @@ -436,18 +445,23 @@ CXXDependentScopeMemberExpr* expr) { string fn_name = expr->getMember().getAsString(); - // Check for VisitorDispatcher::trace(field) + // Check for VisitorDispatcher::trace(field) and + // VisitorDispatcher::registerWeakMembers. if (!expr->isImplicitAccess()) { if (clang::DeclRefExpr* base_decl = clang::dyn_cast<clang::DeclRefExpr>(expr->getBase())) { - if (Config::IsVisitorDispatcherType(base_decl->getType()) && - call->getNumArgs() == 1 && fn_name == kTraceName) { - FindFieldVisitor finder; - finder.TraverseStmt(call->getArg(0)); - if (finder.field()) - FoundField(finder.field()); + if (Config::IsVisitorDispatcherType(base_decl->getType())) { + if (call->getNumArgs() == 1 && fn_name == kTraceName) { + FindFieldVisitor finder; + finder.TraverseStmt(call->getArg(0)); + if (finder.field()) + FoundField(finder.field()); - return; + return; + } else if (call->getNumArgs() == 1 && + fn_name == kRegisterWeakMembersName) { + MarkAllWeakMembersTraced(); + } } } } @@ -541,12 +555,48 @@ if (!IsTraceCallName(func_name)) return false; - RecordInfo::Bases::iterator iter = info_->GetBases().find(callee_record); - if (iter == info_->GetBases().end()) - return false; + for (auto& base : info_->GetBases()) { + // We want to deal with omitted trace() function in an intermediary + // class in the class hierarchy, e.g.: + // class A : public GarbageCollected<A> { trace() { ... } }; + // class B : public A { /* No trace(); have nothing to trace. */ }; + // class C : public B { trace() { B::trace(visitor); } } + // where, B::trace() is actually A::trace(), and in some cases we get + // A as |callee_record| instead of B. We somehow need to mark B as + // traced if we find A::trace() call. + // + // To solve this, here we keep going up the class hierarchy as long as + // they are not required to have a trace method. The implementation is + // a simple DFS, where |base_records| represents the set of base classes + // we need to visit. - iter->second.MarkTraced(); - return true; + std::vector<CXXRecordDecl*> base_records; + base_records.push_back(base.first); + + while (!base_records.empty()) { + CXXRecordDecl* base_record = base_records.back(); + base_records.pop_back(); + + if (base_record == callee_record) { + // If we find a matching trace method, pretend the user has written + // a correct trace() method of the base; in the example above, we + // find A::trace() here and mark B as correctly traced. + base.second.MarkTraced(); + return true; + } + + if (RecordInfo* base_info = cache_->Lookup(base_record)) { + if (!base_info->RequiresTraceMethod()) { + // If this base class is not required to have a trace method, then + // the actual trace method may be defined in an ancestor. + for (auto& inner_base : base_info->GetBases()) + base_records.push_back(inner_base.first); + } + } + } + } + + return false; } bool CheckTraceFieldCall(CXXMemberCallExpr* call) { @@ -609,7 +659,8 @@ }; // Nested checking for weak callbacks. - CheckTraceVisitor(RecordInfo* info) : trace_(0), info_(info) {} + CheckTraceVisitor(RecordInfo* info) + : trace_(nullptr), info_(info), cache_(nullptr) {} bool IsWeakCallback() { return !trace_; } @@ -641,8 +692,19 @@ } } + void MarkAllWeakMembersTraced() { + // If we find a call to registerWeakMembers which is unresolved we + // unsoundly consider all weak members as traced. + // TODO: Find out how to validate weak member tracing for unresolved call. + for (auto& field : info_->GetFields()) { + if (field.second.edge()->IsWeakMember()) + field.second.MarkTraced(); + } + } + CXXMethodDecl* trace_; RecordInfo* info_; + RecordCache* cache_; bool delegates_to_traceimpl_; }; @@ -1069,7 +1131,8 @@ CheckLeftMostDerived(info); CheckDispatch(info); if (CXXMethodDecl* newop = info->DeclaresNewOperator()) - ReportClassOverridesNew(info, newop); + if (!Config::IsIgnoreAnnotated(newop)) + ReportClassOverridesNew(info, newop); if (info->IsGCMixinInstance()) { // Require that declared GCMixin implementations // also provide a trace() override. @@ -1365,7 +1428,8 @@ // Determine what type of tracing method this is (dispatch or trace). void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) { Config::TraceMethodType trace_type = Config::GetTraceMethodType(method); - if (trace_type != Config::TRACE_METHOD || + if (trace_type == Config::TRACE_AFTER_DISPATCH_METHOD || + trace_type == Config::TRACE_AFTER_DISPATCH_IMPL_METHOD || !parent->GetTraceDispatchMethod()) { CheckTraceMethod(parent, method, trace_type); } @@ -1387,7 +1451,7 @@ } } - CheckTraceVisitor visitor(trace, parent); + CheckTraceVisitor visitor(trace, parent, &cache_); visitor.TraverseCXXMethodDecl(trace); // Skip reporting if this trace method is a just delegate to
diff --git a/tools/clang/blink_gc_plugin/CMakeLists.txt b/tools/clang/blink_gc_plugin/CMakeLists.txt index c511edf..7f1dee3 100644 --- a/tools/clang/blink_gc_plugin/CMakeLists.txt +++ b/tools/clang/blink_gc_plugin/CMakeLists.txt
@@ -1,6 +1,6 @@ # This line is read by update.sh and other scripts in tools/clang/scripts # Note: The spaces are significant. -set(LIBRARYNAME BlinkGCPlugin_14) +set(LIBRARYNAME BlinkGCPlugin) add_llvm_loadable_module("lib${LIBRARYNAME}" BlinkGCPlugin.cpp
diff --git a/tools/clang/blink_gc_plugin/Config.h b/tools/clang/blink_gc_plugin/Config.h index c2d39b7..02cbee9a 100644 --- a/tools/clang/blink_gc_plugin/Config.h +++ b/tools/clang/blink_gc_plugin/Config.h
@@ -236,7 +236,7 @@ if (name == kTraceAfterDispatchName) return TRACE_AFTER_DISPATCH_METHOD; if (name == kTraceImplName) - return TRACE_AFTER_DISPATCH_METHOD; + return TRACE_IMPL_METHOD; if (name == kTraceAfterDispatchImplName) return TRACE_AFTER_DISPATCH_IMPL_METHOD;
diff --git a/tools/clang/blink_gc_plugin/Edge.h b/tools/clang/blink_gc_plugin/Edge.h index d0b78b5..7659968 100644 --- a/tools/clang/blink_gc_plugin/Edge.h +++ b/tools/clang/blink_gc_plugin/Edge.h
@@ -24,6 +24,7 @@ // Bare-bones visitor. class EdgeVisitor { public: + virtual ~EdgeVisitor() {} virtual void VisitValue(Value*) {} virtual void VisitRawPtr(RawPtr*) {} virtual void VisitRefPtr(RefPtr*) {}
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.cpp b/tools/clang/blink_gc_plugin/RecordInfo.cpp index 0257415..bda33fa9 100644 --- a/tools/clang/blink_gc_plugin/RecordInfo.cpp +++ b/tools/clang/blink_gc_plugin/RecordInfo.cpp
@@ -427,39 +427,50 @@ if (Config::IsGCBase(name_)) return; CXXMethodDecl* trace = nullptr; + CXXMethodDecl* trace_impl = nullptr; CXXMethodDecl* trace_after_dispatch = nullptr; bool has_adjust_and_mark = false; bool has_is_heap_object_alive = false; - for (CXXRecordDecl::method_iterator it = record_->method_begin(); - it != record_->method_end(); - ++it) { - switch (Config::GetTraceMethodType(*it)) { + for (Decl* decl : record_->decls()) { + CXXMethodDecl* method = dyn_cast<CXXMethodDecl>(decl); + if (!method) { + if (FunctionTemplateDecl* func_template = + dyn_cast<FunctionTemplateDecl>(decl)) + method = dyn_cast<CXXMethodDecl>(func_template->getTemplatedDecl()); + } + if (!method) + continue; + + switch (Config::GetTraceMethodType(method)) { case Config::TRACE_METHOD: - trace = *it; + trace = method; break; case Config::TRACE_AFTER_DISPATCH_METHOD: - trace_after_dispatch = *it; + trace_after_dispatch = method; break; case Config::TRACE_IMPL_METHOD: + trace_impl = method; + break; case Config::TRACE_AFTER_DISPATCH_IMPL_METHOD: break; case Config::NOT_TRACE_METHOD: - if (it->getNameAsString() == kFinalizeName) { - finalize_dispatch_method_ = *it; - } else if (it->getNameAsString() == kAdjustAndMarkName) { + if (method->getNameAsString() == kFinalizeName) { + finalize_dispatch_method_ = method; + } else if (method->getNameAsString() == kAdjustAndMarkName) { has_adjust_and_mark = true; - } else if (it->getNameAsString() == kIsHeapObjectAliveName) { + } else if (method->getNameAsString() == kIsHeapObjectAliveName) { has_is_heap_object_alive = true; } break; } } + // Record if class defines the two GCMixin methods. has_gc_mixin_methods_ = has_adjust_and_mark && has_is_heap_object_alive ? kTrue : kFalse; if (trace_after_dispatch) { trace_method_ = trace_after_dispatch; - trace_dispatch_method_ = trace; + trace_dispatch_method_ = trace_impl ? trace_impl : trace; } else { // TODO: Can we never have a dispatch method called trace without the same // class defining a traceAfterDispatch method?
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.h b/tools/clang/blink_gc_plugin/RecordInfo.h index 82fb604..da2f415 100644 --- a/tools/clang/blink_gc_plugin/RecordInfo.h +++ b/tools/clang/blink_gc_plugin/RecordInfo.h
@@ -23,6 +23,7 @@ class GraphPoint { public: GraphPoint() : traced_(false) {} + virtual ~GraphPoint() {} void MarkTraced() { traced_ = true; } bool IsProperlyTraced() { return traced_ || !NeedsTracing().IsNeeded(); } virtual const TracingStatus NeedsTracing() = 0;
diff --git a/tools/clang/blink_gc_plugin/tests/heap/stubs.h b/tools/clang/blink_gc_plugin/tests/heap/stubs.h index 3220178..e8ff1b3 100644 --- a/tools/clang/blink_gc_plugin/tests/heap/stubs.h +++ b/tools/clang/blink_gc_plugin/tests/heap/stubs.h
@@ -220,7 +220,10 @@ class InlinedGlobalMarkingVisitor : public VisitorHelper<InlinedGlobalMarkingVisitor> { public: - InlinedGlobalMarkingVisitor* operator->() { return this; } + InlinedGlobalMarkingVisitor* operator->() { return this; } + + template<typename T, void (T::*method)(Visitor*)> + void registerWeakMembers(const T* obj); }; class GarbageCollectedMixin {
diff --git a/tools/clang/blink_gc_plugin/tests/register_weak_members_template.cpp b/tools/clang/blink_gc_plugin/tests/register_weak_members_template.cpp new file mode 100644 index 0000000..6742c22 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/register_weak_members_template.cpp
@@ -0,0 +1,7 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "register_weak_members_template.h" + +// Nothing to define here.
diff --git a/tools/clang/blink_gc_plugin/tests/register_weak_members_template.h b/tools/clang/blink_gc_plugin/tests/register_weak_members_template.h new file mode 100644 index 0000000..7d3905a --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/register_weak_members_template.h
@@ -0,0 +1,43 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REGISTER_WEAK_MEMBERS_TEMPLATE_H_ +#define REGISTER_WEAK_MEMBERS_TEMPLATE_H_ + +#include "heap/stubs.h" + +namespace blink { + +class X : public GarbageCollected<X> { + public: + void trace(Visitor* visitor) { traceImpl(visitor); } + void trace(InlinedGlobalMarkingVisitor visitor) { traceImpl(visitor); } + + private: + template <typename VisitorDispatcher> + void traceImpl(VisitorDispatcher visitor) {} +}; + +class HasUntracedWeakMembers : public GarbageCollected<HasUntracedWeakMembers> { + public: + void trace(Visitor* visitor) { traceImpl(visitor); } + void trace(InlinedGlobalMarkingVisitor visitor) { traceImpl(visitor); } + + // Don't have to be defined for the purpose of this test. + void clearWeakMembers(Visitor* visitor); + + private: + template <typename VisitorDispatcher> + void traceImpl(VisitorDispatcher visitor) { + visitor->template registerWeakMembers< + HasUntracedWeakMembers, + &HasUntracedWeakMembers::clearWeakMembers>(this); + } + + WeakMember<X> x_; +}; + +} + +#endif // REGISTER_WEAK_MEMBERS_TEMPLATE_H_
diff --git a/tools/clang/blink_gc_plugin/tests/register_weak_members_template.txt b/tools/clang/blink_gc_plugin/tests/register_weak_members_template.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/register_weak_members_template.txt
@@ -0,0 +1 @@ +
diff --git a/tools/clang/blink_gc_plugin/tests/test.sh b/tools/clang/blink_gc_plugin/tests/test.sh index 02c7477..95bb261 100755 --- a/tools/clang/blink_gc_plugin/tests/test.sh +++ b/tools/clang/blink_gc_plugin/tests/test.sh
@@ -29,6 +29,7 @@ flags="$(cat "${3}")" fi local output="$("${CLANG_PATH}" -c -Wno-c++11-extensions \ + -Wno-inaccessible-base \ -Xclang -load -Xclang "${PLUGIN_PATH}" \ -Xclang -add-plugin -Xclang blink-gc-plugin ${flags} ${1} 2>&1)" local json="${input%cpp}graph.json"
diff --git a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.cpp b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.cpp index 706624d..53a6855 100644 --- a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.cpp +++ b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.cpp
@@ -6,9 +6,11 @@ namespace blink { -void TraceAfterDispatchInlinedBase::trace(Visitor* visitor) { - // Implement a simple form of manual dispatching, because BlinkGCPlugin gets - // angry if dispatching statements are missing. +template <typename VisitorDispatcher> +inline void TraceAfterDispatchInlinedBase::traceImpl( + VisitorDispatcher visitor) { + // Implement a simple form of manual dispatching, because BlinkGCPlugin + // checks if the tracing is dispatched to all derived classes. // // This function has to be implemented out-of-line, since we need to know the // definition of derived classes here. @@ -21,6 +23,15 @@ } void TraceAfterDispatchExternBase::trace(Visitor* visitor) { + traceImpl(visitor); +} + +void TraceAfterDispatchExternBase::trace(InlinedGlobalMarkingVisitor visitor) { + traceImpl(visitor); +} + +template <typename VisitorDispatcher> +inline void TraceAfterDispatchExternBase::traceImpl(VisitorDispatcher visitor) { if (tag_ == DERIVED) { static_cast<TraceAfterDispatchExternDerived*>(this)->traceAfterDispatch( visitor); @@ -33,6 +44,11 @@ traceAfterDispatchImpl(visitor); } +void TraceAfterDispatchExternBase::traceAfterDispatch( + InlinedGlobalMarkingVisitor visitor) { + traceAfterDispatchImpl(visitor); +} + template <typename VisitorDispatcher> inline void TraceAfterDispatchExternBase::traceAfterDispatchImpl( VisitorDispatcher visitor) { @@ -43,6 +59,11 @@ traceAfterDispatchImpl(visitor); } +void TraceAfterDispatchExternDerived::traceAfterDispatch( + InlinedGlobalMarkingVisitor visitor) { + traceAfterDispatchImpl(visitor); +} + template <typename VisitorDispatcher> inline void TraceAfterDispatchExternDerived::traceAfterDispatchImpl( VisitorDispatcher visitor) {
diff --git a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.h b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.h index e55c06e..fe25279 100644 --- a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.h +++ b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.h
@@ -23,12 +23,19 @@ public: explicit TraceAfterDispatchInlinedBase(ClassTag tag) : tag_(tag) {} - void trace(Visitor* visitor); + void trace(Visitor* visitor) { traceImpl(visitor); } + void trace(InlinedGlobalMarkingVisitor visitor) { traceImpl(visitor); } void traceAfterDispatch(Visitor* visitor) { traceAfterDispatchImpl(visitor); } + void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor) { + traceAfterDispatchImpl(visitor); + } private: template <typename VisitorDispatcher> + void traceImpl(VisitorDispatcher visitor); + + template <typename VisitorDispatcher> void traceAfterDispatchImpl(VisitorDispatcher visitor) { visitor->trace(x_base_); } @@ -42,6 +49,9 @@ TraceAfterDispatchInlinedDerived() : TraceAfterDispatchInlinedBase(DERIVED) {} void traceAfterDispatch(Visitor* visitor) { traceAfterDispatchImpl(visitor); } + void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor) { + traceAfterDispatchImpl(visitor); + } private: template <typename VisitorDispatcher> @@ -59,11 +69,16 @@ explicit TraceAfterDispatchExternBase(ClassTag tag) : tag_(tag) {} void trace(Visitor* visitor); + void trace(InlinedGlobalMarkingVisitor visitor); void traceAfterDispatch(Visitor* visitor); + void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor); private: template <typename VisitorDispatcher> + void traceImpl(VisitorDispatcher visitor); + + template <typename VisitorDispatcher> void traceAfterDispatchImpl(VisitorDispatcher visitor); ClassTag tag_; @@ -75,6 +90,7 @@ TraceAfterDispatchExternDerived() : TraceAfterDispatchExternBase(DERIVED) {} void traceAfterDispatch(Visitor* visitor); + void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor); private: template <typename VisitorDispatcher>
diff --git a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.cpp b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.cpp index 1ea19364..23798f7 100644 --- a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.cpp +++ b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.cpp
@@ -6,24 +6,37 @@ namespace blink { -void TraceAfterDispatchInlinedBase::trace(Visitor* visitor) { - // Implement a simple form of manual dispatching, because BlinkGCPlugin gets - // angry if dispatching statements are missing. +template <typename VisitorDispatcher> +inline void TraceAfterDispatchInlinedBase::traceImpl( + VisitorDispatcher visitor) { + // Implement a simple form of manual dispatching, because BlinkGCPlugin + // checks if the tracing is dispatched to all derived classes. // // This function has to be implemented out-of-line, since we need to know the // definition of derived classes here. if (tag_ == DERIVED) { - static_cast<TraceAfterDispatchInlinedDerived*>(this)->traceAfterDispatch( - visitor); + // Missing dispatch call: + // static_cast<TraceAfterDispatchInlinedDerived*>(this)->traceAfterDispatch( + // visitor); } else { traceAfterDispatch(visitor); } } void TraceAfterDispatchExternBase::trace(Visitor* visitor) { + traceImpl(visitor); +} + +void TraceAfterDispatchExternBase::trace(InlinedGlobalMarkingVisitor visitor) { + traceImpl(visitor); +} + +template <typename VisitorDispatcher> +inline void TraceAfterDispatchExternBase::traceImpl(VisitorDispatcher visitor) { if (tag_ == DERIVED) { - static_cast<TraceAfterDispatchExternDerived*>(this)->traceAfterDispatch( - visitor); + // Missing dispatch call: + // static_cast<TraceAfterDispatchExternDerived*>(this)->traceAfterDispatch( + // visitor); } else { traceAfterDispatch(visitor); } @@ -33,6 +46,11 @@ traceAfterDispatchImpl(visitor); } +void TraceAfterDispatchExternBase::traceAfterDispatch( + InlinedGlobalMarkingVisitor visitor) { + traceAfterDispatchImpl(visitor); +} + template <typename VisitorDispatcher> inline void TraceAfterDispatchExternBase::traceAfterDispatchImpl( VisitorDispatcher visitor) { @@ -43,6 +61,11 @@ traceAfterDispatchImpl(visitor); } +void TraceAfterDispatchExternDerived::traceAfterDispatch( + InlinedGlobalMarkingVisitor visitor) { + traceAfterDispatchImpl(visitor); +} + template <typename VisitorDispatcher> inline void TraceAfterDispatchExternDerived::traceAfterDispatchImpl( VisitorDispatcher visitor) {
diff --git a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.h b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.h index 441ef32..b480e39 100644 --- a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.h +++ b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.h
@@ -23,12 +23,19 @@ public: explicit TraceAfterDispatchInlinedBase(ClassTag tag) : tag_(tag) {} - void trace(Visitor* visitor); + void trace(Visitor* visitor) { traceImpl(visitor); } + void trace(InlinedGlobalMarkingVisitor visitor) { traceImpl(visitor); } void traceAfterDispatch(Visitor* visitor) { traceAfterDispatchImpl(visitor); } + void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor) { + traceAfterDispatchImpl(visitor); + } private: template <typename VisitorDispatcher> + void traceImpl(VisitorDispatcher visitor); + + template <typename VisitorDispatcher> void traceAfterDispatchImpl(VisitorDispatcher visitor) { // No trace call; should get a warning. } @@ -42,6 +49,9 @@ TraceAfterDispatchInlinedDerived() : TraceAfterDispatchInlinedBase(DERIVED) {} void traceAfterDispatch(Visitor* visitor) { traceAfterDispatchImpl(visitor); } + void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor) { + traceAfterDispatchImpl(visitor); + } private: template <typename VisitorDispatcher> @@ -58,11 +68,16 @@ explicit TraceAfterDispatchExternBase(ClassTag tag) : tag_(tag) {} void trace(Visitor* visitor); + void trace(InlinedGlobalMarkingVisitor visitor); void traceAfterDispatch(Visitor* visitor); + void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor); private: template <typename VisitorDispatcher> + void traceImpl(VisitorDispatcher visitor); + + template <typename VisitorDispatcher> void traceAfterDispatchImpl(VisitorDispatcher visitor); ClassTag tag_; @@ -74,6 +89,7 @@ TraceAfterDispatchExternDerived() : TraceAfterDispatchExternBase(DERIVED) {} void traceAfterDispatch(Visitor* visitor); + void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor); private: template <typename VisitorDispatcher>
diff --git a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.txt b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.txt index 68b5a72..058fccb8 100644 --- a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.txt +++ b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.txt
@@ -1,28 +1,34 @@ +trace_after_dispatch_impl_error.cpp:10:1: warning: [blink-gc] Missing dispatch to class 'TraceAfterDispatchInlinedDerived' in manual trace dispatch. +inline void TraceAfterDispatchInlinedBase::traceImpl( +^ +trace_after_dispatch_impl_error.cpp:35:1: warning: [blink-gc] Missing dispatch to class 'TraceAfterDispatchExternDerived' in manual trace dispatch. +inline void TraceAfterDispatchExternBase::traceImpl(VisitorDispatcher visitor) { +^ In file included from trace_after_dispatch_impl_error.cpp:5: -./trace_after_dispatch_impl_error.h:32:3: warning: [blink-gc] Class 'TraceAfterDispatchInlinedBase' has untraced fields that require tracing. +./trace_after_dispatch_impl_error.h:39:3: warning: [blink-gc] Class 'TraceAfterDispatchInlinedBase' has untraced fields that require tracing. void traceAfterDispatchImpl(VisitorDispatcher visitor) { ^ -./trace_after_dispatch_impl_error.h:37:3: note: [blink-gc] Untraced field 'x_base_' declared here: +./trace_after_dispatch_impl_error.h:44:3: note: [blink-gc] Untraced field 'x_base_' declared here: Member<X> x_base_; ^ -./trace_after_dispatch_impl_error.h:48:3: warning: [blink-gc] Base class 'TraceAfterDispatchInlinedBase' of derived class 'TraceAfterDispatchInlinedDerived' requires tracing. +./trace_after_dispatch_impl_error.h:58:3: warning: [blink-gc] Base class 'TraceAfterDispatchInlinedBase' of derived class 'TraceAfterDispatchInlinedDerived' requires tracing. void traceAfterDispatchImpl(VisitorDispatcher visitor) { ^ -./trace_after_dispatch_impl_error.h:48:3: warning: [blink-gc] Class 'TraceAfterDispatchInlinedDerived' has untraced fields that require tracing. -./trace_after_dispatch_impl_error.h:52:3: note: [blink-gc] Untraced field 'x_derived_' declared here: +./trace_after_dispatch_impl_error.h:58:3: warning: [blink-gc] Class 'TraceAfterDispatchInlinedDerived' has untraced fields that require tracing. +./trace_after_dispatch_impl_error.h:62:3: note: [blink-gc] Untraced field 'x_derived_' declared here: Member<X> x_derived_; ^ -trace_after_dispatch_impl_error.cpp:37:1: warning: [blink-gc] Class 'TraceAfterDispatchExternBase' has untraced fields that require tracing. +trace_after_dispatch_impl_error.cpp:55:1: warning: [blink-gc] Class 'TraceAfterDispatchExternBase' has untraced fields that require tracing. inline void TraceAfterDispatchExternBase::traceAfterDispatchImpl( ^ -./trace_after_dispatch_impl_error.h:69:3: note: [blink-gc] Untraced field 'x_base_' declared here: +./trace_after_dispatch_impl_error.h:84:3: note: [blink-gc] Untraced field 'x_base_' declared here: Member<X> x_base_; ^ -trace_after_dispatch_impl_error.cpp:47:1: warning: [blink-gc] Base class 'TraceAfterDispatchExternBase' of derived class 'TraceAfterDispatchExternDerived' requires tracing. +trace_after_dispatch_impl_error.cpp:70:1: warning: [blink-gc] Base class 'TraceAfterDispatchExternBase' of derived class 'TraceAfterDispatchExternDerived' requires tracing. inline void TraceAfterDispatchExternDerived::traceAfterDispatchImpl( ^ -trace_after_dispatch_impl_error.cpp:47:1: warning: [blink-gc] Class 'TraceAfterDispatchExternDerived' has untraced fields that require tracing. -./trace_after_dispatch_impl_error.h:82:3: note: [blink-gc] Untraced field 'x_derived_' declared here: +trace_after_dispatch_impl_error.cpp:70:1: warning: [blink-gc] Class 'TraceAfterDispatchExternDerived' has untraced fields that require tracing. +./trace_after_dispatch_impl_error.h:98:3: note: [blink-gc] Untraced field 'x_derived_' declared here: Member<X> x_derived_; ^ -6 warnings generated. +8 warnings generated.
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.cpp b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.cpp new file mode 100644 index 0000000..b6dc2dff --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.cpp
@@ -0,0 +1,7 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "traceimpl_omitted_trace.h" + +// Nothing to define here.
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.h b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.h new file mode 100644 index 0000000..3c5e955 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.h
@@ -0,0 +1,47 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TRACEIMPL_OMITTED_TRACE_H_ +#define TRACEIMPL_OMITTED_TRACE_H_ + +#include "heap/stubs.h" + +namespace blink { + +class A : public GarbageCollected<A> { + public: + virtual void trace(Visitor* visitor) { traceImpl(visitor); } + virtual void trace(InlinedGlobalMarkingVisitor visitor) { + traceImpl(visitor); + } + + private: + template <typename VisitorDispatcher> + void traceImpl(VisitorDispatcher visitor) {} +}; + +class B : public A { + // trace() isn't necessary because we've got nothing to trace here. +}; + +class C : public B { + public: + void trace(Visitor* visitor) override { traceImpl(visitor); } + void trace(InlinedGlobalMarkingVisitor visitor) override { + traceImpl(visitor); + } + + private: + template <typename VisitorDispatcher> + void traceImpl(VisitorDispatcher visitor) { + // B::trace() is actually A::trace(), and in certain cases we only get + // limited information like "there is a function call that will be resolved + // to A::trace()". We still want to mark B as traced. + B::trace(visitor); + } +}; + +} + +#endif // TRACEIMPL_OMITTED_TRACE_H_
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.txt b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.txt
@@ -0,0 +1 @@ +
diff --git a/tools/clang/scripts/blink_gc_plugin_flags.sh b/tools/clang/scripts/blink_gc_plugin_flags.sh index 3654808..38ea72d 100755 --- a/tools/clang/scripts/blink_gc_plugin_flags.sh +++ b/tools/clang/scripts/blink_gc_plugin_flags.sh
@@ -13,9 +13,6 @@ else LIBSUFFIX=so fi -LIBNAME=\ -$(grep 'set(LIBRARYNAME' "$SRC_DIR"/tools/clang/blink_gc_plugin/CMakeLists.txt \ - | cut -d ' ' -f 2 | tr -d ')') FLAGS="" PREFIX="-Xclang -plugin-arg-blink-gc-plugin -Xclang" @@ -31,5 +28,5 @@ fi done -echo -Xclang -load -Xclang $CLANG_LIB_PATH/lib$LIBNAME.$LIBSUFFIX \ +echo -Xclang -load -Xclang $CLANG_LIB_PATH/libBlinkGCPlugin.$LIBSUFFIX \ -Xclang -add-plugin -Xclang blink-gc-plugin $FLAGS
diff --git a/tools/clang/scripts/package.sh b/tools/clang/scripts/package.sh index e0c0fcc4..453a166 100755 --- a/tools/clang/scripts/package.sh +++ b/tools/clang/scripts/package.sh
@@ -52,6 +52,7 @@ LLVM_BUILD_DIR="${THIS_DIR}/../../../third_party/llvm-build" LLVM_BIN_DIR="${LLVM_BUILD_DIR}/Release+Asserts/bin" LLVM_LIB_DIR="${LLVM_BUILD_DIR}/Release+Asserts/lib" +STAMP_FILE="${LLVM_DIR}/../llvm-build/cr_build_revision" echo "Diff in llvm:" | tee buildlog.txt svn stat "${LLVM_DIR}" 2>&1 | tee -a buildlog.txt @@ -86,8 +87,7 @@ "${THIS_DIR}"/update.sh --bootstrap --force-local-build --run-tests \ ${extra_flags} 2>&1 | tee -a buildlog.txt -R=$("${LLVM_BIN_DIR}/clang" --version | \ - sed -ne 's/clang version .*(trunk \([0-9]*\))/\1/p') +R=$(cat "${STAMP_FILE}") PDIR=clang-$R rm -rf $PDIR @@ -122,11 +122,7 @@ # Copy plugins. Some of the dylibs are pretty big, so copy only the ones we # care about. cp "${LLVM_LIB_DIR}/libFindBadConstructs.${SO_EXT}" $PDIR/lib - -BLINKGCPLUGIN_LIBNAME=\ -$(grep 'set(LIBRARYNAME' "$THIS_DIR"/../blink_gc_plugin/CMakeLists.txt \ - | cut -d ' ' -f 2 | tr -d ')') -cp "${LLVM_LIB_DIR}/lib${BLINKGCPLUGIN_LIBNAME}.${SO_EXT}" $PDIR/lib +cp "${LLVM_LIB_DIR}/libBlinkGCPlugin.${SO_EXT}" $PDIR/lib if [[ -n "${gcc_toolchain}" ]]; then # Copy the stdlibc++.so.6 we linked Clang against so it can run. @@ -182,3 +178,5 @@ echo To upload, run: echo gsutil cp -a public-read $PDIR.tgz \ gs://chromium-browser-clang/$PLATFORM/$PDIR.tgz + +# FIXME: Warn if the file already exists on the server.
diff --git a/tools/clang/scripts/plugin_flags.py b/tools/clang/scripts/plugin_flags.py new file mode 100755 index 0000000..3f61d6b --- /dev/null +++ b/tools/clang/scripts/plugin_flags.py
@@ -0,0 +1,29 @@ +#!/usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This script returns the flags that should be used when GYP_DEFINES contains +# clang_use_chrome_plugins. The flags are stored in a script so that they can +# be changed on the bots without requiring a master restart. + +import os +import sys + +# Path constants. (All of these should be absolute paths.) +THIS_DIR = os.path.abspath(os.path.dirname(__file__)) +CHROMIUM_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', '..', '..')) +CLANG_LIB_PATH = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm-build', + 'Release+Asserts', 'lib') + +if sys.platform == 'darwin': + LIBSUFFIX = 'dylib' +else: + LIBSUFFIX = 'so' + +LIB_PATH = os.path.join( + CLANG_LIB_PATH, + 'libFindBadConstructs.' + LIBSUFFIX) + +print ('-Xclang -load -Xclang %s' + ' -Xclang -add-plugin -Xclang find-bad-constructs') % LIB_PATH
diff --git a/tools/clang/scripts/plugin_flags.sh b/tools/clang/scripts/plugin_flags.sh deleted file mode 100755 index 81fe0f1d..0000000 --- a/tools/clang/scripts/plugin_flags.sh +++ /dev/null
@@ -1,22 +0,0 @@ -#!/usr/bin/env bash -# 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 script returns the flags that should be used when GYP_DEFINES contains -# clang_use_chrome_plugins. The flags are stored in a script so that they can -# be changed on the bots without requiring a master restart. - -SRC_ABS_DIR=$(cd $(dirname $0)/../../.. && echo $PWD) -CLANG_LIB_PATH=$SRC_ABS_DIR/third_party/llvm-build/Release+Asserts/lib - -if uname -s | grep -q Darwin; then - LIBSUFFIX=dylib -else - LIBSUFFIX=so -fi - -echo -Xclang -load -Xclang $CLANG_LIB_PATH/libFindBadConstructs.$LIBSUFFIX \ - -Xclang -add-plugin -Xclang find-bad-constructs \ - -Xclang -plugin-arg-find-bad-constructs -Xclang check-weak-ptr-factory-order \ - -Xclang -plugin-arg-find-bad-constructs -Xclang strict-virtual-specifiers
diff --git a/tools/clang/scripts/repackage.sh b/tools/clang/scripts/repackage.sh deleted file mode 100755 index e19ab7e8..0000000 --- a/tools/clang/scripts/repackage.sh +++ /dev/null
@@ -1,67 +0,0 @@ -#!/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 will check out llvm and clang, build a full package -# with the latest plugin revisions and then repackage an existing -# clang-package with the new plugin revisions. - -# The new package can be uploaded to replace the existing clang -# package at the same clang revision. - -THIS_DIR="$(dirname "${0}")" -LLVM_BUILD_DIR="${THIS_DIR}/../../../third_party/llvm-build" -LLVM_TAR_DIR="${LLVM_BUILD_DIR}/Release+Asserts" -LLVM_BIN_DIR="${LLVM_TAR_DIR}/bin" -LLVM_LIB_DIR="${LLVM_TAR_DIR}/lib" - -set -eu - -if [ "$(uname -s)" = "Darwin" ]; then - PLATFORM=Mac - SO_EXT="dylib" -else - PLATFORM=Linux_x64 - SO_EXT="so" -fi - -# Build clang with the new plugin revisions. -"$THIS_DIR"/package.sh $@ - -R=$("${LLVM_BIN_DIR}/clang" --version | \ - sed -ne 's/clang version .*(trunk \([0-9]*\))/\1/p') -PDIR=clang-$R - -if [ ! -f "$PDIR.tgz" ]; then - echo "Could not find package archive $PDIR.tgz generated by package.sh" - exit 1 -fi - -# We don't want to change the clang binary, so fetch the current clang -# package and add the plugin shared-libraries to the existing package. -rm -rf $LLVM_BUILD_DIR -"$THIS_DIR"/update.sh - -LIBNAME=\ -$(grep 'set(LIBRARYNAME' "$THIS_DIR"/../blink_gc_plugin/CMakeLists.txt \ - | cut -d ' ' -f 2 | tr -d ')') -LIBFILE=lib$LIBNAME.$SO_EXT - -# Check that we are actually creating the plugin at a new revision. -if [ -f "$LLVM_LIB_DIR/$LIBFILE" ]; then - echo "The plugin revision $LIBNAME is already in the existing package." - exit 1 -fi - -cp $PDIR/lib/$LIBFILE "$LLVM_LIB_DIR/" -if [ "$(uname -s)" = "Darwin" ]; then - tar zcf ${PDIR}_repack.tgz -C "$LLVM_TAR_DIR" bin include lib buildlog.txt -else - tar zcf ${PDIR}_repack.tgz -C "$LLVM_TAR_DIR" bin lib buildlog.txt -fi - -echo The clang package has been repackaged with $LIBNAME -echo To upload, run: -echo gsutil cp -a public-read ${PDIR}_repack.tgz \ - gs://chromium-browser-clang/$PLATFORM/$PDIR.tgz
diff --git a/tools/clang/scripts/update.sh b/tools/clang/scripts/update.sh index e8b929f..9fb24a9 100755 --- a/tools/clang/scripts/update.sh +++ b/tools/clang/scripts/update.sh
@@ -8,7 +8,12 @@ # Do NOT CHANGE this if you don't know what you're doing -- see # https://code.google.com/p/chromium/wiki/UpdatingClang # Reverting problematic clang rolls is safe, though. -CLANG_REVISION=223108 +CLANG_REVISION=231191 + +# This is incremented when pushing a new build of Clang at the same revision. +CLANG_SUB_REVISION=1 + +PACKAGE_VERSION="${CLANG_REVISION}-${CLANG_SUB_REVISION}" THIS_DIR="$(dirname "${0}")" LLVM_DIR="${THIS_DIR}/../../../third_party/llvm" @@ -34,6 +39,8 @@ # ${A:-a} returns $A if it's set, a else. LLVM_REPO_URL=${LLVM_URL:-https://llvm.org/svn/llvm-project} +CDS_URL=https://commondatastorage.googleapis.com/chromium-browser-clang + if [[ -z "$GYP_DEFINES" ]]; then GYP_DEFINES= fi @@ -88,7 +95,7 @@ force_local_build=yes ;; --print-revision) - echo $CLANG_REVISION + echo $PACKAGE_VERSION exit 0 ;; --run-tests) @@ -161,9 +168,38 @@ with_android= fi - if [[ "${OS}" == "Linux" ]] && [[ -z ${gcc_toolchain:-''} ]]; then - # Set gcc_toolchain on Linux; llvm-symbolizer needs the bundled libstdc++. - gcc_toolchain="$(dirname $(dirname $(which gcc)))" + LLVM_BUILD_TOOLS_DIR="${ABS_LLVM_DIR}/../llvm-build-tools" + + if [[ "${OS}" == "Linux" ]] && [[ -z "${gcc_toolchain}" ]]; then + if [[ $(gcc -dumpversion) < "4.7.0" ]]; then + # We need a newer GCC version. + if [[ ! -e "${LLVM_BUILD_TOOLS_DIR}/gcc482" ]]; then + echo "Downloading pre-built GCC 4.8.2..." + mkdir -p "${LLVM_BUILD_TOOLS_DIR}" + curl --fail -L "${CDS_URL}/tools/gcc482.tgz" | \ + tar zxf - -C "${LLVM_BUILD_TOOLS_DIR}" + echo Done + fi + gcc_toolchain="${LLVM_BUILD_TOOLS_DIR}/gcc482" + else + # Always set gcc_toolchain; llvm-symbolizer needs the bundled libstdc++. + gcc_toolchain="$(dirname $(dirname $(which gcc)))" + fi + fi + + if [[ "${OS}" == "Linux" ]]; then + # TODO(hans): Might need to make this work on Mac eventually. + if [[ $(cmake --version | grep -Eo '[0-9.]+') < "3.0" ]]; then + # We need a newer CMake version. + if [[ ! -e "${LLVM_BUILD_TOOLS_DIR}/cmake310" ]]; then + echo "Downloading pre-built CMake 3.10..." + mkdir -p "${LLVM_BUILD_TOOLS_DIR}" + curl --fail -L "${CDS_URL}/tools/cmake310.tgz" | \ + tar zxf - -C "${LLVM_BUILD_TOOLS_DIR}" + echo Done + fi + export PATH="${LLVM_BUILD_TOOLS_DIR}/cmake310/bin:${PATH}" + fi fi echo "LLVM_FORCE_HEAD_REVISION was set; using r${CLANG_REVISION}" @@ -198,8 +234,8 @@ PREVIOUSLY_BUILT_REVISON=$(cat "${STAMP_FILE}") if [[ -z "$force_local_build" ]] && \ [[ "${PREVIOUSLY_BUILT_REVISON}" = \ - "${CLANG_AND_PLUGINS_REVISION}" ]]; then - echo "Clang already at ${CLANG_AND_PLUGINS_REVISION}" + "${PACKAGE_VERSION}" ]]; then + echo "Clang already at ${PACKAGE_VERSION}" exit 0 fi fi @@ -210,8 +246,7 @@ if [[ -z "$force_local_build" ]]; then # Check if there's a prebuilt binary and if so just fetch that. That's faster, # and goma relies on having matching binary hashes on client and server too. - CDS_URL=https://commondatastorage.googleapis.com/chromium-browser-clang - CDS_FILE="clang-${CLANG_REVISION}.tgz" + CDS_FILE="clang-${PACKAGE_VERSION}.tgz" CDS_OUT_DIR=$(mktemp -d -t clang_download.XXXXXX) CDS_OUTPUT="${CDS_OUT_DIR}/${CDS_FILE}" if [ "${OS}" = "Linux" ]; then @@ -233,12 +268,12 @@ rm -rf "${LLVM_BUILD_DIR}" mkdir -p "${LLVM_BUILD_DIR}" tar -xzf "${CDS_OUTPUT}" -C "${LLVM_BUILD_DIR}" - echo clang "${CLANG_REVISION}" unpacked - echo "${CLANG_AND_PLUGINS_REVISION}" > "${STAMP_FILE}" + echo clang "${PACKAGE_VERSION}" unpacked + echo "${PACKAGE_VERSION}" > "${STAMP_FILE}" rm -rf "${CDS_OUT_DIR}" exit 0 else - echo Did not find prebuilt clang at r"${CLANG_REVISION}", building + echo Did not find prebuilt clang "${PACKAGE_VERSION}", building fi fi @@ -282,6 +317,8 @@ "${CLANG_DIR}/lib/Sema/SemaExprCXX.cpp" \ "${CLANG_DIR}/test/SemaCXX/default2.cpp" \ "${CLANG_DIR}/test/SemaCXX/typo-correction-delayed.cpp" \ + "${COMPILER_RT_DIR}/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc" \ + "${COMPILER_RT_DIR}/test/tsan/signal_segv_handler.cc" \ ; do if [[ -e "${i}" ]]; then rm -f "${i}" # For unversioned files. @@ -364,349 +401,6 @@ patch -p0 popd - # Apply r223211: "Revert r222997." - pushd "${LLVM_DIR}" - cat << 'EOF' | ---- a/lib/Transforms/Instrumentation/MemorySanitizer.cpp -+++ b/lib/Transforms/Instrumentation/MemorySanitizer.cpp -@@ -921,8 +921,6 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { - Value *OriginPtr = - getOriginPtrForArgument(&FArg, EntryIRB, ArgOffset); - setOrigin(A, EntryIRB.CreateLoad(OriginPtr)); -- } else { -- setOrigin(A, getCleanOrigin()); - } - } - ArgOffset += RoundUpToAlignment(Size, kShadowTLSAlignment); -@@ -942,13 +940,15 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { - /// \brief Get the origin for a value. - Value *getOrigin(Value *V) { - if (!MS.TrackOrigins) return nullptr; -- if (!PropagateShadow) return getCleanOrigin(); -- if (isa<Constant>(V)) return getCleanOrigin(); -- assert((isa<Instruction>(V) || isa<Argument>(V)) && -- "Unexpected value type in getOrigin()"); -- Value *Origin = OriginMap[V]; -- assert(Origin && "Missing origin"); -- return Origin; -+ if (isa<Instruction>(V) || isa<Argument>(V)) { -+ Value *Origin = OriginMap[V]; -+ if (!Origin) { -+ DEBUG(dbgs() << "NO ORIGIN: " << *V << "\n"); -+ Origin = getCleanOrigin(); -+ } -+ return Origin; -+ } -+ return getCleanOrigin(); - } - - /// \brief Get the origin for i-th argument of the instruction I. -@@ -1088,7 +1088,6 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { - IRB.CreateStore(getCleanShadow(&I), ShadowPtr); - - setShadow(&I, getCleanShadow(&I)); -- setOrigin(&I, getCleanOrigin()); - } - - void visitAtomicRMWInst(AtomicRMWInst &I) { -EOF - patch -p1 - popd - - # Apply r223219: "Preserve LD_LIBRARY_PATH when using the 'env' command" - pushd "${CLANG_DIR}" - cat << 'EOF' | ---- a/test/Driver/env.c -+++ b/test/Driver/env.c -@@ -5,12 +5,14 @@ - // REQUIRES: shell - // - // The PATH variable is heavily used when trying to find a linker. --// RUN: env -i LC_ALL=C %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ -+// RUN: env -i LC_ALL=C LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ -+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ - // RUN: --target=i386-unknown-linux \ - // RUN: --sysroot=%S/Inputs/basic_linux_tree \ - // RUN: | FileCheck --check-prefix=CHECK-LD-32 %s - // --// RUN: env -i LC_ALL=C PATH="" %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ -+// RUN: env -i LC_ALL=C PATH="" LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ -+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ - // RUN: --target=i386-unknown-linux \ - // RUN: --sysroot=%S/Inputs/basic_linux_tree \ - // RUN: | FileCheck --check-prefix=CHECK-LD-32 %s -EOF - patch -p1 - popd - - # Revert r220714: "Frontend: Define __EXCEPTIONS if -fexceptions is passed" - pushd "${CLANG_DIR}" - cat << 'EOF' | ---- a/lib/Frontend/InitPreprocessor.cpp -+++ b/lib/Frontend/InitPreprocessor.cpp -@@ -566,7 +566,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, - Builder.defineMacro("__BLOCKS__"); - } - -- if (!LangOpts.MSVCCompat && LangOpts.Exceptions) -+ if (!LangOpts.MSVCCompat && LangOpts.CXXExceptions) - Builder.defineMacro("__EXCEPTIONS"); - if (!LangOpts.MSVCCompat && LangOpts.RTTI) - Builder.defineMacro("__GXX_RTTI"); -diff --git a/test/Frontend/exceptions.c b/test/Frontend/exceptions.c -index 981b5b9..4bbaaa3 100644 ---- a/test/Frontend/exceptions.c -+++ b/test/Frontend/exceptions.c -@@ -1,9 +1,6 @@ --// RUN: %clang_cc1 -fms-compatibility -fexceptions -fcxx-exceptions -DMS_MODE -verify %s -+// RUN: %clang_cc1 -fms-compatibility -fexceptions -fcxx-exceptions -verify %s - // expected-no-diagnostics - --// RUN: %clang_cc1 -fms-compatibility -fexceptions -verify %s --// expected-no-diagnostics -- --#if defined(MS_MODE) && defined(__EXCEPTIONS) -+#if defined(__EXCEPTIONS) - #error __EXCEPTIONS should not be defined. - #endif -diff --git a/test/Preprocessor/predefined-exceptions.m b/test/Preprocessor/predefined-exceptions.m -index 0791075..c13f429 100644 ---- a/test/Preprocessor/predefined-exceptions.m -+++ b/test/Preprocessor/predefined-exceptions.m -@@ -1,6 +1,6 @@ - // RUN: %clang_cc1 -x objective-c -fobjc-exceptions -fexceptions -E -dM %s | FileCheck -check-prefix=CHECK-OBJC-NOCXX %s - // CHECK-OBJC-NOCXX: #define OBJC_ZEROCOST_EXCEPTIONS 1 --// CHECK-OBJC-NOCXX: #define __EXCEPTIONS 1 -+// CHECK-OBJC-NOCXX-NOT: #define __EXCEPTIONS 1 - - // RUN: %clang_cc1 -x objective-c++ -fobjc-exceptions -fexceptions -fcxx-exceptions -E -dM %s | FileCheck -check-prefix=CHECK-OBJC-CXX %s - // CHECK-OBJC-CXX: #define OBJC_ZEROCOST_EXCEPTIONS 1 -EOF - patch -p1 - popd - - # Apply r223177: "Ensure typos in the default values of template parameters get diagnosed." - pushd "${CLANG_DIR}" - cat << 'EOF' | ---- a/lib/Parse/ParseTemplate.cpp -+++ b/lib/Parse/ParseTemplate.cpp -@@ -676,7 +676,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { - GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); - EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); - -- DefaultArg = ParseAssignmentExpression(); -+ DefaultArg = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); - if (DefaultArg.isInvalid()) - SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); - } -diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp -index 1626044..c4d40b4 100644 ---- a/test/SemaCXX/default2.cpp -+++ b/test/SemaCXX/default2.cpp -@@ -122,3 +122,9 @@ class XX { - void A(int length = -1 ) { } - void B() { A(); } - }; -+ -+template <int I = (1 * I)> struct S {}; // expected-error-re {{use of undeclared identifier 'I'{{$}}}} -+S<1> s; -+ -+template <int I1 = I2, int I2 = 1> struct T {}; // expected-error-re {{use of undeclared identifier 'I2'{{$}}}} -+T<0, 1> t; -diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp -index bff1d76..7bf9258 100644 ---- a/test/SemaCXX/typo-correction-delayed.cpp -+++ b/test/SemaCXX/typo-correction-delayed.cpp -@@ -102,3 +102,7 @@ void f(int *i) { - __atomic_load(i, i, something_something); // expected-error-re {{use of undeclared identifier 'something_something'{{$}}}} - } - } -+ -+const int DefaultArg = 9; // expected-note {{'DefaultArg' declared here}} -+template <int I = defaultArg> struct S {}; // expected-error {{use of undeclared identifier 'defaultArg'; did you mean 'DefaultArg'?}} -+S<1> s; -EOF - patch -p1 - popd - - # Apply r223209: "Handle delayed corrections in a couple more error paths in ParsePostfixExpressionSuffix." - pushd "${CLANG_DIR}" - cat << 'EOF' | ---- a/lib/Parse/ParseExpr.cpp -+++ b/lib/Parse/ParseExpr.cpp -@@ -1390,6 +1390,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { - SourceLocation OpenLoc = ConsumeToken(); - - if (ParseSimpleExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) { -+ (void)Actions.CorrectDelayedTyposInExpr(LHS); - LHS = ExprError(); - } - -@@ -1440,6 +1441,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { - if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs, &Sema::CodeCompleteCall, - LHS.get())) { -+ (void)Actions.CorrectDelayedTyposInExpr(LHS); - LHS = ExprError(); - } - } -diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp -index 7bf9258..f7ef015 100644 ---- a/test/SemaCXX/typo-correction-delayed.cpp -+++ b/test/SemaCXX/typo-correction-delayed.cpp -@@ -106,3 +106,9 @@ void f(int *i) { - const int DefaultArg = 9; // expected-note {{'DefaultArg' declared here}} - template <int I = defaultArg> struct S {}; // expected-error {{use of undeclared identifier 'defaultArg'; did you mean 'DefaultArg'?}} - S<1> s; -+ -+namespace foo {} -+void test_paren_suffix() { -+ foo::bar({5, 6}); // expected-error-re {{no member named 'bar' in namespace 'foo'{{$}}}} \ -+ // expected-error {{expected expression}} -+} -EOF - patch -p1 - popd - - # Apply r223705: "Handle possible TypoExprs in member initializers." - pushd "${CLANG_DIR}" - cat << 'EOF' | ---- a/lib/Sema/SemaDeclCXX.cpp -+++ b/lib/Sema/SemaDeclCXX.cpp -@@ -2813,6 +2813,11 @@ Sema::BuildMemInitializer(Decl *ConstructorD, - SourceLocation IdLoc, - Expr *Init, - SourceLocation EllipsisLoc) { -+ ExprResult Res = CorrectDelayedTyposInExpr(Init); -+ if (!Res.isUsable()) -+ return true; -+ Init = Res.get(); -+ - if (!ConstructorD) - return true; - -diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp -index f7ef015..d303b58 100644 ---- a/test/SemaCXX/typo-correction-delayed.cpp -+++ b/test/SemaCXX/typo-correction-delayed.cpp -@@ -112,3 +112,10 @@ void test_paren_suffix() { - foo::bar({5, 6}); // expected-error-re {{no member named 'bar' in namespace 'foo'{{$}}}} \ - // expected-error {{expected expression}} - } -+ -+const int kNum = 10; // expected-note {{'kNum' declared here}} -+class SomeClass { -+ int Kind; -+public: -+ explicit SomeClass() : Kind(kSum) {} // expected-error {{use of undeclared identifier 'kSum'; did you mean 'kNum'?}} -+}; -EOF - patch -p1 - popd - - # Apply r224172: "Typo correction: Ignore temporary binding exprs after overload resolution" - pushd "${CLANG_DIR}" - cat << 'EOF' | ---- a/lib/Sema/SemaExprCXX.cpp -+++ b/lib/Sema/SemaExprCXX.cpp -@@ -6105,8 +6105,13 @@ public: - auto Result = BaseTransform::RebuildCallExpr(Callee, LParenLoc, Args, - RParenLoc, ExecConfig); - if (auto *OE = dyn_cast<OverloadExpr>(Callee)) { -- if (!Result.isInvalid() && Result.get()) -- OverloadResolution[OE] = cast<CallExpr>(Result.get())->getCallee(); -+ if (!Result.isInvalid() && Result.get()) { -+ Expr *ResultCall = Result.get(); -+ if (auto *BE = dyn_cast<CXXBindTemporaryExpr>(ResultCall)) -+ ResultCall = BE->getSubExpr(); -+ if (auto *CE = dyn_cast<CallExpr>(ResultCall)) -+ OverloadResolution[OE] = CE->getCallee(); -+ } - } - return Result; - } -diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp -index d303b58..d42888f 100644 ---- a/test/SemaCXX/typo-correction-delayed.cpp -+++ b/test/SemaCXX/typo-correction-delayed.cpp -@@ -119,3 +119,23 @@ class SomeClass { - public: - explicit SomeClass() : Kind(kSum) {} // expected-error {{use of undeclared identifier 'kSum'; did you mean 'kNum'?}} - }; -+ -+extern "C" int printf(const char *, ...); -+ -+// There used to be an issue with typo resolution inside overloads. -+struct AssertionResult { -+ ~AssertionResult(); -+ operator bool(); -+ int val; -+}; -+AssertionResult Compare(const char *a, const char *b); -+AssertionResult Compare(int a, int b); -+int main() { -+ // expected-note@+1 {{'result' declared here}} -+ const char *result; -+ // expected-error@+1 {{use of undeclared identifier 'resulta'; did you mean 'result'?}} -+ if (AssertionResult ar = (Compare("value1", resulta))) -+ ; -+ else -+ printf("ar: %d\n", ar.val); -+} -EOF - patch -p1 - popd - - # Apply r224173: "Implement feedback on r224172 in PR21899" - pushd "${CLANG_DIR}" - cat << 'EOF' | ---- a/lib/Sema/SemaExprCXX.cpp -+++ b/lib/Sema/SemaExprCXX.cpp -@@ -6105,7 +6105,7 @@ public: - auto Result = BaseTransform::RebuildCallExpr(Callee, LParenLoc, Args, - RParenLoc, ExecConfig); - if (auto *OE = dyn_cast<OverloadExpr>(Callee)) { -- if (!Result.isInvalid() && Result.get()) { -+ if (Result.isUsable()) { - Expr *ResultCall = Result.get(); - if (auto *BE = dyn_cast<CXXBindTemporaryExpr>(ResultCall)) - ResultCall = BE->getSubExpr(); -diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp -index d42888f..7879d29 100644 ---- a/test/SemaCXX/typo-correction-delayed.cpp -+++ b/test/SemaCXX/typo-correction-delayed.cpp -@@ -120,22 +120,13 @@ public: - explicit SomeClass() : Kind(kSum) {} // expected-error {{use of undeclared identifier 'kSum'; did you mean 'kNum'?}} - }; - --extern "C" int printf(const char *, ...); -- - // There used to be an issue with typo resolution inside overloads. --struct AssertionResult { -- ~AssertionResult(); -- operator bool(); -- int val; --}; --AssertionResult Compare(const char *a, const char *b); --AssertionResult Compare(int a, int b); --int main() { -+struct AssertionResult { ~AssertionResult(); }; -+AssertionResult Overload(const char *a); -+AssertionResult Overload(int a); -+void UseOverload() { - // expected-note@+1 {{'result' declared here}} - const char *result; - // expected-error@+1 {{use of undeclared identifier 'resulta'; did you mean 'result'?}} -- if (AssertionResult ar = (Compare("value1", resulta))) -- ; -- else -- printf("ar: %d\n", ar.val); -+ Overload(resulta); - } -EOF - patch -p1 - popd - # This Go bindings test doesn't work after the bootstrap build on Linux. (PR21552) pushd "${LLVM_DIR}" cat << 'EOF' | @@ -723,6 +417,7 @@ patch -p0 popd + fi # Echo all commands. @@ -975,4 +670,4 @@ fi # After everything is done, log success for this revision. -echo "${CLANG_AND_PLUGINS_REVISION}" > "${STAMP_FILE}" +echo "${PACKAGE_VERSION}" > "${STAMP_FILE}"
diff --git a/tools/gn/c_include_iterator.h b/tools/gn/c_include_iterator.h index 86c5ede..94ebca14 100644 --- a/tools/gn/c_include_iterator.h +++ b/tools/gn/c_include_iterator.h
@@ -52,4 +52,4 @@ DISALLOW_COPY_AND_ASSIGN(CIncludeIterator); }; -#endif // TOOLS_GN_INCLUDE_ITERATOR_H_ +#endif // TOOLS_GN_C_INCLUDE_ITERATOR_H_
diff --git a/tools/gn/commands.h b/tools/gn/commands.h index dd2cb1b..239c07b5 100644 --- a/tools/gn/commands.h +++ b/tools/gn/commands.h
@@ -173,4 +173,4 @@ } // namespace commands -#endif // TOOLS_GN_COMMANDS_H +#endif // TOOLS_GN_COMMANDS_H_
diff --git a/tools/gn/example/hello_shared.h b/tools/gn/example/hello_shared.h index f62b5ee..7af804b3 100644 --- a/tools/gn/example/hello_shared.h +++ b/tools/gn/example/hello_shared.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 HELLO_SHARED_H_ -#define HELLO_SHARED_H_ +#ifndef TOOLS_GN_EXAMPLE_HELLO_SHARED_H_ +#define TOOLS_GN_EXAMPLE_HELLO_SHARED_H_ #if defined(WIN32) @@ -17,16 +17,16 @@ #else -#if defined(HELLO_IMPLEMENTATION) +#if defined(HELLO_SHARED_IMPLEMENTATION) #define HELLO_EXPORT __attribute__((visibility("default"))) #define HELLO_EXPORT_PRIVATE __attribute__((visibility("default"))) #else #define HELLO_EXPORT #define HELLO_EXPORT_PRIVATE -#endif // defined(HELLO_IMPLEMENTATION) +#endif // defined(HELLO_SHARED_IMPLEMENTATION) #endif HELLO_EXPORT const char* GetSharedText(); -#endif // HELLO_SHARED_H_ +#endif // TOOLS_GN_EXAMPLE_HELLO_SHARED_H_
diff --git a/tools/gn/example/hello_static.h b/tools/gn/example/hello_static.h index 248ca050..f15a633 100644 --- a/tools/gn/example/hello_static.h +++ b/tools/gn/example/hello_static.h
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef HELLO_STATIC_H_ -#define HELLO_STATIC_H_ +#ifndef TOOLS_GN_EXAMPLE_HELLO_STATIC_H_ +#define TOOLS_GN_EXAMPLE_HELLO_STATIC_H_ const char* GetStaticText(); -#endif // HELLO_STATIC_H_ +#endif // TOOLS_GN_EXAMPLE_HELLO_STATIC_H_
diff --git a/tools/gn/gn.gyp b/tools/gn/gn.gyp index 9337761f..0b6d204 100644 --- a/tools/gn/gn.gyp +++ b/tools/gn/gn.gyp
@@ -30,8 +30,8 @@ 'command_check.cc', 'command_clean.cc', 'command_desc.cc', - 'command_gen.cc', 'command_format.cc', + 'command_gen.cc', 'command_help.cc', 'command_ls.cc', 'command_refs.cc', @@ -53,13 +53,10 @@ 'err.h', 'escape.cc', 'escape.h', - 'exec_process.h', 'exec_process.cc', + 'exec_process.h', 'filesystem_utils.cc', 'filesystem_utils.h', - 'functions_target.cc', - 'functions.cc', - 'functions.h', 'function_exec_script.cc', 'function_foreach.cc', 'function_get_label_info.cc', @@ -73,6 +70,9 @@ 'function_template.cc', 'function_toolchain.cc', 'function_write_file.cc', + 'functions.cc', + 'functions.h', + 'functions_target.cc', 'group_target_generator.cc', 'group_target_generator.h', 'header_checker.cc', @@ -106,12 +106,12 @@ 'ninja_copy_target_writer.h', 'ninja_group_target_writer.cc', 'ninja_group_target_writer.h', - 'ninja_utils.cc', - 'ninja_utils.h', 'ninja_target_writer.cc', 'ninja_target_writer.h', 'ninja_toolchain_writer.cc', 'ninja_toolchain_writer.h', + 'ninja_utils.cc', + 'ninja_utils.h', 'ninja_writer.cc', 'ninja_writer.h', 'operators.cc', @@ -170,9 +170,9 @@ 'tool.h', 'toolchain.cc', 'toolchain.h', - 'unique_vector.h', 'trace.cc', 'trace.h', + 'unique_vector.h', 'value.cc', 'value.h', 'value_extractors.cc',
diff --git a/tools/gn/ninja_build_writer.h b/tools/gn/ninja_build_writer.h index 427b54e..6f7bf38 100644 --- a/tools/gn/ninja_build_writer.h +++ b/tools/gn/ninja_build_writer.h
@@ -58,5 +58,5 @@ DISALLOW_COPY_AND_ASSIGN(NinjaBuildWriter); }; -#endif // TOOLS_GN_NINJA_BUILD_GENERATOR_H_ +#endif // TOOLS_GN_NINJA_BUILD_WRITER_H_
diff --git a/tools/gn/substitution_list.h b/tools/gn/substitution_list.h index 3a45ba8..f3e3c01 100644 --- a/tools/gn/substitution_list.h +++ b/tools/gn/substitution_list.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 TOOLS_GN_SUBSTUTITION_LIST_H -#define TOOLS_GN_SUBSTUTITION_LIST_H +#ifndef TOOLS_GN_SUBSTITUTION_LIST_H_ +#define TOOLS_GN_SUBSTITUTION_LIST_H_ #include <string> #include <vector> @@ -43,4 +43,4 @@ std::vector<SubstitutionType> required_types_; }; -#endif // TOOLS_GN_SUBSTUTITION_LIST_H +#endif // TOOLS_GN_SUBSTITUTION_LIST_H_
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids index efd5760c..d2b3ede 100644 --- a/tools/gritsettings/resource_ids +++ b/tools/gritsettings/resource_ids
@@ -215,6 +215,9 @@ "ui/login/login_resources.grd": { "includes": [28300], }, + "ui/oobe/oobe_resources.grd": { + "includes": [28310], + }, "chrome/browser/resources/translate_internals_resources.grd": { "includes": [28500], },
diff --git a/tools/ipc_fuzzer/mutate/generate.cc b/tools/ipc_fuzzer/mutate/generate.cc index ba3dc997..aa4b09b 100644 --- a/tools/ipc_fuzzer/mutate/generate.cc +++ b/tools/ipc_fuzzer/mutate/generate.cc
@@ -992,7 +992,8 @@ static bool Generate(content::SyntheticGesturePacket* p, Generator* generator) { scoped_ptr<content::SyntheticGestureParams> gesture_params; - switch (RandInRange(3)) { + switch (RandInRange( + content::SyntheticGestureParams::SYNTHETIC_GESTURE_TYPE_MAX + 1)) { case content::SyntheticGestureParams::GestureType:: SMOOTH_SCROLL_GESTURE: { content::SyntheticSmoothScrollGestureParams* params = @@ -1008,6 +1009,18 @@ gesture_params.reset(params); break; } + case content::SyntheticGestureParams::GestureType::SMOOTH_DRAG_GESTURE: { + content::SyntheticSmoothDragGestureParams* params = + new content::SyntheticSmoothDragGestureParams(); + if (!GenerateParam(¶ms->start_point, generator)) + return false; + if (!GenerateParam(¶ms->distances, generator)) + return false; + if (!GenerateParam(¶ms->speed_in_pixels_s, generator)) + return false; + gesture_params.reset(params); + break; + } case content::SyntheticGestureParams::GestureType::PINCH_GESTURE: { content::SyntheticPinchGestureParams* params = new content::SyntheticPinchGestureParams();
diff --git a/tools/ipc_fuzzer/replay/replay_process.cc b/tools/ipc_fuzzer/replay/replay_process.cc index 0a7b830..8f942c6 100644 --- a/tools/ipc_fuzzer/replay/replay_process.cc +++ b/tools/ipc_fuzzer/replay/replay_process.cc
@@ -93,7 +93,7 @@ content::ShouldUseMojoChannel(); if (should_use_mojo) { channel_ = IPC::ChannelProxy::Create( - IPC::ChannelMojo::CreateClientFactory(channel_name), this, + IPC::ChannelMojo::CreateClientFactory(nullptr, channel_name), this, io_thread_.message_loop_proxy()); } else { channel_ =
diff --git a/tools/json_schema_compiler/idl_schema.py b/tools/json_schema_compiler/idl_schema.py index 45f0609..31e0a273 100755 --- a/tools/json_schema_compiler/idl_schema.py +++ b/tools/json_schema_compiler/idl_schema.py
@@ -343,7 +343,8 @@ internal=False, platforms=None, compiler_options=None, - deprecated=None): + deprecated=None, + documentation_options=None): self.namespace = namespace_node self.nodoc = nodoc self.internal = internal @@ -355,6 +356,7 @@ self.callbacks = OrderedDict() self.description = description self.deprecated = deprecated + self.documentation_options = documentation_options def process(self): for node in self.namespace.GetChildren(): @@ -371,10 +373,8 @@ self.types.append(Enum(node).process()) else: sys.exit('Did not process %s %s' % (node.cls, node)) - if self.compiler_options is not None: - compiler_options = self.compiler_options - else: - compiler_options = {} + compiler_options = self.compiler_options or {} + documentation_options = self.documentation_options or {} return {'namespace': self.namespace.GetName(), 'description': self.description, 'nodoc': self.nodoc, @@ -384,7 +384,8 @@ 'events': self.events, 'platforms': self.platforms, 'compiler_options': compiler_options, - 'deprecated': self.deprecated} + 'deprecated': self.deprecated, + 'documentation_options': documentation_options} def process_interface(self, node): members = [] @@ -412,6 +413,7 @@ platforms = None compiler_options = {} deprecated = None + documentation_options = {} for node in self.idl: if node.cls == 'Namespace': if not description: @@ -422,7 +424,8 @@ namespace = Namespace(node, description, nodoc, internal, platforms=platforms, compiler_options=compiler_options or None, - deprecated=deprecated) + deprecated=deprecated, + documentation_options=documentation_options) namespaces.append(namespace.process()) nodoc = False internal = False @@ -445,6 +448,12 @@ compiler_options['camel_case_enum_to_string'] = node.value elif node.name == 'deprecated': deprecated = str(node.value) + elif node.name == 'documentation_title': + documentation_options['title'] = node.value + elif node.name == 'documentation_namespace': + documentation_options['namespace'] = node.value + elif node.name == 'documented_in': + documentation_options['documented_in'] = node.value else: continue else:
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 95674aa..e024a1d 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -1146,8 +1146,19 @@ </action> <action name="BadMessageTerminate_MIDI"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> - <description>Please enter the description of this user action.</description> + <owner>toyoshim@chromium.org</owner> + <description> + Indicates that an IPC message to send a SysEx MIDI message is received from + a renderer that is not permitted to send a SysEx MIDI message. + </description> +</action> + +<action name="BadMessageTerminate_MIDIPort"> + <owner>toyoshim@chromium.org</owner> + <description> + Indicates that an IPC message to send a MIDI message against out of range + output port is received from a renderer. + </description> </action> <action name="BadMessageTerminate_NC"> @@ -8486,6 +8497,20 @@ <description>Settings: Bluetooth: Add a device</description> </action> +<action name="Options_CaptivePortalBypassProxy_Disable"> + <owner>alemate@chromium.org</owner> + <description> + Captive portal authorization bypass proxy is disabled. + </description> +</action> + +<action name="Options_CaptivePortalBypassProxy_Enable"> + <owner>alemate@chromium.org</owner> + <description> + Captive portal authorization bypass proxy is enabled. + </description> +</action> + <action name="Options_ChangeDefaultZoomLevel"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 79775fa..ac5fc89 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -6488,6 +6488,80 @@ </summary> </histogram> +<histogram name="EasyUnlock.AuthProximity.RemoteDeviceModelHash" + enum="EasyUnlockDeviceModelHash"> + <owner>tengs@chromium.org</owner> + <owner>xiaowenx@chromium.org</owner> + <summary> + The hash of the phone model used to successfully sign in or unlock using + Smart Lock. + </summary> + <details> + This hash is calculated by taking the first 4 bytes of the MD5 hash of the + device model. + </details> +</histogram> + +<histogram name="EasyUnlock.AuthProximity.RollingRssi" units="dBm"> + <owner>tengs@chromium.org</owner> + <owner>xiaowenx@chromium.org</owner> + <summary> + Measures the exponentially weighted rolling average of the received signal + strength indicator (RSSI) of the phone when the user successfully unlocks or + signs in using Smart Lock. + </summary> + <details> + The exponentially weighted averaging formula is: + + rollingRssi = (1 - weight) * rollingRssi + weight * currentRssi; + + RSSI readings are inherently noisy, so this averaging gives a smoothed RSSI + value to work with as a heuristic for proximity. + + If no RSSI was read, then a sentinel value of 127 will be recorded. + </details> +</histogram> + +<histogram name="EasyUnlock.AuthProximity.TimeSinceLastZeroRssi" + units="milliseconds"> + <owner>tengs@chromium.org</owner> + <owner>xiaowenx@chromium.org</owner> + <summary> + Measures the time delta in milliseconds since the last zero RSSI value was + read to when the user successfully unlocks or signs in using Smart Lock. + </summary> + <details> + A zero RSSI value is special because both Bluetooth devices in a connection + attempt to maintain by adjusting their transmit power levels. This time + delta can be used as a possible heuristic to determine that the phone is + close to the local device. + + If no RSSI was read, then an overflow value will be recorded. + </details> +</histogram> + +<histogram name="EasyUnlock.AuthProximity.TransmitPowerDelta" units="dBm"> + <owner>tengs@chromium.org</owner> + <owner>xiaowenx@chromium.org</owner> + <summary> + Measures the difference between the current transmit power and the maximum + transmit power of the local device when the user successfully unlocks or + signs in using Smart Lock. + </summary> + <details> + Devices connected using classic Bluetooth adjust their transmit power + dynamically to optimize power and signal strength. The difference between + the current transmit power and maximum transmit power can be used as a + heurstic to determine if the phone is close to the local device. + + According to the Bluetooth specs, there are three classes of devices, with a + maximum transmit power of 20, 4, and 0 dBm respectively. + + If no transmit power was read, then a sentinel value of 127 will be + recorded. + </details> +</histogram> + <histogram name="EasyUnlock.ClickedButton" enum="EasyUnlockButton"> <owner>joshwoodward@google.com</owner> <owner>tbarzic@chromium.org</owner> @@ -8368,6 +8442,16 @@ </summary> </histogram> +<histogram name="Extensions.BadMessageFunctionName" enum="ExtensionFunctions"> + <owner>kalman@chromium.org</owner> + <summary> + The number of times each Extension function call sends a bad message, + killing the renderer. This may indicate a bug in that API's implementation + on the renderer. Note a similar, aggregate metric is BadMessageTerminate_EFD + which counts the number of bad messages that are sent overall. + </summary> +</histogram> + <histogram name="Extensions.CheckForExternalUpdatesTime"> <owner>rkaplow@chromium.org</owner> <summary> @@ -8700,6 +8784,14 @@ </summary> </histogram> +<histogram name="Extensions.ExtensionManagement_RefreshTime" + units="milliseconds"> + <owner>rkaplow@chromium.org</owner> + <summary> + The amount of time that elapsed during ExtensionManagement::Refresh. + </summary> +</histogram> + <histogram name="Extensions.ExtensionRootPathLength"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary> @@ -33448,6 +33540,14 @@ </summary> </histogram> +<histogram name="Session.TotalDuration" units="milliseconds"> + <owner>mariakhomenko@chromium.org</owner> + <owner>fqian@chromium.org</owner> + <summary> + The length of a session (launch/foregrounding to backgrounding) on mobile. + </summary> +</histogram> + <histogram name="SessionCrashed.Bubble" enum="SessionCrashedBubbleUserAction"> <owner>yiyaoliu@chromium.org</owner> <summary>How did the user interact with the SessionCrashed Bubble?</summary> @@ -37644,6 +37744,33 @@ </summary> </histogram> +<histogram name="Startup.PreMainMessageLoopRunImplStep1Time" + units="milliseconds"> + <owner>rkaplow@chromium.org</owner> + <summary> + The amount of time that elapsed during the first untracked section of + ChromeBrowserMainParts::PreMainMessageLoopRunImpl. + </summary> +</histogram> + +<histogram name="Startup.PreMainMessageLoopRunImplStep2Time" + units="milliseconds"> + <owner>rkaplow@chromium.org</owner> + <summary> + The amount of time that elapsed during the second untracked section of + ChromeBrowserMainParts::PreMainMessageLoopRunImpl. Not written for Android. + </summary> +</histogram> + +<histogram name="Startup.PreMainMessageLoopRunImplStep3Time" + units="milliseconds"> + <owner>rkaplow@chromium.org</owner> + <summary> + The amount of time that elapsed during the third untracked section of + ChromeBrowserMainParts::PreMainMessageLoopRunImpl. Not written for Android. + </summary> +</histogram> + <histogram name="Startup.PreMainMessageLoopRunImplTime" units="milliseconds"> <obsolete> Deprecated as of 2/2015. @@ -41145,8 +41272,8 @@ <owner>ulan@chromium.org</owner> <summary> Number of garbage collections that a detached global context survives, - recorded after each major garbage collection. - Values greater than 7 indicate a memory leak. + recorded after each major garbage collection. Values greater than 7 indicate + a memory leak. </summary> </histogram> @@ -43706,6 +43833,16 @@ <summary>Number of times that each menu item is clicked.</summary> </histogram> +<histogram name="WrenchMenu.OpeningAnimationFrameTimes" units="milliseconds"> + <owner>kkimlabs@chromium.org</owner> + <summary> + Frame times of the Android wrench menu opening animation. For example, if + the menu opening animation runs exactly at 60fps for a second, then each + frame time is 16ms, and a total of 60 values of 16ms are recorded. If the + animation is janky, we will see values greater than 16ms in the histogram. + </summary> +</histogram> + <histogram name="WrenchMenu.RecentTabsSubMenu" enum="RecentTabsAction"> <owner>rpop@chromium.org</owner> <summary> @@ -43723,7 +43860,7 @@ </histogram> <histogram name="WrenchMenu.TouchDuration" units="milliseconds"> - <owner>kkimlabs@google.com</owner> + <owner>kkimlabs@chromium.org</owner> <summary> Time difference between touch down and touch up on Android wrench button. </summary> @@ -46615,6 +46752,13 @@ <int value="9" label="No recent updates"/> </enum> +<enum name="EasyUnlockDeviceModelHash" type="int"> + <int value="-1168032746" label="Motorola Nexus 6"/> + <int value="-617422855" label="LGE Nexus 4"/> + <int value="1286382027" label="Motorola XT1095"/> + <int value="1881443083" label="LGE Nexus 5"/> +</enum> + <enum name="EasyUnlockHasSecureScreenLock" type="int"> <int value="0" label="Lacks secure screen lock"/> <int value="1" label="Has secure screen lock"/> @@ -47315,6 +47459,7 @@ <int value="293" label="Send monitoring heartbeats to the management server."/> <int value="294" label="How often the monitoring heartbeats are sent."/> + <int value="295" label="Captive portal authentication ignores proxy"/> </enum> <enum name="EnterprisePolicyInvalidations" type="int"> @@ -52243,6 +52388,7 @@ <int value="-1691668194" label="enable-new-bookmark-apps"/> <int value="-1662447331" label="wake-on-packets"/> <int value="-1654344175" label="disable-extension-info-dialog"/> + <int value="-1630419335" label="enable-download-notification"/> <int value="-1619757314" label="touch-scrolling-mode"/> <int value="-1614912400" label="enable-link-disambiguation-popup"/> <int value="-1605567628" label="disable-overlay-scrollbar"/> @@ -52254,6 +52400,7 @@ <int value="-1514611301" label="enable-data-reduction-proxy-bypass-warnings"/> <int value="-1510839574" label="disable-sync-synced-notifications"/> <int value="-1497338981" label="disable-accelerated-overflow-scroll"/> + <int value="-1490298774" label="enable-captive-portal-bypass-proxy-option"/> <int value="-1482685863" label="enable-request-tablet-site"/> <int value="-1460462432" label="disable-media-source"/> <int value="-1433087548" label="enable-app-install-alerts"/> @@ -55629,6 +55776,7 @@ <int value="706893509" label="PPB_ContentDecryptor_Private;0.11"/> <int value="714324031" label="PPB_Graphics3D;1.0"/> <int value="724664149" label="PPB_Flash_Menu;0.2"/> + <int value="732838108" label="PPB_IsolatedFileSystem_Private;0.2"/> <int value="760024173" label="PPB_FileIO;1.0"/> <int value="760246876" label="PPB_OpenGLES2VertexArrayObject;1.0"/> <int value="763746388" label="PPB_NaCl_Private;1.0"/> @@ -57664,33 +57812,41 @@ </enum> <enum name="SB2DatabaseFailure" type="int"> - <int value="0" label="CORRUPT"/> - <int value="1" label="CORRUPT_HANDLER"/> - <int value="2" label="BROWSE_DB_UPDATE_BEGIN"/> - <int value="3" label="BROWSE_DB_UPDATE_FINISH"/> - <int value="4" label="FILTER_MISSING"/> - <int value="5" label="FILTER_READ"/> - <int value="6" label="FILTER_WRITE"/> - <int value="7" label="FILTER_DELETE"/> - <int value="8" label="STORE_MISSING"/> - <int value="9" label="STORE_DELETE"/> - <int value="10" label="DOWNLOAD_DB_UPDATE_BEGIN"/> - <int value="11" label="DOWNLOAD_DB_UPDATE_FINISH"/> - <int value="12" label="CSD_DB_UPDATE_BEGIN"/> - <int value="13" label="CSD_DB_UPDATE_FINISH"/> - <int value="14" label="BROWSE_PREFIX_SET_MISSING"/> - <int value="15" label="BROWSE_PREFIX_SET_READ"/> - <int value="16" label="BROWSE_PREFIX_SET_WRITE"/> - <int value="17" label="BROWSE_PREFIX_SET_DELETE"/> - <int value="18" label="EXTENSION_BLACKLIST_UPDATE_BEGIN"/> - <int value="19" label="EXTENSION_BLACKLIST_UPDATE_FINISH"/> - <int value="20" label="EXTENSION_BLACKLIST_UPDATE_DELETE"/> - <int value="21" label="SIDE_EFFECT_FREE_WHITELIST_UPDATE_BEGIN"/> - <int value="22" label="SIDE_EFFECT_FREE_WHITELIST_UPDATE_FINISH"/> - <int value="23" label="SIDE_EFFECT_FREE_WHITELIST_DELETE"/> - <int value="24" label="SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_READ"/> - <int value="25" label="SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_WRITE"/> - <int value="26" label="SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_DELETE"/> + <int value="0" label="FAILURE_DATABASE_CORRUPT"/> + <int value="1" label="FAILURE_DATABASE_CORRUPT_HANDLER"/> + <int value="2" label="FAILURE_BROWSE_DATABASE_UPDATE_BEGIN"/> + <int value="3" label="FAILURE_BROWSE_DATABASE_UPDATE_FINISH"/> + <int value="4" label="FAILURE_DATABASE_FILTER_MISSING_OBSOLETE"/> + <int value="5" label="FAILURE_DATABASE_FILTER_READ_OBSOLETE"/> + <int value="6" label="FAILURE_DATABASE_FILTER_WRITE_OBSOLETE"/> + <int value="7" label="FAILURE_DATABASE_FILTER_DELETE"/> + <int value="8" label="FAILURE_DATABASE_STORE_MISSING"/> + <int value="9" label="FAILURE_DATABASE_STORE_DELETE"/> + <int value="10" label="FAILURE_DOWNLOAD_DATABASE_UPDATE_BEGIN"/> + <int value="11" label="FAILURE_DOWNLOAD_DATABASE_UPDATE_FINISH"/> + <int value="12" label="FAILURE_WHITELIST_DATABASE_UPDATE_BEGIN"/> + <int value="13" label="FAILURE_WHITELIST_DATABASE_UPDATE_FINISH"/> + <int value="14" label="FAILURE_BROWSE_PREFIX_SET_READ"/> + <int value="15" label="FAILURE_BROWSE_PREFIX_SET_WRITE"/> + <int value="16" label="FAILURE_BROWSE_PREFIX_SET_DELETE"/> + <int value="17" label="FAILURE_EXTENSION_BLACKLIST_UPDATE_BEGIN"/> + <int value="18" label="FAILURE_EXTENSION_BLACKLIST_UPDATE_FINISH"/> + <int value="19" label="FAILURE_EXTENSION_BLACKLIST_DELETE"/> + <int value="20" label="FAILURE_SIDE_EFFECT_FREE_WHITELIST_UPDATE_BEGIN"/> + <int value="21" label="FAILURE_SIDE_EFFECT_FREE_WHITELIST_UPDATE_FINISH"/> + <int value="22" label="FAILURE_SIDE_EFFECT_FREE_WHITELIST_DELETE"/> + <int value="23" label="FAILURE_SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_READ"/> + <int value="24" label="FAILURE_SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_WRITE"/> + <int value="25" label="FAILURE_SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_DELETE"/> + <int value="26" label="FAILURE_IP_BLACKLIST_UPDATE_BEGIN"/> + <int value="27" label="FAILURE_IP_BLACKLIST_UPDATE_FINISH"/> + <int value="28" label="FAILURE_IP_BLACKLIST_UPDATE_INVALID"/> + <int value="29" label="FAILURE_IP_BLACKLIST_DELETE"/> + <int value="30" label="FAILURE_UNWANTED_SOFTWARE_DATABASE_UPDATE_BEGIN"/> + <int value="31" label="FAILURE_UNWANTED_SOFTWARE_DATABASE_UPDATE_FINISH"/> + <int value="32" label="FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_READ"/> + <int value="33" label="FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_WRITE"/> + <int value="34" label="FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_DELETE"/> </enum> <enum name="SB2DownloadChecks" type="int">
diff --git a/tools/perf/benchmarks/draw_properties.py b/tools/perf/benchmarks/draw_properties.py index 9ac9ff2..aa0e12d0 100644 --- a/tools/perf/benchmarks/draw_properties.py +++ b/tools/perf/benchmarks/draw_properties.py
@@ -8,6 +8,7 @@ import page_sets +@benchmark.Disabled() # http://crbug.com/463111 class DrawPropertiesToughScrolling(benchmark.Benchmark): test = draw_properties.DrawProperties page_set = page_sets.ToughScrollingCasesPageSet @@ -15,6 +16,8 @@ def Name(cls): return 'draw_properties.tough_scrolling' + +@benchmark.Disabled() # http://crbug.com/463111 class DrawPropertiesTop25(benchmark.Benchmark): """Measures the relative performance of CalcDrawProperties vs computing draw properties from property trees.
diff --git a/tools/perf/benchmarks/gpu_times.py b/tools/perf/benchmarks/gpu_times.py index c2ccd0ec..011e6f1 100644 --- a/tools/perf/benchmarks/gpu_times.py +++ b/tools/perf/benchmarks/gpu_times.py
@@ -13,21 +13,16 @@ 'disabled-by-default-gpu.service'] -def _GetGPUTimelineMetric(_): - return [gpu_timeline.GPUTimelineMetric()] - - class _GPUTimes(benchmark.Benchmark): def CreateTimelineBasedMeasurementOptions(self): cat_string = ','.join(TOPLEVEL_CATEGORIES) cat_filter = tracing_category_filter.TracingCategoryFilter(cat_string) return timeline_based_measurement.Options( - overhead_level=cat_filter, - get_metrics_from_flags_callback=_GetGPUTimelineMetric) + overhead_level=cat_filter) @classmethod - def ValueCanBeAddedPredicate(cls, value): + def ValueCanBeAddedPredicate(cls, value, _): return (isinstance(value, gpu_timeline.GPUTimelineListOfValues) or isinstance(value, gpu_timeline.GPUTimelineValue))
diff --git a/tools/perf/benchmarks/page_cycler.py b/tools/perf/benchmarks/page_cycler.py index c4837d0f..103afad 100644 --- a/tools/perf/benchmarks/page_cycler.py +++ b/tools/perf/benchmarks/page_cycler.py
@@ -9,6 +9,7 @@ class _PageCycler(benchmark.Benchmark): options = {'pageset_repeat': 6} + cold_load_percent = 50 # % of page visits for which a cold load is forced @classmethod def Name(cls): @@ -20,14 +21,15 @@ action='store_true', help='Enable the speed index metric.') - parser.add_option('--cold-load-percent', type='int', default=50, - help='%d of page visits for which a cold load is forced') + @classmethod + def ValueCanBeAddedPredicate(cls, _, is_first_result): + return cls.cold_load_percent > 0 or not is_first_result def CreatePageTest(self, options): return page_cycler.PageCycler( page_repeat = options.page_repeat, pageset_repeat = options.pageset_repeat, - cold_load_percent = options.cold_load_percent, + cold_load_percent = self.cold_load_percent, report_speed_index = options.report_speed_index) @@ -139,10 +141,10 @@ tag = 'netsim' page_set = page_sets.Top10PageSet options = { - 'cold_load_percent': 100, 'extra_wpr_args_as_string': '--shaping_type=proxy --net=cable', 'pageset_repeat': 6, } + cold_load_percent = 100 @classmethod def Name(cls): @@ -152,7 +154,7 @@ return page_cycler.PageCycler( page_repeat = options.page_repeat, pageset_repeat = options.pageset_repeat, - cold_load_percent = options.cold_load_percent, + cold_load_percent = self.cold_load_percent, report_speed_index = options.report_speed_index, clear_cache_before_each_run = True) @@ -195,7 +197,7 @@ return 'page_cycler.tough_layout_cases' -# crbug.com/273986: This test is really flakey on xp. +# crbug.com/273986: This test is flakey on Windows. @benchmark.Disabled('win') class PageCyclerTypical25(_PageCycler): """Page load time benchmark for a 25 typical web pages. @@ -211,6 +213,21 @@ def CreatePageSet(self, options): return page_sets.Typical25PageSet(run_no_page_interactions=True) +# crbug.com/273986: This test is flakey on Windows. +@benchmark.Disabled # crbug.com/463346: Test is crashing Chrome. +class PageCyclerOopifTypical25(_PageCycler): + """ A varation of the benchmark above, but running in --site-per-process + to allow measuring performance of out-of-process iframes. + """ + @classmethod + def Name(cls): + return 'page_cycler_oopif.typical_25' + + def CustomizeBrowserOptions(self, options): + options.AppendExtraBrowserArgs(['--site-per-process']) + + def CreatePageSet(self, options): + return page_sets.Typical25PageSet(run_no_page_interactions=True) @benchmark.Disabled # crbug.com/443730 class PageCyclerBigJs(_PageCycler): @@ -218,4 +235,3 @@ @classmethod def Name(cls): return 'page_cycler.big_js' -
diff --git a/tools/perf/benchmarks/rasterize_and_record_micro.py b/tools/perf/benchmarks/rasterize_and_record_micro.py index 81b450ec..88ddaad2 100644 --- a/tools/perf/benchmarks/rasterize_and_record_micro.py +++ b/tools/perf/benchmarks/rasterize_and_record_micro.py
@@ -46,7 +46,7 @@ """Measures rasterize and record performance on the top 25 web pages. http://www.chromium.org/developers/design-documents/rendering-benchmarks""" - page_set = page_sets.Top25SmoothPageSet + page_set = page_sets.Top25PageSet @classmethod def Name(cls):
diff --git a/tools/perf/benchmarks/session_restore.py b/tools/perf/benchmarks/session_restore.py index 997b904..278efab 100644 --- a/tools/perf/benchmarks/session_restore.py +++ b/tools/perf/benchmarks/session_restore.py
@@ -23,6 +23,7 @@ TODO(slamm): Make SmallProfileCreator and this use the same page_set ref. """ page_set = page_sets.Typical25PageSet + tag = None # override with 'warm' or 'cold' @classmethod def Name(cls): @@ -48,6 +49,10 @@ small_profile_creator.SmallProfileCreator, profile_type, new_args) args.browser_options.profile_dir = profile_dir + @classmethod + def ValueCanBeAddedPredicate(cls, _, is_first_result): + return cls.tag == 'cold' or not is_first_result + def CreateUserStorySet(self, _): """Return a user story set that only has the first user story.
diff --git a/tools/perf/benchmarks/startup.py b/tools/perf/benchmarks/startup.py index b68ae4c..957619a0d 100644 --- a/tools/perf/benchmarks/startup.py +++ b/tools/perf/benchmarks/startup.py
@@ -27,6 +27,10 @@ def Name(cls): return 'startup' + @classmethod + def ValueCanBeAddedPredicate(cls, _, is_first_result): + return not is_first_result + def CreatePageTest(self, options): return startup.Startup(cold=False)
diff --git a/tools/perf/measurements/measurement_smoke_test.py b/tools/perf/measurements/measurement_smoke_test.py index e27199c5..0a17633 100644 --- a/tools/perf/measurements/measurement_smoke_test.py +++ b/tools/perf/measurements/measurement_smoke_test.py
@@ -9,8 +9,6 @@ import logging import unittest -from measurements import rasterize_and_record_micro - from telemetry import benchmark as benchmark_module from telemetry.core import discover from telemetry.page import page_test @@ -66,8 +64,6 @@ def testNoNewActionNameToRunUsed(self): invalid_tests = [] for test in _GetAllPossiblePageTestInstances(): - if isinstance(test, rasterize_and_record_micro.RasterizeAndRecordMicro): - continue if not hasattr(test, 'action_name_to_run'): invalid_tests.append(test) logging.error('Test %s missing action_name_to_run attribute.',
diff --git a/tools/perf/measurements/oilpan_gc_times.py b/tools/perf/measurements/oilpan_gc_times.py index 49e0a2e3..eb105ae 100644 --- a/tools/perf/measurements/oilpan_gc_times.py +++ b/tools/perf/measurements/oilpan_gc_times.py
@@ -176,4 +176,5 @@ def CustomizeBrowserOptions(cls, options): # 'expose-internals-for-testing' can be enabled on content shell. assert 'content-shell' in options.browser_type - options.AppendExtraBrowserArgs('--expose-internals-for-testing') + options.AppendExtraBrowserArgs(['--expose-internals-for-testing', + '--js-flags=--expose-gc'])
diff --git a/tools/perf/measurements/page_cycler.py b/tools/perf/measurements/page_cycler.py index ce1dc97..b7e2c89 100644 --- a/tools/perf/measurements/page_cycler.py +++ b/tools/perf/measurements/page_cycler.py
@@ -61,8 +61,6 @@ (int(pageset_repeat) - 1) * (100 - cold_load_percent) / 100) number_warm_runs = number_warm_pageset_runs * page_repeat self._cold_run_start_index = number_warm_runs + page_repeat - self._discard_first_result = (not cold_load_percent or - self._discard_first_result) else: self._cold_run_start_index = pageset_repeat * page_repeat
diff --git a/tools/perf/measurements/rasterize_and_record_micro.py b/tools/perf/measurements/rasterize_and_record_micro.py index 73fbbfa..41bd09b 100644 --- a/tools/perf/measurements/rasterize_and_record_micro.py +++ b/tools/perf/measurements/rasterize_and_record_micro.py
@@ -13,7 +13,8 @@ class RasterizeAndRecordMicro(page_test.PageTest): def __init__(self, start_wait_time=2, rasterize_repeat=100, record_repeat=100, timeout=120, report_detailed_results=False): - super(RasterizeAndRecordMicro, self).__init__('') + super(RasterizeAndRecordMicro, self).__init__( + action_name_to_run='RunPageInteractions') self._chrome_branch_number = None self._start_wait_time = start_wait_time self._rasterize_repeat = rasterize_repeat
diff --git a/tools/perf/measurements/startup.py b/tools/perf/measurements/startup.py index aa6ad16..09e02e8 100644 --- a/tools/perf/measurements/startup.py +++ b/tools/perf/measurements/startup.py
@@ -24,9 +24,6 @@ def CustomizeBrowserOptions(self, options): if self._cold: options.clear_sytem_cache_for_browser_and_profile_on_start = True - else: - self.discard_first_result = True - options.AppendExtraBrowserArgs([ '--enable-stats-collection-bindings' ])
diff --git a/tools/perf/page_sets/data/top_25_smooth.json b/tools/perf/page_sets/data/top_25_smooth.json new file mode 100644 index 0000000..59fb8ed --- /dev/null +++ b/tools/perf/page_sets/data/top_25_smooth.json
@@ -0,0 +1,40 @@ +{ + "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", + "archives": { + "top_25_003.wpr": [ + "Facebook" + ], + "top_25_001.wpr": [ + "https://plus.google.com/110031535020051778989/posts" + ], + "top_25_002.wpr": [ + "https://www.google.com/search?q=cats&tbm=isch" + ], + "top_25_000.wpr": [ + "https://www.google.com/#hl=en&q=barack+obama", + "https://mail.google.com/mail/", + "https://www.google.com/calendar/", + "https://drive.google.com", + "https://docs.google.com/document/d/1X-IKNjtEnx-WW5JIKRLsyhz5sbsat3mfTpAPUSX3_s4/view", + "http://www.youtube.com", + "http://googlewebmastercentral.blogspot.com/", + "http://en.blog.wordpress.com/2012/09/04/freshly-pressed-editors-picks-for-august-2012/", + "http://www.facebook.com/barackobama", + "http://www.linkedin.com/in/linustorvalds", + "http://en.wikipedia.org/wiki/Wikipedia", + "https://twitter.com/katyperry", + "http://pinterest.com", + "http://espn.go.com", + "http://news.yahoo.com", + "http://www.cnn.com", + "http://www.weather.com/weather/right-now/Mountain+View+CA+94043", + "http://www.amazon.com", + "http://www.ebay.com", + "http://games.yahoo.com", + "http://booking.com", + "http://answers.yahoo.com", + "http://sports.yahoo.com/", + "http://techcrunch.com" + ] + } +} \ No newline at end of file
diff --git a/tools/perf/page_sets/key_mobile_sites_smooth.py b/tools/perf/page_sets/key_mobile_sites_smooth.py index 918e46d..7b95d79 100644 --- a/tools/perf/page_sets/key_mobile_sites_smooth.py +++ b/tools/perf/page_sets/key_mobile_sites_smooth.py
@@ -40,6 +40,36 @@ _IssueMarkerAndScroll(action_runner) +class LinkedInSmoothPage(key_mobile_sites_pages.LinkedInPage): + + def __init__(self, page_set): + super(LinkedInSmoothPage, self).__init__(page_set=page_set) + + # Linkedin has expensive shader compilation so it can benefit from shader + # cache from reload. + def RunNavigateSteps(self, action_runner): + super(LinkedInSmoothPage, self).RunNavigateSteps(action_runner) + action_runner.ScrollPage() + action_runner.ReloadPage() + super(LinkedInSmoothPage, self).RunNavigateSteps(action_runner) + + +class WowwikiSmoothPage(KeyMobileSitesSmoothPage): + """Why: Mobile wiki.""" + def __init__(self, page_set): + super(WowwikiSmoothPage, self).__init__( + url='http://www.wowwiki.com/World_of_Warcraft:_Mists_of_Pandaria', + page_set=page_set) + + # Wowwiki has expensive shader compilation so it can benefit from shader + # cache from reload. + def RunNavigateSteps(self, action_runner): + super(WowwikiSmoothPage, self).RunNavigateSteps(action_runner) + action_runner.ScrollPage() + action_runner.ReloadPage() + super(WowwikiSmoothPage, self).RunNavigateSteps(action_runner) + + class GmailSmoothPage(key_mobile_sites_pages.GmailPage): def RunPageInteractions(self, action_runner): @@ -129,7 +159,6 @@ key_mobile_sites_pages.CnnArticlePage, key_mobile_sites_pages.FacebookPage, key_mobile_sites_pages.YoutubeMobilePage, - key_mobile_sites_pages.LinkedInPage, key_mobile_sites_pages.YahooAnswersPage, key_mobile_sites_pages.GoogleNewsMobilePage, ] @@ -137,6 +166,10 @@ self.AddUserStory( _CreatePageClassWithSmoothInteractions(page_class)(self)) + self.AddUserStory( + _CreatePageClassWithSmoothInteractions(LinkedInSmoothPage)(self)) + self.AddUserStory(WowwikiSmoothPage(self)) + # Add pages with custom page interaction logic. # Page behaves non-deterministically, replaced with test version for now. @@ -253,8 +286,6 @@ 'http://www.sfgate.com/', # Why: Non-latin character set 'http://worldjournal.com/', - # Why: Mobile wiki - 'http://www.wowwiki.com/World_of_Warcraft:_Mists_of_Pandaria', # Why: #15 Alexa news 'http://online.wsj.com/home-page', # Why: Image-heavy mobile site
diff --git a/tools/perf/page_sets/top_25_pages.py b/tools/perf/page_sets/top_25_pages.py new file mode 100644 index 0000000..c6ba4cd --- /dev/null +++ b/tools/perf/page_sets/top_25_pages.py
@@ -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. +from telemetry.page import page +from telemetry.page import page_set + +from page_sets import top_pages + + +class Top25PageSet(page_set.PageSet): + + """ Page set consists of top 25 pages with only navigation actions. """ + + def __init__(self): + super(Top25PageSet, self).__init__( + user_agent_type='desktop', + archive_data_file='data/top_25.json', + bucket=page_set.PARTNER_BUCKET) + + self.AddUserStory(top_pages.GoogleWebSearchPage(self)) + self.AddUserStory(top_pages.GmailPage(self)) + self.AddUserStory(top_pages.GoogleCalendarPage(self)) + self.AddUserStory(top_pages.GoogleImageSearchPage(self)) + self.AddUserStory(top_pages.GoogleDocPage(self)) + self.AddUserStory(top_pages.GooglePlusPage(self)) + self.AddUserStory(top_pages.YoutubePage(self)) + self.AddUserStory(top_pages.BlogspotPage(self)) + self.AddUserStory(top_pages.WordpressPage(self)) + self.AddUserStory(top_pages.FacebookPage(self)) + self.AddUserStory(top_pages.LinkedinPage(self)) + self.AddUserStory(top_pages.WikipediaPage(self)) + self.AddUserStory(top_pages.TwitterPage(self)) + self.AddUserStory(top_pages.PinterestPage(self)) + self.AddUserStory(top_pages.ESPNPage(self)) + self.AddUserStory(top_pages.WeatherPage(self)) + self.AddUserStory(top_pages.YahooGamesPage(self)) + + other_urls = [ + # Why: #1 news worldwide (Alexa global) + 'http://news.yahoo.com', + # Why: #2 news worldwide + 'http://www.cnn.com', + # Why: #1 world commerce website by visits; #3 commerce in the US by + # time spent + 'http://www.amazon.com', + # Why: #1 commerce website by time spent by users in US + 'http://www.ebay.com', + # Why: #1 Alexa recreation + 'http://booking.com', + # Why: #1 Alexa reference + 'http://answers.yahoo.com', + # Why: #1 Alexa sports + 'http://sports.yahoo.com/', + # Why: top tech blog + 'http://techcrunch.com' + ] + + for url in other_urls: + self.AddUserStory(page.Page(url, self))
diff --git a/tools/perf/page_sets/top_25_smooth.py b/tools/perf/page_sets/top_25_smooth.py index cf5d8fc0..5088a82 100644 --- a/tools/perf/page_sets/top_25_smooth.py +++ b/tools/perf/page_sets/top_25_smooth.py
@@ -93,7 +93,7 @@ def __init__(self): super(Top25SmoothPageSet, self).__init__( user_agent_type='desktop', - archive_data_file='data/top_25.json', + archive_data_file='data/top_25_smooth.json', bucket=page_set_module.PARTNER_BUCKET) self.AddUserStory(_CreatePageClassWithSmoothInteractions(
diff --git a/tools/perf/profile_creators/fast_navigation_profile_extender.py b/tools/perf/profile_creators/fast_navigation_profile_extender.py index e4904038..abcc8eb 100644 --- a/tools/perf/profile_creators/fast_navigation_profile_extender.py +++ b/tools/perf/profile_creators/fast_navigation_profile_extender.py
@@ -161,7 +161,7 @@ """Retrives the URL of the tab.""" try: return tab.EvaluateJavaScript('document.URL', timeout) - except (exceptions.DevtoolsTargetCrashException, + except (exceptions.Error, devtools_http.DevToolsClientConnectionError, devtools_http.DevToolsClientUrlError): return None @@ -204,7 +204,7 @@ try: tab.Navigate(url, None, timeout_in_seconds) - except (exceptions.DevtoolsTargetCrashException, + except (exceptions.Error, devtools_http.DevToolsClientConnectionError, devtools_http.DevToolsClientUrlError): # We expect a time out. It's possible for other problems to arise, but @@ -242,7 +242,7 @@ except exceptions.TimeoutException: # Ignore time outs. pass - except (exceptions.DevtoolsTargetCrashException, + except (exceptions.Error, devtools_http.DevToolsClientConnectionError, devtools_http.DevToolsClientUrlError): # If any error occurs, remove the tab. it's probably in an
diff --git a/tools/telemetry/bin/win/AMD64/ippet.zip.sha1 b/tools/telemetry/bin/win/ippet.zip.sha1 similarity index 100% rename from tools/telemetry/bin/win/AMD64/ippet.zip.sha1 rename to tools/telemetry/bin/win/ippet.zip.sha1
diff --git a/tools/telemetry/bin/win/AMD64/winring0.zip.sha1 b/tools/telemetry/bin/win/winring0.zip.sha1 similarity index 100% rename from tools/telemetry/bin/win/AMD64/winring0.zip.sha1 rename to tools/telemetry/bin/win/winring0.zip.sha1
diff --git a/tools/telemetry/count b/tools/telemetry/count new file mode 100755 index 0000000..01b50893 --- /dev/null +++ b/tools/telemetry/count
@@ -0,0 +1,40 @@ +#! /usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import imp +import inspect +import os + +from telemetry.util import path + + +def IncludeDir(dir_name): + return (dir_name[0] != '.' and dir_name[0] != '_' and + not dir_name.startswith('internal') and not dir_name == 'third_party') + + +def IncludeFile(file_name): + root, ext = os.path.splitext(file_name) + return (file_name[0] != '.' and + not root.endswith('_unittest') and ext == '.py') + + +def ListFiles(directory): + matching_files = [] + for root, dirs, files in os.walk(directory): + dirs[:] = [dir_name for dir_name in dirs if IncludeDir(dir_name)] + matching_files += [ + os.path.relpath(os.path.join(root, file_name), directory) + for file_name in files if IncludeFile(file_name)] + return sorted(matching_files) + + +def main(): + modules = ListFiles(path.GetTelemetryDir()) + print len(modules) + + +if __name__ == '__main__': + main()
diff --git a/tools/telemetry/telemetry/benchmark.py b/tools/telemetry/telemetry/benchmark.py index f86393c..1c42c0c 100644 --- a/tools/telemetry/telemetry/benchmark.py +++ b/tools/telemetry/telemetry/benchmark.py
@@ -138,17 +138,22 @@ def ProcessCommandLineArgs(cls, parser, args): pass + # pylint: disable=unused-argument @classmethod - def ValueCanBeAddedPredicate(cls, value): # pylint: disable=unused-argument - """ Returns whether |value| can be added to the test results. + def ValueCanBeAddedPredicate(cls, value, is_first_result): + """Returns whether |value| can be added to the test results. + Override this method to customize the logic of adding values to test results. Args: value: a value.Value instance. + is_first_result: True if |value| is the first result for its + corresponding user story. - Returns: a boolean. True if value should be added to the test results and - False otherwise. + Returns: + True if |value| should be added to the test results. + Otherwise, it returns False. """ return True
diff --git a/tools/telemetry/telemetry/benchmark_runner.py b/tools/telemetry/telemetry/benchmark_runner.py index 348d5f8..83552ea 100644 --- a/tools/telemetry/telemetry/benchmark_runner.py +++ b/tools/telemetry/telemetry/benchmark_runner.py
@@ -68,7 +68,7 @@ if len(commands) == 1: command = commands[0] parser = command.CreateParser() - command.AddCommandLineArgs(parser) + command.AddCommandLineArgs(parser, None) parser.print_help() return 0
diff --git a/tools/telemetry/telemetry/benchmark_unittest.py b/tools/telemetry/telemetry/benchmark_unittest.py index 4335a78a..2bdcccc 100644 --- a/tools/telemetry/telemetry/benchmark_unittest.py +++ b/tools/telemetry/telemetry/benchmark_unittest.py
@@ -132,7 +132,7 @@ def testBenchmarkPredicate(self): class PredicateBenchmark(TestBenchmark): @classmethod - def ValueCanBeAddedPredicate(cls, value): + def ValueCanBeAddedPredicate(cls, value, is_first_result): return False original_run_fn = user_story_runner.Run
diff --git a/tools/telemetry/telemetry/core/backends/chrome/cros_unittest.py b/tools/telemetry/telemetry/core/backends/chrome/cros_unittest.py index aeda1d2..61808685 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/cros_unittest.py +++ b/tools/telemetry/telemetry/core/backends/chrome/cros_unittest.py
@@ -62,7 +62,7 @@ extension.ExecuteJavaScript('chrome.autotestPrivate.logout();') # TODO(chrishenry): crbug.com/450278. DevToolsClientConnectionError # should probably be caught at a lower-level. - except (exceptions.AppCrashException, + except (exceptions.Error, devtools_http.DevToolsClientConnectionError): pass util.WaitFor(lambda: not self._IsCryptohomeMounted(), 20)
diff --git a/tools/telemetry/telemetry/core/backends/chrome/misc_web_contents_backend.py b/tools/telemetry/telemetry/core/backends/chrome/misc_web_contents_backend.py index 480d095..130cfc7 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/misc_web_contents_backend.py +++ b/tools/telemetry/telemetry/core/backends/chrome/misc_web_contents_backend.py
@@ -22,7 +22,7 @@ """Lightweight property to determine if the oobe webui is visible.""" try: return bool(len(self)) - except (exceptions.AppCrashException, + except (exceptions.Error, devtools_http.DevToolsClientConnectionError): return False
diff --git a/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend.py b/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend.py index ec93210..796b73e 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend.py +++ b/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend.py
@@ -74,10 +74,12 @@ def CreateWrapper(self, inspector_backend): return tab.Tab(inspector_backend, self, self._browser_backend.browser) - def _HandleDevToolsConnectionError(self, err_msg): + def _HandleDevToolsConnectionError(self, error): if not self._browser_backend.IsAppRunning(): - raise exceptions.BrowserGoneException(self.app, err_msg) + error.AddDebuggingMessage('The browser is not running. It probably ' + 'crashed.') elif not self._browser_backend.HasBrowserFinishedLaunching(): - raise exceptions.BrowserConnectionGoneException(self.app, err_msg) + error.AddDebuggingMessage('The browser exists but cannot be reached.') else: - raise exceptions.DevtoolsTargetCrashException(self.app, err_msg) + error.AddDebuggingMessage('The browser exists and can be reached. ' + 'The devtools target probably crashed.')
diff --git a/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend_unittest.py b/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend_unittest.py index c4377db..5ceacbbb 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend_unittest.py +++ b/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend_unittest.py
@@ -1,11 +1,14 @@ # Copyright 2015 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. + +from telemetry import decorators from telemetry.core import exceptions from telemetry.unittest_util import tab_test_case class TabListBackendTest(tab_test_case.TabTestCase): + @decorators.Enabled('has tabs') def testTabIdMatchesContextId(self): # Ensure that there are two tabs. while len(self.tabs) < 2: @@ -18,6 +21,7 @@ self.assertEquals(tab.id, context_id) tabs.append(self.tabs.GetTabById(context_id)) + @decorators.Enabled('has tabs') def testTabIdStableAfterTabCrash(self): # Ensure that there are two tabs. while len(self.tabs) < 2:
diff --git a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend.py b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend.py index b8483be1..886024e 100644 --- a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend.py +++ b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend.py
@@ -17,16 +17,11 @@ from telemetry.core.backends.chrome_inspector import inspector_runtime from telemetry.core.backends.chrome_inspector import inspector_websocket from telemetry.core.backends.chrome_inspector import websocket -from telemetry.core.heap import model as heap_model_module from telemetry.image_processing import image_util from telemetry.timeline import model as timeline_model_module from telemetry.timeline import trace_data as trace_data_module -class InspectorException(Exception): - pass - - class InspectorBackend(object): def __init__(self, app, devtools_client, context, timeout=60): self._websocket = inspector_websocket.InspectorWebsocket() @@ -45,7 +40,7 @@ try: self._websocket.Connect(self.debugger_url) except (websocket.WebSocketException, exceptions.TimeoutException) as e: - raise InspectorException(e.msg) + self._HandleError(e) self._console = inspector_console.InspectorConsole(self._websocket) self._memory = inspector_memory.InspectorMemory(self._websocket) @@ -203,17 +198,52 @@ self._WaitForInspectorToGoAwayAndReconnect() return if res['method'] == 'Inspector.targetCrashed': - raise exceptions.DevtoolsTargetCrashException(self.app) + exception = exceptions.DevtoolsTargetCrashException(self.app) + self._AddDebuggingInformation(exception) + raise exception def _HandleError(self, error): + """Converts a websocket Exception into a Telemetry exception. + + This method always raises a Telemetry exception. It appends debugging + information. + + Args: + error: An instance of socket.error or websocket.WebSocketException. + Raises: + exception.TimeoutException: A timeout occured. + exception.DevtoolsTargetCrashException: On any other error, the most + likely explanation is that the devtool's target crashed. + """ + if isinstance(error, websocket.WebSocketTimeoutException): + new_error = exceptions.TimeoutException() + else: + new_error = exceptions.DevtoolsTargetCrashException(self.app) + + original_error_msg = 'Original exception:\n' + str(error) + new_error.AddDebuggingMessage(original_error_msg) + self._AddDebuggingInformation(new_error) + + raise new_error + + def _AddDebuggingInformation(self, error): + """Adds debugging information to error. + + Args: + error: An instance of exceptions.Error. + """ if self.IsInspectable(): - raise exceptions.DevtoolsTargetCrashException(self.app, + msg = ( 'Received a socket error in the browser connection and the tab ' - 'still exists, assuming it timed out. ' - 'Error=%s' % error) - raise exceptions.DevtoolsTargetCrashException(self.app, - 'Received a socket error in the browser connection and the tab no ' - 'longer exists, assuming it crashed. Error=%s' % error) + 'still exists. The operation probably timed out.' + ) + else: + msg = ( + 'Received a socket error in the browser connection and the tab no ' + 'longer exists. The tab probably crashed.' + ) + error.AddDebuggingMessage(msg) + error.AddDebuggingMessage('Debugger url: %s' % self.debugger_url) def _WaitForInspectorToGoAwayAndReconnect(self): sys.stderr.write('The connection to Chrome was lost to the Inspector UI.\n') @@ -240,25 +270,3 @@ self._page.CollectGarbage() except (socket.error, websocket.WebSocketException) as e: self._HandleError(e) - - def TakeJSHeapSnapshot(self, timeout=120): - snapshot = [] - - def OnNotification(res): - if res['method'] == 'HeapProfiler.addHeapSnapshotChunk': - snapshot.append(res['params']['chunk']) - - try: - self._websocket.RegisterDomain('HeapProfiler', OnNotification) - - self._websocket.SyncRequest({'method': 'Page.getResourceTree'}, timeout) - self._websocket.SyncRequest({'method': 'Debugger.enable'}, timeout) - self._websocket.SyncRequest( - {'method': 'HeapProfiler.takeHeapSnapshot'}, timeout) - except (socket.error, websocket.WebSocketException) as e: - self._HandleError(e) - - snapshot = ''.join(snapshot) - - self.UnregisterDomain('HeapProfiler') - return heap_model_module.Model(snapshot)
diff --git a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend_list.py b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend_list.py index ea3a6e2f..c0c6a7c6 100644 --- a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend_list.py +++ b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend_list.py
@@ -77,9 +77,9 @@ try: backend = self._devtools_context_map_backend.GetInspectorBackend( context_id) - except inspector_backend.InspectorException: - err_msg = sys.exc_info()[1] - self._HandleDevToolsConnectionError(err_msg) + except exceptions.Error as e: + self._HandleDevToolsConnectionError(e) + raise e # Propagate KeyError from GetInspectorBackend call. wrapper = self.CreateWrapper(backend) @@ -114,10 +114,10 @@ if context_id not in self._filtered_context_ids: del self._wrapper_dict[context_id] - def _HandleDevToolsConnectionError(self, err_msg): - """Call when handling errors in connecting to the DevTools websocket. + def _HandleDevToolsConnectionError(self, error): + """Called when handling errors in connecting to the DevTools websocket. - This can be overwritten by sub-classes to further specify the exceptions - which should be thrown. + This can be overwritten by sub-classes to add more debugging information to + errors. """ - raise exceptions.DevtoolsTargetCrashException(self.app, err_msg) + pass
diff --git a/tools/telemetry/telemetry/core/exceptions.py b/tools/telemetry/telemetry/core/exceptions.py index ed9f9cb..6b13129f 100644 --- a/tools/telemetry/telemetry/core/exceptions.py +++ b/tools/telemetry/telemetry/core/exceptions.py
@@ -2,10 +2,39 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import sys + class Error(Exception): """Base class for Telemetry exceptions.""" - pass + def __init__(self, msg=''): + super(Error, self).__init__(msg) + self._debugging_messages = [] + + def AddDebuggingMessage(self, msg): + """Adds a message to the description of the exception. + + Many Telemetry exceptions arise from failures in another application. These + failures are difficult to pinpoint. This method allows Telemetry classes to + append useful debugging information to the exception. This method also logs + information about the location from where it was called. + """ + frame = sys._getframe(1) + line_number = frame.f_lineno + file_name = frame.f_code.co_filename + function_name = frame.f_code.co_name + call_site = '%s:%s %s' % (file_name, line_number, function_name) + annotated_message = '(%s) %s' % (call_site, msg) + + self._debugging_messages.append(annotated_message) + + def __str__(self): + divider = '\n' + '*' * 80 + '\n' + output = super(Error, self).__str__() + for message in self._debugging_messages: + output += divider + output += message + return output class PlatformError(Error):
diff --git a/tools/telemetry/telemetry/core/heap/chrome_js_heap_snapshot_parser.py b/tools/telemetry/telemetry/core/heap/chrome_js_heap_snapshot_parser.py deleted file mode 100644 index 9706dad..0000000 --- a/tools/telemetry/telemetry/core/heap/chrome_js_heap_snapshot_parser.py +++ /dev/null
@@ -1,248 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import json - -from telemetry.core.heap import live_heap_object -from telemetry.core.heap import retaining_edge - - -class ChromeJsHeapSnapshotParser(object): - """ Parser for the heap snapshot. - - The heap snapshot JSON format is defined by HeapSnapshotJSONSerializer in V8. - - The snapshot contains a list of integers describing nodes (types, names, etc.) - and a list of integers describing edges (types, the node the edge points to, - etc.) and a string table. All strings are expressed as indices to the string - table. - - In addition, the snapshot contains meta information describing the data fields - for nodes and the data fields for edges. - - Attributes: - _node_dict: {int -> LiveHeapObject}, maps integer ids to LiveHeapObject - objects. - _node_list: [int], the raw node data of the heap snapshot. - _edge_list: [int], the raw edge data of the heap snapshot. - _node_types: [str], the possible node types in the heap snapshot. - _edge_types: [str], the possible edge types in the heap snapshot. - _node_fields: [str], the fields present in the heap snapshot for each node. - _edge_fields: [str], the fields present in the heap snapshot for each node. - _node_type_ix: int, index of the node type field. - _node_name_ix: int, index of the node name field. - _node_id_ix: int, index of the node id field. - _node_edge_count_ix: int, index of the node edge count field. - _node_field_count: int, number of node fields. - _edge_type_ix: int, index of the edge type field. - _edge_name_or_ix_ix: int, index of the "edge name or index" field. - _edge_to_node_ix: int, index of the "to node for an edge" field. - _edge_field_count: int, number of edge fields. - """ - - def __init__(self, raw_data): - heap = json.loads(raw_data) - self._node_dict = {} - - # Read the snapshot components (nodes, edges, strings, metadata). - self._node_list = heap['nodes'] - self._edge_list = heap['edges'] - self._strings = heap['strings'] - - self._node_types = heap['snapshot']['meta']['node_types'][0] - self._edge_types = heap['snapshot']['meta']['edge_types'][0] - node_fields = heap['snapshot']['meta']['node_fields'] - edge_fields = heap['snapshot']['meta']['edge_fields'] - - # Find the indices of the required node and edge fields based on the - # metadata. - self._node_type_ix = node_fields.index('type') - self._node_name_ix = node_fields.index('name') - self._node_id_ix = node_fields.index('id') - self._node_edge_count_ix = node_fields.index('edge_count') - self._node_field_count = len(node_fields) - - self._edge_type_ix = edge_fields.index('type') - self._edge_name_or_ix_ix = edge_fields.index('name_or_index') - self._edge_to_node_ix = edge_fields.index('to_node') - self._edge_field_count = len(edge_fields) - - self._ParseSnapshot() - - @staticmethod - def CanImport(raw_data): - heap = json.loads(raw_data) - if ('nodes' not in heap or 'edges' not in heap or 'strings' not in heap or - 'snapshot' not in heap or 'meta' not in heap['snapshot']): - return False - meta = heap['snapshot']['meta'] - if ('node_types' not in meta or 'edge_types' not in meta or - 'node_fields' not in meta or 'edge_fields' not in meta): - return False - node_fields = meta['node_fields'] - edge_fields = meta['edge_fields'] - if ('type' not in node_fields or 'name' not in node_fields or - 'id' not in node_fields or 'edge_count' not in node_fields): - return False - if ('type' not in edge_fields or 'name_or_index' not in edge_fields or - 'to_node' not in edge_fields): - return False - return True - - def GetAllLiveHeapObjects(self): - return self._node_dict.values() - - @staticmethod - def LiveHeapObjectToJavaScript(heap_object): - return heap_object.name or str(heap_object) - - @staticmethod - def RetainingEdgeToJavaScript(edge): - if edge.type_string == 'property': - return '.' + edge.name_string - if edge.type_string == 'element': - return '[' + edge.name_string + ']' - return str(edge) - - def _ParseSnapshot(self): - """Parses the stored JSON snapshot data. - - Fills in self._node_dict with LiveHeapObject objects constructed based on - the heap snapshot. The LiveHeapObject objects contain the associated - RetainingEdge objects. - """ - edge_start_ix = 0 - for ix in xrange(0, len(self._node_list), self._node_field_count): - edge_start_ix = self._ReadNodeFromIndex(ix, edge_start_ix) - - # Add pointers to the endpoints to the edges, and associate the edges with - # the "to" nodes. - for node_id in self._node_dict: - n = self._node_dict[node_id] - for e in n.edges_from: - self._node_dict[e.to_object_id].AddEdgeTo(e) - e.SetFromObject(n) - e.SetToObject(self._node_dict[e.to_object_id]) - - def _ReadNodeFromIndex(self, ix, edges_start): - """Reads the data for a node from the heap snapshot. - - If the index contains an interesting node, constructs a Node object and adds - it to self._node_dict. - - Args: - ix: int, index into the self._node_list array. - edges_start: int, the index of the edge array where the edges for the node - start. - Returns: - int, the edge start index for the next node. - - Raises: - Exception: The node list of the snapshot is malformed. - """ - if ix + self._node_field_count > len(self._node_list): - raise Exception('Snapshot node list too short') - - type_ix = self._node_list[ix + self._node_type_ix] - type_string = self._node_types[int(type_ix)] - - # edges_end is noninclusive (the index of the first edge that is not part of - # this node). - edge_count = self._node_list[ix + self._node_edge_count_ix] - edges_end = edges_start + edge_count * self._edge_field_count - - if ChromeJsHeapSnapshotParser._IsNodeTypeUninteresting(type_string): - return edges_end - - name_ix = self._node_list[ix + self._node_name_ix] - node_id = self._node_list[ix + self._node_id_ix] - - def ConstructorName(type_string, node_name_ix): - if type_string == 'object': - return self._strings[int(node_name_ix)] - return '(%s)' % type_string - - ctor_name = ConstructorName(type_string, name_ix) - n = live_heap_object.LiveHeapObject(node_id, type_string, ctor_name) - if type_string == 'string': - n.string = self._strings[int(name_ix)] - - for edge_ix in xrange(edges_start, edges_end, self._edge_field_count): - edge = self._ReadEdgeFromIndex(node_id, edge_ix) - if edge: - # The edge will be associated with the other endpoint when all the data - # has been read. - n.AddEdgeFrom(edge) - - self._node_dict[node_id] = n - return edges_end - - @staticmethod - def _IsNodeTypeUninteresting(type_string): - """Helper function for filtering out nodes from the heap snapshot. - - Args: - type_string: str, type of the node. - Returns: - bool, True if the node is of an uninteresting type and shouldn't be - included in the heap snapshot analysis. - """ - uninteresting_types = ('hidden', 'code', 'number', 'native', 'synthetic') - return type_string in uninteresting_types - - @staticmethod - def _IsEdgeTypeUninteresting(edge_type_string): - """Helper function for filtering out edges from the heap snapshot. - - Args: - edge_type_string: str, type of the edge. - Returns: - bool, True if the edge is of an uninteresting type and shouldn't be - included in the heap snapshot analysis. - """ - uninteresting_types = ('weak', 'hidden', 'internal') - return edge_type_string in uninteresting_types - - def _ReadEdgeFromIndex(self, node_id, edge_ix): - """Reads the data for an edge from the heap snapshot. - - Args: - node_id: int, id of the node which is the starting point of the edge. - edge_ix: int, index into the self._edge_list array. - Returns: - Edge, if the index contains an interesting edge, otherwise None. - Raises: - Exception: The node list of the snapshot is malformed. - """ - if edge_ix + self._edge_field_count > len(self._edge_list): - raise Exception('Snapshot edge list too short') - - edge_type_ix = self._edge_list[edge_ix + self._edge_type_ix] - edge_type_string = self._edge_types[int(edge_type_ix)] - - if ChromeJsHeapSnapshotParser._IsEdgeTypeUninteresting(edge_type_string): - return None - - child_name_or_ix = self._edge_list[edge_ix + self._edge_name_or_ix_ix] - child_node_ix = self._edge_list[edge_ix + self._edge_to_node_ix] - - # The child_node_ix is an index into the node list. Read the actual - # node information. - child_node_type_ix = self._node_list[child_node_ix + self._node_type_ix] - child_node_type_string = self._node_types[int(child_node_type_ix)] - child_node_id = self._node_list[child_node_ix + self._node_id_ix] - - if ChromeJsHeapSnapshotParser._IsNodeTypeUninteresting( - child_node_type_string): - return None - - child_name_string = '' - # For element nodes, the child has no name (only an index). - if (edge_type_string == 'element' or - int(child_name_or_ix) >= len(self._strings)): - child_name_string = str(child_name_or_ix) - else: - child_name_string = self._strings[int(child_name_or_ix)] - return retaining_edge.RetainingEdge(node_id, child_node_id, - edge_type_string, child_name_string)
diff --git a/tools/telemetry/telemetry/core/heap/chrome_js_heap_snapshot_parser_unittest.py b/tools/telemetry/telemetry/core/heap/chrome_js_heap_snapshot_parser_unittest.py deleted file mode 100644 index 94bb49a..0000000 --- a/tools/telemetry/telemetry/core/heap/chrome_js_heap_snapshot_parser_unittest.py +++ /dev/null
@@ -1,57 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import json -import unittest - -from telemetry.core.heap import chrome_js_heap_snapshot_parser - - -class ChromeJsHeapSnapshotParserUnittest(unittest.TestCase): - def _HeapSnapshotData(self, node_types, edge_types, node_fields, edge_fields, - node_list, edge_list, strings): - """Helper for creating heap snapshot data.""" - return {'snapshot': {'meta': {'node_types': [node_types], - 'edge_types': [edge_types], - 'node_fields': node_fields, - 'edge_fields': edge_fields}}, - 'nodes': node_list, - 'edges': edge_list, - 'strings': strings} - - def testParseSimpleSnapshot(self): - # Create a snapshot containing 2 nodes and an edge between them. - node_types = ['object'] - edge_types = ['property'] - node_fields = ['type', 'name', 'id', 'edge_count'] - edge_fields = ['type', 'name_or_index', 'to_node'] - node_list = [0, 0, 0, 1, - 0, 1, 1, 0] - edge_list = [0, 2, 4] - strings = ['node1', 'node2', 'edge1'] - heap = self._HeapSnapshotData(node_types, edge_types, node_fields, - edge_fields, node_list, edge_list, strings) - objects = list(chrome_js_heap_snapshot_parser.ChromeJsHeapSnapshotParser( - json.dumps(heap)).GetAllLiveHeapObjects()) - self.assertEqual(2, len(objects)) - if objects[0].edges_from: - from_ix = 0 - to_ix = 1 - else: - from_ix = 1 - to_ix = 0 - self.assertEqual('node1', objects[from_ix].class_name) - self.assertEqual('node2', objects[to_ix].class_name) - self.assertEqual(1, len(objects[from_ix].edges_from)) - self.assertEqual(0, len(objects[from_ix].edges_to)) - self.assertEqual(0, len(objects[to_ix].edges_from)) - self.assertEqual(1, len(objects[to_ix].edges_to)) - self.assertEqual('node1', - objects[from_ix].edges_from[0].from_object.class_name) - self.assertEqual('node2', - objects[from_ix].edges_from[0].to_object.class_name) - self.assertEqual('edge1', objects[from_ix].edges_from[0].name_string) - self.assertEqual('node1', objects[to_ix].edges_to[0].from_object.class_name) - self.assertEqual('node2', objects[to_ix].edges_to[0].to_object.class_name) - self.assertEqual('edge1', objects[to_ix].edges_to[0].name_string)
diff --git a/tools/telemetry/telemetry/core/heap/live_heap_object.py b/tools/telemetry/telemetry/core/heap/live_heap_object.py deleted file mode 100644 index c8be3df..0000000 --- a/tools/telemetry/telemetry/core/heap/live_heap_object.py +++ /dev/null
@@ -1,57 +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 LiveHeapObject(object): - """Data structure for representing an object in the heap snapshot. - - Attributes: - object_id: int, identifier for the object. - type_string: str, describes the type of the node. - class_name: str, describes the class of the JavaScript object - represented by this LiveHeapObject. - edges_to: [RetainingEdge], edges whose end point this LiveHeapObject is. - edges_from: [RetainingEdge], edges whose start point this LiveHeapObject is. - string: str, for string LiveHeapObjects, contains the string the - LiveHeapObject represents. Empty string for LiveHeapObjects which are - not strings. - name: str, how to refer to this LiveHeapObject. - """ - - def __init__(self, object_id, type_string, class_name): - """Initializes the LiveHeapObject object. - - Args: - object_id: int, identifier for the LiveHeapObject. - type_string: str, the type of the node. - class_name: str, the class of the object this LiveHeapObject represents. - """ - self.object_id = object_id - self.type_string = type_string - self.class_name = class_name - self.edges_to = [] - self.edges_from = [] - self.string = '' - self.name = '' - - def AddEdgeTo(self, edge): - """Associates an Edge with the LiveHeapObject (the end point). - - Args: - edge: Edge, an edge whose end point this LiveHeapObject is. - """ - self.edges_to.append(edge) - - def AddEdgeFrom(self, edge): - """Associates an Edge with the LiveHeapObject (the start point). - - Args: - edge: Edge, an edge whose start point this LiveHeapObject is. - """ - self.edges_from.append(edge) - - def __str__(self): - prefix = 'LiveHeapObject(' + str(self.object_id) + ' ' - if self.type_string == 'object': - return prefix + self.class_name + ')' - return prefix + self.type_string + ')'
diff --git a/tools/telemetry/telemetry/core/heap/model.py b/tools/telemetry/telemetry/core/heap/model.py deleted file mode 100644 index 551716e6..0000000 --- a/tools/telemetry/telemetry/core/heap/model.py +++ /dev/null
@@ -1,22 +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. - -from telemetry.core.heap import chrome_js_heap_snapshot_parser - - -class Model(object): - """ The heap snapshot model is a set of LiveHeapObjects. The LiveHeapObjects - contain the RetainingEdge objects describing the relationships between the - LiveHeapObjects.""" - - def __init__(self, raw_data): - if not chrome_js_heap_snapshot_parser.ChromeJsHeapSnapshotParser.CanImport( - raw_data): - raise ValueError("Cannot import snapshot data") - parser = chrome_js_heap_snapshot_parser.ChromeJsHeapSnapshotParser(raw_data) - self._all_live_heap_objects = parser.GetAllLiveHeapObjects() - - @property - def all_live_heap_objects(self): - return self._all_live_heap_objects
diff --git a/tools/telemetry/telemetry/core/heap/retaining_edge.py b/tools/telemetry/telemetry/core/heap/retaining_edge.py deleted file mode 100644 index d6b9978c..0000000 --- a/tools/telemetry/telemetry/core/heap/retaining_edge.py +++ /dev/null
@@ -1,52 +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 RetainingEdge(object): - """Data structure for representing a retainer relationship between objects. - - Attributes: - from_object_id: int, id of the object which is the start point of this - RetainingEdge. Used when the corresponding LiveHeapObject object is not - yet contstructed. - to_object_id: int, id of the object which is the end point of this - RetainingEdge. Used when the corresponding LiveHeapObject object is not - yet contstructed. - from_object: LiveHeapObject, the start point of this RetainingEdge. - to_object: LiveHeapObject, the end point of this RetainingEdge. - type_string: str, the type of the RetainingEdge. - name_string: str, the JavaScript attribute name this RetainingEdge - represents. - """ - - def __init__(self, from_object_id, to_object_id, type_string, name_string): - """Initializes the RetainingEdge object. - - Args: - from_object_id: int, id of the object which is the start point of this - RetainingEdge. Used when the corresponding LiveHeapObject object is - not yet contstructed. - to_object_id: int, id of the object which is the end point of this - RetainingEdge. Used when the corresponding LiveHeapObject object is - not yet contstructed. - type_string: str, the type of the RetainingEdge. - name_string: str, the JavaScript attribute name this RetainingEdge - represents. - """ - self.from_object_id = from_object_id - self.to_object_id = to_object_id - self.from_object = {} - self.to_object = {} - self.type_string = type_string - self.name_string = name_string - - def SetFromObject(self, obj): - self.from_object = obj - return self - - def SetToObject(self, obj): - self.to_object = obj - return self - - def __str__(self): - return 'RetainingEdge(' + self.type_string + ' ' + self.name_string + ')'
diff --git a/tools/telemetry/telemetry/core/tab_unittest.py b/tools/telemetry/telemetry/core/tab_unittest.py index c8f1c3f..4540810 100644 --- a/tools/telemetry/telemetry/core/tab_unittest.py +++ b/tools/telemetry/telemetry/core/tab_unittest.py
@@ -164,6 +164,7 @@ # renderer_thread corresponding to it in the the trace. self.assertIs(None, timeline_model.GetRendererThreadFromTabId(third_tab.id)) + @decorators.Disabled('android') # https://crbug.com/463933 def testTabIsAlive(self): self.assertEquals(self._tab.url, 'about:blank') self.assertTrue(self._tab.IsAlive())
diff --git a/tools/telemetry/telemetry/core/web_contents.py b/tools/telemetry/telemetry/core/web_contents.py index 38232360..71a5c76 100644 --- a/tools/telemetry/telemetry/core/web_contents.py +++ b/tools/telemetry/telemetry/core/web_contents.py
@@ -174,9 +174,6 @@ def StopTimelineRecording(self): self._inspector_backend.StopTimelineRecording() - def TakeJSHeapSnapshot(self, timeout=120): - return self._inspector_backend.TakeJSHeapSnapshot(timeout) - def IsAlive(self): """Whether the WebContents is still operating normally.
diff --git a/tools/telemetry/telemetry/page/shared_page_state.py b/tools/telemetry/telemetry/page/shared_page_state.py index 4bf56ad..4a9c4d79 100644 --- a/tools/telemetry/telemetry/page/shared_page_state.py +++ b/tools/telemetry/telemetry/page/shared_page_state.py
@@ -240,11 +240,11 @@ self._PreparePage() self._ImplicitPageNavigation() self._test.RunPage(self._current_page, self._current_tab, results) - except exceptions.AppCrashException: + except exceptions.Error: if self._test.is_multi_tab_test: # Avoid trying to recover from an unknown multi-tab state. exception_formatter.PrintFormattedException( - msg='AppCrashException during multi tab test:') + msg='Telemetry Error during multi tab test:') raise page_test.MultiTabTestAppCrashError raise
diff --git a/tools/telemetry/telemetry/results/csv_pivot_table_output_formatter.py b/tools/telemetry/telemetry/results/csv_pivot_table_output_formatter.py index eb3a1223..c7f66fd3 100644 --- a/tools/telemetry/telemetry/results/csv_pivot_table_output_formatter.py +++ b/tools/telemetry/telemetry/results/csv_pivot_table_output_formatter.py
@@ -45,8 +45,8 @@ for run in page_test_results.all_page_runs: run_index = page_test_results.all_page_runs.index(run) page_dict = { - 'page': run.page.display_name, - 'page_set': run.page.page_set.Name(), + 'page': run.user_story.display_name, + 'page_set': run.user_story.page_set.Name(), 'run_index': run_index, } for value in run.values:
diff --git a/tools/telemetry/telemetry/results/gtest_progress_reporter.py b/tools/telemetry/telemetry/results/gtest_progress_reporter.py index 26b2d6c..87c03f74 100644 --- a/tools/telemetry/telemetry/results/gtest_progress_reporter.py +++ b/tools/telemetry/telemetry/results/gtest_progress_reporter.py
@@ -81,7 +81,7 @@ (len(page_test_results.failures), unit)) for failed_run in failed_runs: print >> self._output_stream, '[ FAILED ] %s' % ( - failed_run.page.display_name) + failed_run.user_story.display_name) print >> self._output_stream count = len(failed_runs) unit = 'TEST' if count == 1 else 'TESTS'
diff --git a/tools/telemetry/telemetry/results/json_output_formatter.py b/tools/telemetry/telemetry/results/json_output_formatter.py index db7b13b..7ef539d 100644 --- a/tools/telemetry/telemetry/results/json_output_formatter.py +++ b/tools/telemetry/telemetry/results/json_output_formatter.py
@@ -36,7 +36,7 @@ def _GetAllPages(page_test_results): - pages = set(page_run.page for page_run in + pages = set(page_run.user_story for page_run in page_test_results.all_page_runs) return pages
diff --git a/tools/telemetry/telemetry/results/page_run.py b/tools/telemetry/telemetry/results/page_run.py deleted file mode 100644 index 72bd4084..0000000 --- a/tools/telemetry/telemetry/results/page_run.py +++ /dev/null
@@ -1,51 +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. - -from telemetry.value import failure -from telemetry.value import skip - - -class PageRun(object): - def __init__(self, page): - self._page = page - self._values = [] - - def AddValue(self, value): - self._values.append(value) - - @property - def page(self): - return self._page - - @property - def values(self): - """The values that correspond to this page run.""" - return self._values - - @property - def ok(self): - """Whether the current run is still ok. - - To be precise: returns true if there is neither FailureValue nor - SkipValue in self.values. - """ - return not self.skipped and not self.failed - - @property - def skipped(self): - """Whether the current run is being skipped. - - To be precise: returns true if there is any SkipValue in self.values. - """ - return any(isinstance(v, skip.SkipValue) for v in self.values) - - @property - def failed(self): - """Whether the current run failed. - - To be precise: returns true if there is a FailureValue but not - SkipValue in self.values. - """ - return not self.skipped and any( - isinstance(v, failure.FailureValue) for v in self.values)
diff --git a/tools/telemetry/telemetry/results/page_run_unittest.py b/tools/telemetry/telemetry/results/page_run_unittest.py deleted file mode 100644 index 23ce506..0000000 --- a/tools/telemetry/telemetry/results/page_run_unittest.py +++ /dev/null
@@ -1,65 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import unittest - -from telemetry import page as page_module -from telemetry.page import page_set -from telemetry.results import page_run -from telemetry.value import failure -from telemetry.value import scalar -from telemetry.value import skip - - -class PageRunTest(unittest.TestCase): - def setUp(self): - self.page_set = page_set.PageSet(file_path=os.path.dirname(__file__)) - self.page_set.AddUserStory(page_module.Page( - 'http://www.bar.com/', self.page_set, self.page_set.base_dir)) - - @property - def pages(self): - return self.page_set.pages - - def testPageRunFailed(self): - run = page_run.PageRun(self.pages[0]) - run.AddValue(failure.FailureValue.FromMessage(self.pages[0], 'test')) - self.assertFalse(run.ok) - self.assertTrue(run.failed) - self.assertFalse(run.skipped) - - run = page_run.PageRun(self.pages[0]) - run.AddValue(scalar.ScalarValue(self.pages[0], 'a', 's', 1)) - run.AddValue(failure.FailureValue.FromMessage(self.pages[0], 'test')) - self.assertFalse(run.ok) - self.assertTrue(run.failed) - self.assertFalse(run.skipped) - - def testPageRunSkipped(self): - run = page_run.PageRun(self.pages[0]) - run.AddValue(failure.FailureValue.FromMessage(self.pages[0], 'test')) - run.AddValue(skip.SkipValue(self.pages[0], 'test')) - self.assertFalse(run.ok) - self.assertFalse(run.failed) - self.assertTrue(run.skipped) - - run = page_run.PageRun(self.pages[0]) - run.AddValue(scalar.ScalarValue(self.pages[0], 'a', 's', 1)) - run.AddValue(skip.SkipValue(self.pages[0], 'test')) - self.assertFalse(run.ok) - self.assertFalse(run.failed) - self.assertTrue(run.skipped) - - def testPageRunSucceeded(self): - run = page_run.PageRun(self.pages[0]) - self.assertTrue(run.ok) - self.assertFalse(run.failed) - self.assertFalse(run.skipped) - - run = page_run.PageRun(self.pages[0]) - run.AddValue(scalar.ScalarValue(self.pages[0], 'a', 's', 1)) - self.assertTrue(run.ok) - self.assertFalse(run.failed) - self.assertFalse(run.skipped)
diff --git a/tools/telemetry/telemetry/results/page_test_results.py b/tools/telemetry/telemetry/results/page_test_results.py index 819684f..38b62e4 100644 --- a/tools/telemetry/telemetry/results/page_test_results.py +++ b/tools/telemetry/telemetry/results/page_test_results.py
@@ -12,8 +12,8 @@ import traceback from telemetry import value as value_module -from telemetry.results import page_run from telemetry.results import progress_reporter as progress_reporter_module +from telemetry.results import user_story_run from telemetry.util import cloud_storage from telemetry.value import failure from telemetry.value import skip @@ -23,7 +23,7 @@ class PageTestResults(object): def __init__(self, output_stream=None, output_formatters=None, progress_reporter=None, trace_tag='', output_dir=None, - value_can_be_added_predicate=lambda v: True): + value_can_be_added_predicate=lambda v, is_first: True): """ Args: output_stream: The output stream to use to write test results. @@ -36,9 +36,10 @@ used for buildbot. output_dir: A string specified the directory where to store the test artifacts, e.g: trace, videos,... - value_can_be_added_predicate: A function that takes an value.Value - instance as input. It returns True if the value can be added to the - test results and False otherwise. + value_can_be_added_predicate: A function that takes two arguments: + a value.Value instance and a boolean (True when the value is part + of the first result for the user story). It returns True if the value + can be added to the test results and False otherwise. """ # TODO(chrishenry): Figure out if trace_tag is still necessary. @@ -55,6 +56,7 @@ self._current_page_run = None self._all_page_runs = [] + self._all_user_stories = set() self._representative_value_for_each_value_name = {} self._all_summary_values = [] self._serialized_trace_file_ids_to_paths = {} @@ -94,7 +96,7 @@ @property def current_page(self): assert self._current_page_run, 'Not currently running test.' - return self._current_page_run.page + return self._current_page_run.user_story @property def current_page_run(self): @@ -108,7 +110,7 @@ @property def pages_that_succeeded(self): """Returns the set of pages that succeeded.""" - pages = set(run.page for run in self.all_page_runs) + pages = set(run.user_story for run in self.all_page_runs) pages.difference_update(self.pages_that_failed) return pages @@ -118,7 +120,7 @@ failed_pages = set() for run in self.all_page_runs: if run.failed: - failed_pages.add(run.page) + failed_pages.add(run.user_story) return failed_pages @property @@ -150,26 +152,26 @@ def WillRunPage(self, page): assert not self._current_page_run, 'Did not call DidRunPage.' - self._current_page_run = page_run.PageRun(page) + self._current_page_run = user_story_run.UserStoryRun(page) self._progress_reporter.WillRunPage(self) - def DidRunPage(self, page, discard_run=False): # pylint: disable=W0613 + def DidRunPage(self, page): # pylint: disable=W0613 """ Args: page: The current page under test. - discard_run: Whether to discard the entire run and all of its - associated results. """ assert self._current_page_run, 'Did not call WillRunPage.' self._progress_reporter.DidRunPage(self) - if not discard_run: - self._all_page_runs.append(self._current_page_run) + self._all_page_runs.append(self._current_page_run) + self._all_user_stories.add(self._current_page_run.user_story) self._current_page_run = None def AddValue(self, value): assert self._current_page_run, 'Not currently running test.' self._ValidateValue(value) - if not self._value_can_be_added_predicate(value): + is_first_result = ( + self._current_page_run.user_story not in self._all_user_stories) + if not self._value_can_be_added_predicate(value, is_first_result): return # TODO(eakuefner/chrishenry): Add only one skip per pagerun assert here self._current_page_run.AddValue(value)
diff --git a/tools/telemetry/telemetry/results/page_test_results_unittest.py b/tools/telemetry/telemetry/results/page_test_results_unittest.py index 21006a1..e172ccee4 100644 --- a/tools/telemetry/telemetry/results/page_test_results_unittest.py +++ b/tools/telemetry/telemetry/results/page_test_results_unittest.py
@@ -3,6 +3,7 @@ # found in the LICENSE file. import os +import unittest from telemetry import page as page_module from telemetry.page import page_set @@ -44,7 +45,6 @@ self.assertTrue(results.all_page_runs[0].failed) self.assertTrue(results.all_page_runs[1].ok) - def testSkips(self): results = page_test_results.PageTestResults() results.WillRunPage(self.pages[0]) @@ -55,7 +55,7 @@ results.DidRunPage(self.pages[1]) self.assertTrue(results.all_page_runs[0].skipped) - self.assertEqual(self.pages[0], results.all_page_runs[0].page) + self.assertEqual(self.pages[0], results.all_page_runs[0].user_story) self.assertEqual(set([self.pages[0], self.pages[1]]), results.pages_that_succeeded) @@ -84,38 +84,6 @@ values = results.FindAllPageSpecificValuesNamed('a') assert len(values) == 2 - def testResultsFiltering(self): - def AcceptValueNamed_a(value): - return value.name == 'a' - results = page_test_results.PageTestResults( - value_can_be_added_predicate=AcceptValueNamed_a) - results.WillRunPage(self.pages[0]) - results.AddValue(scalar.ScalarValue(self.pages[0], 'a', 'seconds', 3)) - results.AddValue(scalar.ScalarValue(self.pages[0], 'b', 'seconds', 3)) - results.DidRunPage(self.pages[0]) - - results.WillRunPage(self.pages[1]) - results.AddValue(scalar.ScalarValue(self.pages[1], 'a', 'seconds', 3)) - results.AddValue(scalar.ScalarValue(self.pages[1], 'd', 'seconds', 3)) - results.DidRunPage(self.pages[1]) - - results.PrintSummary() - - values = results.FindPageSpecificValuesForPage(self.pages[0], 'a') - self.assertEquals(1, len(values)) - v = values[0] - self.assertEquals(v.name, 'a') - self.assertEquals(v.page, self.pages[0]) - - values = results.FindPageSpecificValuesForPage(self.pages[0], 'b') - self.assertEquals(0, len(values)) - - values = results.FindAllPageSpecificValuesNamed('a') - self.assertEquals(len(values), 2) - - values = results.all_page_specific_values - self.assertEquals(len(values), 2) - def testUrlIsInvalidValue(self): results = page_test_results.PageTestResults() results.WillRunPage(self.pages[0]) @@ -266,3 +234,69 @@ results.CleanUp() self.assertFalse(results.FindAllTraceValues()) + + +class PageTestResultsFilterTest(unittest.TestCase): + def setUp(self): + ps = page_set.PageSet(file_path=os.path.dirname(__file__)) + ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir)) + ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir)) + self.page_set = ps + + @property + def pages(self): + return self.page_set.pages + + def testFilterValue(self): + def AcceptValueNamed_a(value, _): + return value.name == 'a' + results = page_test_results.PageTestResults( + value_can_be_added_predicate=AcceptValueNamed_a) + results.WillRunPage(self.pages[0]) + results.AddValue(scalar.ScalarValue(self.pages[0], 'a', 'seconds', 3)) + results.AddValue(scalar.ScalarValue(self.pages[0], 'b', 'seconds', 3)) + results.DidRunPage(self.pages[0]) + + results.WillRunPage(self.pages[1]) + results.AddValue(scalar.ScalarValue(self.pages[1], 'a', 'seconds', 3)) + results.AddValue(scalar.ScalarValue(self.pages[1], 'd', 'seconds', 3)) + results.DidRunPage(self.pages[1]) + results.PrintSummary() + self.assertEquals( + [('a', 'http://www.foo.com/'), ('a', 'http://www.bar.com/')], + [(v.name, v.page.url) for v in results.all_page_specific_values]) + + def testFilterIsFirstResult(self): + def AcceptSecondValues(_, is_first_result): + return not is_first_result + results = page_test_results.PageTestResults( + value_can_be_added_predicate=AcceptSecondValues) + + # First results (filtered out) + results.WillRunPage(self.pages[0]) + results.AddValue(scalar.ScalarValue(self.pages[0], 'a', 'seconds', 7)) + results.AddValue(scalar.ScalarValue(self.pages[0], 'b', 'seconds', 8)) + results.DidRunPage(self.pages[0]) + results.WillRunPage(self.pages[1]) + results.AddValue(scalar.ScalarValue(self.pages[1], 'a', 'seconds', 5)) + results.AddValue(scalar.ScalarValue(self.pages[1], 'd', 'seconds', 6)) + results.DidRunPage(self.pages[1]) + + # Second results + results.WillRunPage(self.pages[0]) + results.AddValue(scalar.ScalarValue(self.pages[0], 'a', 'seconds', 3)) + results.AddValue(scalar.ScalarValue(self.pages[0], 'b', 'seconds', 4)) + results.DidRunPage(self.pages[0]) + results.WillRunPage(self.pages[1]) + results.AddValue(scalar.ScalarValue(self.pages[1], 'a', 'seconds', 1)) + results.AddValue(scalar.ScalarValue(self.pages[1], 'd', 'seconds', 2)) + results.DidRunPage(self.pages[1]) + results.PrintSummary() + expected_values = [ + ('a', 'http://www.foo.com/', 3), + ('b', 'http://www.foo.com/', 4), + ('a', 'http://www.bar.com/', 1), + ('d', 'http://www.bar.com/', 2)] + actual_values = [(v.name, v.page.url, v.value) + for v in results.all_page_specific_values] + self.assertEquals(expected_values, actual_values)
diff --git a/tools/telemetry/telemetry/results/results_options.py b/tools/telemetry/telemetry/results/results_options.py index 461d074..5b70ad7 100644 --- a/tools/telemetry/telemetry/results/results_options.py +++ b/tools/telemetry/telemetry/results/results_options.py
@@ -108,7 +108,7 @@ def CreateResults(benchmark_metadata, options, - value_can_be_added_predicate=lambda v: True): + value_can_be_added_predicate=lambda v, is_first: True): """ Args: options: Contains the options specified in AddResultsOptions.
diff --git a/tools/telemetry/telemetry/results/user_story_run.py b/tools/telemetry/telemetry/results/user_story_run.py new file mode 100644 index 0000000..eafa1d3f --- /dev/null +++ b/tools/telemetry/telemetry/results/user_story_run.py
@@ -0,0 +1,51 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from telemetry.value import failure +from telemetry.value import skip + + +class UserStoryRun(object): + def __init__(self, user_story): + self._user_story = user_story + self._values = [] + + def AddValue(self, value): + self._values.append(value) + + @property + def user_story(self): + return self._user_story + + @property + def values(self): + """The values that correspond to this user_story run.""" + return self._values + + @property + def ok(self): + """Whether the current run is still ok. + + To be precise: returns true if there is neither FailureValue nor + SkipValue in self.values. + """ + return not self.skipped and not self.failed + + @property + def skipped(self): + """Whether the current run is being skipped. + + To be precise: returns true if there is any SkipValue in self.values. + """ + return any(isinstance(v, skip.SkipValue) for v in self.values) + + @property + def failed(self): + """Whether the current run failed. + + To be precise: returns true if there is a FailureValue but not + SkipValue in self.values. + """ + return not self.skipped and any( + isinstance(v, failure.FailureValue) for v in self.values)
diff --git a/tools/telemetry/telemetry/results/user_story_run_unittest.py b/tools/telemetry/telemetry/results/user_story_run_unittest.py new file mode 100644 index 0000000..4aa3cf6 --- /dev/null +++ b/tools/telemetry/telemetry/results/user_story_run_unittest.py
@@ -0,0 +1,74 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import unittest + +from telemetry import user_story as user_story_module +from telemetry.results import user_story_run +from telemetry.user_story import shared_user_story_state +from telemetry.user_story import user_story_set +from telemetry.value import failure +from telemetry.value import scalar +from telemetry.value import skip + + +# pylint: disable=abstract-method +class SharedUserStoryStateBar(shared_user_story_state.SharedUserStoryState): + pass + +class UserStoryFoo(user_story_module.UserStory): + def __init__(self, name='', labels=None): + super(UserStoryFoo, self).__init__( + SharedUserStoryStateBar, name, labels) + +class UserStoryRunTest(unittest.TestCase): + def setUp(self): + self.user_story_set = user_story_set.UserStorySet() + self.user_story_set.AddUserStory(UserStoryFoo()) + + @property + def user_stories(self): + return self.user_story_set.user_stories + + def testUserStoryRunFailed(self): + run = user_story_run.UserStoryRun(self.user_stories[0]) + run.AddValue(failure.FailureValue.FromMessage(self.user_stories[0], 'test')) + self.assertFalse(run.ok) + self.assertTrue(run.failed) + self.assertFalse(run.skipped) + + run = user_story_run.UserStoryRun(self.user_stories[0]) + run.AddValue(scalar.ScalarValue(self.user_stories[0], 'a', 's', 1)) + run.AddValue(failure.FailureValue.FromMessage(self.user_stories[0], 'test')) + self.assertFalse(run.ok) + self.assertTrue(run.failed) + self.assertFalse(run.skipped) + + def testUserStoryRunSkipped(self): + run = user_story_run.UserStoryRun(self.user_stories[0]) + run.AddValue(failure.FailureValue.FromMessage(self.user_stories[0], 'test')) + run.AddValue(skip.SkipValue(self.user_stories[0], 'test')) + self.assertFalse(run.ok) + self.assertFalse(run.failed) + self.assertTrue(run.skipped) + + run = user_story_run.UserStoryRun(self.user_stories[0]) + run.AddValue(scalar.ScalarValue(self.user_stories[0], 'a', 's', 1)) + run.AddValue(skip.SkipValue(self.user_stories[0], 'test')) + self.assertFalse(run.ok) + self.assertFalse(run.failed) + self.assertTrue(run.skipped) + + def testUserStoryRunSucceeded(self): + run = user_story_run.UserStoryRun(self.user_stories[0]) + self.assertTrue(run.ok) + self.assertFalse(run.failed) + self.assertFalse(run.skipped) + + run = user_story_run.UserStoryRun(self.user_stories[0]) + run.AddValue(scalar.ScalarValue(self.user_stories[0], 'a', 's', 1)) + self.assertTrue(run.ok) + self.assertFalse(run.failed) + self.assertFalse(run.skipped)
diff --git a/tools/telemetry/telemetry/unittest_util/run_tests.py b/tools/telemetry/telemetry/unittest_util/run_tests.py index 8539e5d3..b4f6b8db 100644 --- a/tools/telemetry/telemetry/unittest_util/run_tests.py +++ b/tools/telemetry/telemetry/unittest_util/run_tests.py
@@ -141,16 +141,9 @@ def GetClassifier(args, possible_browser): def ClassifyTest(test_set, test): name = test.id() - if args.positional_args: - if _MatchesSelectedTest(name, args.positional_args, - args.exact_test_filter): - assert hasattr(test, '_testMethodName') - method = getattr(test, test._testMethodName) # pylint: disable=W0212 - if decorators.ShouldBeIsolated(method, possible_browser): - test_set.isolated_tests.append(typ.TestInput(name)) - else: - test_set.parallel_tests.append(typ.TestInput(name)) - else: + if (not args.positional_args + or _MatchesSelectedTest(name, args.positional_args, + args.exact_test_filter)): assert hasattr(test, '_testMethodName') method = getattr(test, test._testMethodName) # pylint: disable=W0212 should_skip, reason = decorators.ShouldSkip(method, possible_browser)
diff --git a/tools/telemetry/telemetry/user_story/user_story_runner.py b/tools/telemetry/telemetry/user_story/user_story_runner.py index 1bb6b95..24255fc 100644 --- a/tools/telemetry/telemetry/user_story/user_story_runner.py +++ b/tools/telemetry/telemetry/user_story/user_story_runner.py
@@ -89,7 +89,7 @@ except (page_test.Failure, exceptions.TimeoutException, exceptions.LoginException, exceptions.ProfilingException): ProcessError() - except exceptions.AppCrashException: + except exceptions.Error: ProcessError() raise except page_action.PageActionNotSupported as e: @@ -218,7 +218,6 @@ user_story_groups = GetUserStoryGroupsWithSameSharedUserStoryClass( user_stories) - user_story_with_discarded_first_results = set() for group in user_story_groups: state = None @@ -234,13 +233,13 @@ _WaitForThermalThrottlingIfNeeded(state.platform) _RunUserStoryAndProcessErrorIfNeeded( expectations, user_story, results, state) - except exceptions.AppCrashException: - # Catch AppCrashException to give the story a chance to retry. + except exceptions.Error: + # Catch all Telemetry errors to give the story a chance to retry. # The retry is enabled by tearing down the state and creating # a new state instance in the next iteration. try: # If TearDownState raises, do not catch the exception. - # (The AppCrashException was saved as a failure value.) + # (The Error was saved as a failure value.) state.TearDownState(results) finally: # Later finally-blocks use state, so ensure it is cleared. @@ -250,14 +249,7 @@ try: if state: _CheckThermalThrottling(state.platform) - # TODO(slamm): Make discard_first_result part of user_story API. - # https://crbug.com/440101 - discard_current_run = ( - getattr(test, 'discard_first_result', False) and - user_story not in user_story_with_discarded_first_results) - if discard_current_run: - user_story_with_discarded_first_results.add(user_story) - results.DidRunPage(user_story, discard_run=discard_current_run) + results.DidRunPage(user_story) except Exception: if not has_existing_exception: raise
diff --git a/tools/telemetry/telemetry/user_story/user_story_runner_unittest.py b/tools/telemetry/telemetry/user_story/user_story_runner_unittest.py index 6c5b8a6..7136fd1 100644 --- a/tools/telemetry/telemetry/user_story/user_story_runner_unittest.py +++ b/tools/telemetry/telemetry/user_story/user_story_runner_unittest.py
@@ -355,61 +355,6 @@ # The AppCrashException gets added as a failure. self.assertEquals(1, len(self.results.failures)) - def testDiscardFirstResult(self): - us = user_story_set.UserStorySet() - us.AddUserStory(DummyLocalUserStory(TestSharedPageState)) - us.AddUserStory(DummyLocalUserStory(TestSharedPageState)) - class Measurement(page_test.PageTest): - @property - def discard_first_result(self): - return True - - def RunPage(self, page, _, results): - results.AddValue(string.StringValue(page, 'test', 't', page.name)) - - def ValidateAndMeasurePage(self, page, tab, results): - pass - - results = results_options.CreateResults( - EmptyMetadataForTest(), self.options) - user_story_runner.Run( - Measurement(), us, self.expectations, self.options, results) - - self.assertEquals(0, GetNumberOfSuccessfulPageRuns(results)) - self.assertEquals(0, len(results.failures)) - self.assertEquals(0, len(results.all_page_specific_values)) - - - results = results_options.CreateResults( - EmptyMetadataForTest(), self.options) - self.options.page_repeat = 1 - self.options.pageset_repeat = 2 - user_story_runner.Run( - Measurement(), us, self.expectations, self.options, results) - self.assertEquals(2, GetNumberOfSuccessfulPageRuns(results)) - self.assertEquals(0, len(results.failures)) - self.assertEquals(2, len(results.all_page_specific_values)) - - results = results_options.CreateResults( - EmptyMetadataForTest(), self.options) - self.options.page_repeat = 2 - self.options.pageset_repeat = 1 - user_story_runner.Run( - Measurement(), us, self.expectations, self.options, results) - self.assertEquals(2, GetNumberOfSuccessfulPageRuns(results)) - self.assertEquals(0, len(results.failures)) - self.assertEquals(2, len(results.all_page_specific_values)) - - results = results_options.CreateResults( - EmptyMetadataForTest(), self.options) - self.options.page_repeat = 1 - self.options.pageset_repeat = 1 - user_story_runner.Run( - Measurement(), us, self.expectations, self.options, results) - self.assertEquals(0, GetNumberOfSuccessfulPageRuns(results)) - self.assertEquals(0, len(results.failures)) - self.assertEquals(0, len(results.all_page_specific_values)) - def testPagesetRepeat(self): us = user_story_set.UserStorySet() us.AddUserStory(DummyLocalUserStory(TestSharedPageState, name='blank'))
diff --git a/tools/telemetry/telemetry/value/__init__.py b/tools/telemetry/telemetry/value/__init__.py index d381998..474a9b4e 100644 --- a/tools/telemetry/telemetry/value/__init__.py +++ b/tools/telemetry/telemetry/value/__init__.py
@@ -42,7 +42,8 @@ class Value(object): """An abstract value produced by a telemetry page test. """ - def __init__(self, page, name, units, important, description): + def __init__(self, page, name, units, important, description, + interaction_record): """A generic Value object. Args: @@ -56,6 +57,8 @@ by default in downstream UIs. description: A string explaining in human-understandable terms what this value represents. + interaction_record: The string label of the TimelineInteractionRecord with + which this value is associated. """ # TODO(eakuefner): Check user story here after migration (crbug.com/442036) if not isinstance(name, basestring): @@ -66,17 +69,23 @@ raise ValueError('important field of Value must be bool.') if not ((description is None) or isinstance(description, basestring)): raise ValueError('description field of Value must absent or string.') + if not ((interaction_record is None) or + isinstance(interaction_record, basestring)): + raise ValueError('interaction_record field of Value must absent or ' + 'string.') self.page = page self.name = name self.units = units self.important = important self.description = description + self.interaction_record = interaction_record def IsMergableWith(self, that): return (self.units == that.units and type(self) == type(that) and - self.important == that.important) + self.important == that.important and + self.interaction_record == that.interaction_record) @classmethod def MergeLikeValuesFromSamePage(cls, values): @@ -196,6 +205,9 @@ if self.description: d['description'] = self.description + if self.interaction_record: + d['interaction_record'] = self.interaction_record + if self.page: d['page_id'] = self.page.id @@ -282,6 +294,12 @@ d['important'] = False + interaction_record = value_dict.get('interaction_record', None) + if interaction_record: + d['interaction_record'] = interaction_record + else: + d['interaction_record'] = None + return d def ValueNameFromTraceAndChartName(trace_name, chart_name=None):
diff --git a/tools/telemetry/telemetry/value/failure.py b/tools/telemetry/telemetry/value/failure.py index 3b51b61..aa07424 100644 --- a/tools/telemetry/telemetry/value/failure.py +++ b/tools/telemetry/telemetry/value/failure.py
@@ -10,7 +10,7 @@ class FailureValue(value_module.Value): - def __init__(self, page, exc_info, description=None): + def __init__(self, page, exc_info, description=None, interaction_record=None): """A value representing a failure when running the page. Args: @@ -19,7 +19,8 @@ this failure. """ exc_type = exc_info[0].__name__ - super(FailureValue, self).__init__(page, exc_type, '', True, description) + super(FailureValue, self).__init__(page, exc_type, '', True, description, + interaction_record) self._exc_info = exc_info @classmethod @@ -81,8 +82,7 @@ kwargs = value_module.Value.GetConstructorKwArgs(value_dict, page_dict) del kwargs['name'] del kwargs['units'] - important = kwargs.get('important', None) - if important != None: + if 'important' in kwargs: del kwargs['important'] kwargs['exc_info'] = FailureValue._GetExcInfoFromMessage( value_dict['value'])
diff --git a/tools/telemetry/telemetry/value/histogram.py b/tools/telemetry/telemetry/value/histogram.py index 877e135..6f5d4067 100644 --- a/tools/telemetry/telemetry/value/histogram.py +++ b/tools/telemetry/telemetry/value/histogram.py
@@ -29,9 +29,9 @@ class HistogramValue(value_module.Value): def __init__(self, page, name, units, raw_value=None, raw_value_json=None, important=True, - description=None): + description=None, interaction_record=None): super(HistogramValue, self).__init__(page, name, units, important, - description) + description, interaction_record) if raw_value_json: assert raw_value == None, \ 'Don\'t specify both raw_value and raw_value_json' @@ -52,12 +52,13 @@ else: page_name = None return ('HistogramValue(%s, %s, %s, raw_json_string="%s", ' - 'important=%s, description=%s') % ( - page_name, - self.name, self.units, - self.ToJSONString(), - self.important, - self.description) + 'important=%s, description=%s, interaction_record=%s') % ( + page_name, + self.name, self.units, + self.ToJSONString(), + self.important, + self.description, + self.interaction_record) def GetBuildbotDataType(self, output_context): if self._IsImportantGivenOutputIntent(output_context): @@ -103,6 +104,9 @@ kwargs = value_module.Value.GetConstructorKwArgs(value_dict, page_dict) kwargs['raw_value'] = value_dict + if 'interaction_record' in value_dict: + kwargs['interaction_record'] = value_dict['interaction_record'] + return HistogramValue(**kwargs) @classmethod @@ -113,7 +117,7 @@ v0.page, v0.name, v0.units, raw_value_json=histogram_util.AddHistograms( [v.ToJSONString() for v in values]), - important=v0.important) + important=v0.important, interaction_record=v0.interaction_record) @classmethod def MergeLikeValuesFromDifferentPages(cls, values,
diff --git a/tools/telemetry/telemetry/value/list_of_scalar_values.py b/tools/telemetry/telemetry/value/list_of_scalar_values.py index 698957a..297ddbf 100644 --- a/tools/telemetry/telemetry/value/list_of_scalar_values.py +++ b/tools/telemetry/telemetry/value/list_of_scalar_values.py
@@ -14,10 +14,11 @@ class ListOfScalarValues(value_module.Value): def __init__(self, page, name, units, values, - important=True, description=None, none_value_reason=None, + important=True, description=None, + interaction_record=None, none_value_reason=None, same_page_merge_policy=value_module.CONCATENATE): super(ListOfScalarValues, self).__init__(page, name, units, important, - description) + description, interaction_record) if values is not None: assert isinstance(values, list) assert len(values) > 0 @@ -37,13 +38,15 @@ else: merge_policy = 'PICK_FIRST' return ('ListOfScalarValues(%s, %s, %s, %s, ' - 'important=%s, description=%s, same_page_merge_policy=%s)') % ( + 'important=%s, description=%s, interaction_record=%s, ' + 'same_page_merge_policy=%s)') % ( page_name, self.name, self.units, repr(self.values), self.important, self.description, + self.interaction_record, merge_policy) def GetBuildbotDataType(self, output_context): @@ -84,6 +87,8 @@ if 'none_value_reason' in value_dict: kwargs['none_value_reason'] = value_dict['none_value_reason'] + if 'interaction_record' in value_dict: + kwargs['interaction_record'] = value_dict['interaction_record'] return ListOfScalarValues(**kwargs) @@ -101,7 +106,7 @@ none_value_reason=v0.none_value_reason) assert v0.same_page_merge_policy == value_module.CONCATENATE - return cls._MergeLikeValues(values, v0.page, v0.name) + return cls._MergeLikeValues(values, v0.page, v0.name, v0.interaction_record) @classmethod def MergeLikeValuesFromDifferentPages(cls, values, @@ -109,10 +114,10 @@ assert len(values) > 0 v0 = values[0] name = v0.name_suffix if group_by_name_suffix else v0.name - return cls._MergeLikeValues(values, None, name) + return cls._MergeLikeValues(values, None, name, v0.interaction_record) @classmethod - def _MergeLikeValues(cls, values, page, name): + def _MergeLikeValues(cls, values, page, name, interaction_record): v0 = values[0] merged_values = [] none_value_reason = None @@ -126,5 +131,6 @@ page, name, v0.units, merged_values, important=v0.important, + interaction_record=interaction_record, same_page_merge_policy=v0.same_page_merge_policy, none_value_reason=none_value_reason)
diff --git a/tools/telemetry/telemetry/value/list_of_string_values.py b/tools/telemetry/telemetry/value/list_of_string_values.py index 4f3604a..d69f31a 100644 --- a/tools/telemetry/telemetry/value/list_of_string_values.py +++ b/tools/telemetry/telemetry/value/list_of_string_values.py
@@ -8,10 +8,11 @@ class ListOfStringValues(value_module.Value): def __init__(self, page, name, units, values, - important=True, description=None, none_value_reason=None, + important=True, description=None, + interaction_record=None, none_value_reason=None, same_page_merge_policy=value_module.CONCATENATE): super(ListOfStringValues, self).__init__(page, name, units, important, - description) + description, interaction_record) if values is not None: assert isinstance(values, list) assert len(values) > 0 @@ -30,15 +31,17 @@ merge_policy = 'CONCATENATE' else: merge_policy = 'PICK_FIRST' - return ('ListOfStringValues(%s, %s, %s, %s, ' + - 'important=%s, description=%s, same_page_merge_policy=%s)') % ( - page_name, - self.name, - self.units, - repr(self.values), - self.important, - self.description, - merge_policy) + return ('ListOfStringValues(%s, %s, %s, %s, ' + 'important=%s, description=%s, interaction_record=%s, ' + 'same_page_merge_policy=%s)') % ( + page_name, + self.name, + self.units, + repr(self.values), + self.important, + self.description, + self.interaction_record, + merge_policy) def GetBuildbotDataType(self, output_context): if self._IsImportantGivenOutputIntent(output_context): @@ -78,6 +81,8 @@ if 'none_value_reason' in value_dict: kwargs['none_value_reason'] = value_dict['none_value_reason'] + if 'interaction_record' in value_dict: + kwargs['interaction_record'] = value_dict['interaction_record'] return ListOfStringValues(**kwargs) @@ -95,7 +100,7 @@ none_value_reason=v0.none_value_reason) assert v0.same_page_merge_policy == value_module.CONCATENATE - return cls._MergeLikeValues(values, v0.page, v0.name) + return cls._MergeLikeValues(values, v0.page, v0.name, v0.interaction_record) @classmethod def MergeLikeValuesFromDifferentPages(cls, values, @@ -103,10 +108,10 @@ assert len(values) > 0 v0 = values[0] name = v0.name_suffix if group_by_name_suffix else v0.name - return cls._MergeLikeValues(values, None, name) + return cls._MergeLikeValues(values, None, name, v0.interaction_record) @classmethod - def _MergeLikeValues(cls, values, page, name): + def _MergeLikeValues(cls, values, page, name, interaction_record): v0 = values[0] merged_values = [] none_value_reason = None @@ -120,5 +125,6 @@ page, name, v0.units, merged_values, important=v0.important, + interaction_record=interaction_record, same_page_merge_policy=v0.same_page_merge_policy, none_value_reason=none_value_reason)
diff --git a/tools/telemetry/telemetry/value/merge_values_unittest.py b/tools/telemetry/telemetry/value/merge_values_unittest.py index 4633efc7..698c3b1 100644 --- a/tools/telemetry/telemetry/value/merge_values_unittest.py +++ b/tools/telemetry/telemetry/value/merge_values_unittest.py
@@ -60,6 +60,18 @@ self.assertEquals(all_values[0].name, merged_values[0].name) self.assertEquals(all_values[0].units, merged_values[0].units) + def testSamePageMergeWithInteractionRecord(self): + page0 = self.pages[0] + + all_values = [scalar.ScalarValue(page0, 'foo-x', 'units', 1, + interaction_record='foo'), + scalar.ScalarValue(page0, 'foo-x', 'units', 4, + interaction_record='foo')] + + merged_values = merge_values.MergeLikeValuesFromSamePage(all_values) + self.assertEquals(1, len(merged_values)) + self.assertEquals('foo', merged_values[0].interaction_record) + def testDifferentPageMergeBasic(self): page0 = self.pages[0] page1 = self.pages[1]
diff --git a/tools/telemetry/telemetry/value/scalar.py b/tools/telemetry/telemetry/value/scalar.py index d83753a..be4f7f8 100644 --- a/tools/telemetry/telemetry/value/scalar.py +++ b/tools/telemetry/telemetry/value/scalar.py
@@ -11,14 +11,16 @@ class ScalarValue(value_module.Value): def __init__(self, page, name, units, value, important=True, - description=None, none_value_reason=None): + description=None, interaction_record=None, + none_value_reason=None): """A single value (float or integer) result from a test. A test that counts the number of DOM elements in a page might produce a scalar value: ScalarValue(page, 'num_dom_elements', 'count', num_elements) """ - super(ScalarValue, self).__init__(page, name, units, important, description) + super(ScalarValue, self).__init__(page, name, units, important, description, + interaction_record) assert value is None or isinstance(value, numbers.Number) none_values.ValidateNoneValueReason(value, none_value_reason) self.value = value @@ -29,13 +31,15 @@ page_name = self.page.url else: page_name = None - return 'ScalarValue(%s, %s, %s, %s, important=%s, description=%s)' % ( - page_name, - self.name, - self.units, - self.value, - self.important, - self.description) + return ('ScalarValue(%s, %s, %s, %s, important=%s, description=%s, ' + 'interaction_record=%s') % ( + page_name, + self.name, + self.units, + self.value, + self.important, + self.description, + self.interaction_record) def GetBuildbotDataType(self, output_context): if self._IsImportantGivenOutputIntent(output_context): @@ -73,6 +77,8 @@ if 'none_value_reason' in value_dict: kwargs['none_value_reason'] = value_dict['none_value_reason'] + if 'interaction_record' in value_dict: + kwargs['interaction_record'] = value_dict['interaction_record'] return ScalarValue(**kwargs) @@ -80,7 +86,7 @@ def MergeLikeValuesFromSamePage(cls, values): assert len(values) > 0 v0 = values[0] - return cls._MergeLikeValues(values, v0.page, v0.name) + return cls._MergeLikeValues(values, v0.page, v0.name, v0.interaction_record) @classmethod def MergeLikeValuesFromDifferentPages(cls, values, @@ -88,10 +94,10 @@ assert len(values) > 0 v0 = values[0] name = v0.name_suffix if group_by_name_suffix else v0.name - return cls._MergeLikeValues(values, None, name) + return cls._MergeLikeValues(values, None, name, v0.interaction_record) @classmethod - def _MergeLikeValues(cls, values, page, name): + def _MergeLikeValues(cls, values, page, name, interaction_record): v0 = values[0] merged_value = [v.value for v in values] none_value_reason = None @@ -100,4 +106,5 @@ none_value_reason = none_values.MERGE_FAILURE_REASON return list_of_scalar_values.ListOfScalarValues( page, name, v0.units, merged_value, important=v0.important, + interaction_record=interaction_record, none_value_reason=none_value_reason)
diff --git a/tools/telemetry/telemetry/value/skip.py b/tools/telemetry/telemetry/value/skip.py index 2b03725..eb86af0b 100644 --- a/tools/telemetry/telemetry/value/skip.py +++ b/tools/telemetry/telemetry/value/skip.py
@@ -14,7 +14,7 @@ page: The skipped page object. reason: The string reason the page was skipped. """ - super(SkipValue, self).__init__(page, 'skip', '', True, description) + super(SkipValue, self).__init__(page, 'skip', '', True, description, None) self._reason = reason def __repr__(self): @@ -54,10 +54,11 @@ kwargs = value_module.Value.GetConstructorKwArgs(value_dict, page_dict) del kwargs['name'] del kwargs['units'] - important = kwargs.get('important', None) - if important != None: + if 'important' in kwargs: del kwargs['important'] kwargs['reason'] = value_dict['reason'] + if 'interaction_record' in kwargs: + del kwargs['interaction_record'] return SkipValue(**kwargs)
diff --git a/tools/telemetry/telemetry/value/string.py b/tools/telemetry/telemetry/value/string.py index b1cb6ff..d9e21c6 100644 --- a/tools/telemetry/telemetry/value/string.py +++ b/tools/telemetry/telemetry/value/string.py
@@ -9,14 +9,16 @@ class StringValue(value_module.Value): def __init__(self, page, name, units, value, important=True, - description=None, none_value_reason=None): + description=None, interaction_record=None, + none_value_reason=None): """A single value (float, integer or string) result from a test. A test that output a hash of the content in a page might produce a string value: StringValue(page, 'page_hash', 'hash', '74E377FF') """ - super(StringValue, self).__init__(page, name, units, important, description) + super(StringValue, self).__init__(page, name, units, important, description, + interaction_record) assert value is None or isinstance(value, basestring) none_values.ValidateNoneValueReason(value, none_value_reason) self.value = value @@ -27,13 +29,15 @@ page_name = self.page.url else: page_name = None - return 'StringValue(%s, %s, %s, %s, important=%s, description=%s)' % ( - page_name, - self.name, - self.units, - self.value, - self.important, - self.description) + return ('StringValue(%s, %s, %s, %s, important=%s, description=%s, ' + 'interaction_record=%s)') % ( + page_name, + self.name, + self.units, + self.value, + self.important, + self.description, + self.interaction_record) def GetBuildbotDataType(self, output_context): if self._IsImportantGivenOutputIntent(output_context): @@ -71,6 +75,8 @@ if 'none_value_reason' in value_dict: kwargs['none_value_reason'] = value_dict['none_value_reason'] + if 'interaction_record' in value_dict: + kwargs['interaction_record'] = value_dict['interaction_record'] return StringValue(**kwargs) @@ -78,7 +84,7 @@ def MergeLikeValuesFromSamePage(cls, values): assert len(values) > 0 v0 = values[0] - return cls._MergeLikeValues(values, v0.page, v0.name) + return cls._MergeLikeValues(values, v0.page, v0.name, v0.interaction_record) @classmethod def MergeLikeValuesFromDifferentPages(cls, values, @@ -86,10 +92,10 @@ assert len(values) > 0 v0 = values[0] name = v0.name_suffix if group_by_name_suffix else v0.name - return cls._MergeLikeValues(values, None, name) + return cls._MergeLikeValues(values, None, name, v0.interaction_record) @classmethod - def _MergeLikeValues(cls, values, page, name): + def _MergeLikeValues(cls, values, page, name, interaction_record): v0 = values[0] merged_value = [v.value for v in values] none_value_reason = None @@ -98,4 +104,5 @@ none_value_reason = none_values.MERGE_FAILURE_REASON return list_of_string_values.ListOfStringValues( page, name, v0.units, merged_value, important=v0.important, + interaction_record=interaction_record, none_value_reason=none_value_reason)
diff --git a/tools/telemetry/telemetry/value/trace.py b/tools/telemetry/telemetry/value/trace.py index a148bbb..1860ade 100644 --- a/tools/telemetry/telemetry/value/trace.py +++ b/tools/telemetry/telemetry/value/trace.py
@@ -28,7 +28,7 @@ """ super(TraceValue, self).__init__( page, name='trace', units='', important=important, - description=description) + description=description, interaction_record=None) self._temp_file = self._GetTempFileHandle(trace_data) self._cloud_url = None self._serialized_file_handle = None
diff --git a/tools/telemetry/telemetry/value/value_unittest.py b/tools/telemetry/telemetry/value/value_unittest.py index 7c95571..f6ca452 100644 --- a/tools/telemetry/telemetry/value/value_unittest.py +++ b/tools/telemetry/telemetry/value/value_unittest.py
@@ -71,78 +71,117 @@ page0 = self.pages[0] page1 = self.pages[0] - a = value.Value(page0, 'x', 'unit', important=False, description=None) - b = value.Value(page1, 'x', 'unit', important=False, description=None) + a = value.Value(page0, 'x', 'unit', important=False, description=None, + interaction_record='foo') + b = value.Value(page1, 'x', 'unit', important=False, description=None, + interaction_record='foo') self.assertTrue(b.IsMergableWith(a)) def testIncompat(self): page0 = self.pages[0] - a = value.Value(page0, 'x', 'unit', important=False, description=None) + a = value.Value(page0, 'x', 'unit', important=False, description=None, + interaction_record=None) b = value.Value(page0, 'x', 'incompatUnit', important=False, - description=None) + interaction_record=None, description=None) self.assertFalse(b.IsMergableWith(a)) - a = value.Value(page0, 'x', 'unit', important=False, description=None) - b = value.Value(page0, 'x', 'unit', important=True, description=None) + a = value.Value(page0, 'x', 'unit', important=False, description=None, + interaction_record=None) + b = value.Value(page0, 'x', 'unit', important=True, description=None, + interaction_record=None) self.assertFalse(b.IsMergableWith(a)) - a = value.Value(page0, 'x', 'unit', important=False, description=None) - b = ValueForTest(page0, 'x', 'unit', important=True, description=None) + a = value.Value(page0, 'x', 'unit', important=False, description=None, + interaction_record=None) + b = ValueForTest(page0, 'x', 'unit', important=True, description=None, + interaction_record=None) + self.assertFalse(b.IsMergableWith(a)) + + a = value.Value(page0, 'x', 'unit', important=False, description=None, + interaction_record='foo') + b = value.Value(page0, 'x', 'unit', important=False, description=None, + interaction_record='bar') self.assertFalse(b.IsMergableWith(a)) def testNameMustBeString(self): with self.assertRaises(ValueError): - value.Value(None, 42, 'unit', important=False, description=None) + value.Value(None, 42, 'unit', important=False, description=None, + interaction_record=None) def testUnitsMustBeString(self): with self.assertRaises(ValueError): - value.Value(None, 'x', 42, important=False, description=None) + value.Value(None, 'x', 42, important=False, description=None, + interaction_record=None) def testImportantMustBeBool(self): with self.assertRaises(ValueError): - value.Value(None, 'x', 'unit', important='foo', description=None) + value.Value(None, 'x', 'unit', important='foo', description=None, + interaction_record=None) def testDescriptionMustBeStringOrNone(self): with self.assertRaises(ValueError): - value.Value(None, 'x', 'unit', important=False, description=42) + value.Value(None, 'x', 'unit', important=False, description=42, + interaction_record=None) + + def testInteractionRecordMustBeStringOrNone(self): + with self.assertRaises(ValueError): + value.Value(None, 'x', 'unit', important=False, description=None, + interaction_record=42) def testAsDictBaseKeys(self): - v = ValueForAsDictTest(None, 'x', 'unit', important=True, description=None) + v = ValueForAsDictTest(None, 'x', 'unit', important=True, description=None, + interaction_record='bar') d = v.AsDict() self.assertEquals(d, { 'name': 'x', 'type': 'baz', 'units': 'unit', - 'important': True + 'important': True, + 'interaction_record': 'bar' }) def testAsDictWithPage(self): page0 = self.pages[0] v = ValueForAsDictTest(page0, 'x', 'unit', important=False, - description=None) + description=None, interaction_record=None) d = v.AsDict() self.assertIn('page_id', d) def testAsDictWithoutPage(self): - v = ValueForAsDictTest(None, 'x', 'unit', important=False, description=None) + v = ValueForAsDictTest(None, 'x', 'unit', important=False, description=None, + interaction_record=None) d = v.AsDict() self.assertNotIn('page_id', d) def testAsDictWithDescription(self): v = ValueForAsDictTest(None, 'x', 'unit', important=False, - description='Some description.') + description='Some description.', + interaction_record=None) d = v.AsDict() self.assertEqual('Some description.', d['description']) def testAsDictWithoutDescription(self): - v = ValueForAsDictTest(None, 'x', 'unit', important=False, description=None) + v = ValueForAsDictTest(None, 'x', 'unit', important=False, description=None, + interaction_record=None) self.assertNotIn('description', v.AsDict()) + def testAsDictWithInteractionRecord(self): + v = ValueForAsDictTest(None, 'x', 'unit', important=False, + description='Some description.', + interaction_record='foo') + d = v.AsDict() + self.assertEqual('foo', d['interaction_record']) + + def testAsDictWithoutDescription(self): + v = ValueForAsDictTest(None, 'x', 'unit', important=False, description=None, + interaction_record=None) + self.assertNotIn('interaction_record', v.AsDict()) + def testFromDictBaseKeys(self): d = { 'type': 'value_for_from_dict_test', @@ -202,6 +241,28 @@ v = value.Value.FromDict(d, {}) self.assertEquals(v.description, None) + def testFromDictWithInteractionRecord(self): + d = { + 'type': 'value_for_from_dict_test', + 'name': 'x', + 'units': 'unit', + 'description': 'foo', + 'interaction_record': 'bar' + } + + v = value.Value.FromDict(d, {}) + self.assertEquals(v.interaction_record, 'bar') + + def testFromDictWithoutInteractionRecord(self): + d = { + 'type': 'value_for_from_dict_test', + 'name': 'x', + 'units': 'unit' + } + + v = value.Value.FromDict(d, {}) + self.assertEquals(v.interaction_record, None) + def testListOfValuesFromListOfDicts(self): d0 = { 'type': 'value_for_from_dict_test',
diff --git a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py index 5f9278d5..ed39e53 100644 --- a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py +++ b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py
@@ -20,7 +20,7 @@ FORWARD_SCROLL_UPDATE_COMP_NAME = ( 'INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT') # This is when the input event has reached swap buffer. -END_COMP_NAME = 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT' +END_COMP_NAME = 'INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT' # Name for a main thread scroll update latency event. SCROLL_UPDATE_EVENT_NAME = 'InputLatency:ScrollUpdate'
diff --git a/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py b/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py index 017bf08..267ef00 100644 --- a/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py +++ b/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py
@@ -12,6 +12,7 @@ from telemetry.web_perf import timeline_interaction_record as tir_module from telemetry.web_perf.metrics import responsiveness_metric from telemetry.web_perf.metrics import smoothness +from telemetry.web_perf.metrics import layout # TimelineBasedMeasurement considers all instrumentation as producing a single # timeline. But, depending on the amount of instrumentation that is enabled, @@ -27,25 +28,20 @@ DEBUG_OVERHEAD_LEVEL ] -DEFAULT_METRICS = { - tir_module.IS_SMOOTH: smoothness.SmoothnessMetric, - tir_module.IS_RESPONSIVE: responsiveness_metric.ResponsivenessMetric, -} + +def _GetAllTimelineBasedMetrics(): + # TODO(nednguyen): use discovery pattern to return all the instances of + # all TimelineBasedMetrics class in web_perf/metrics/ folder. + # This cannot be done until crbug.com/460208 is fixed. + return (smoothness.SmoothnessMetric(), + responsiveness_metric.ResponsivenessMetric(), + layout.LayoutMetric()) + class InvalidInteractions(Exception): pass -def _GetMetricsFromFlags(record_custom_flags): - flags_set = set(record_custom_flags) - unknown_flags = flags_set.difference(DEFAULT_METRICS) - if unknown_flags: - raise Exception("Unknown metric flags: %s" % sorted(unknown_flags)) - - return [metric() for flag, metric in DEFAULT_METRICS.iteritems() - if flag in flags_set] - - # TODO(nednguyen): Get rid of this results wrapper hack after we add interaction # record to telemetry value system. class _ResultsWrapper(object): @@ -86,13 +82,10 @@ class _TimelineBasedMetrics(object): - def __init__(self, model, renderer_thread, interaction_records, - get_metrics_from_flags_callback): + def __init__(self, model, renderer_thread, interaction_records): self._model = model self._renderer_thread = renderer_thread self._interaction_records = interaction_records - self._get_metrics_from_flags_callback = \ - get_metrics_from_flags_callback def AddResults(self, results): interactions_by_label = defaultdict(list) @@ -118,8 +111,7 @@ raise InvalidInteractions('Interaction records with the same logical ' 'name must have the same flags.') - metrics_list = self._get_metrics_from_flags_callback(records_custom_flags) - for metric in metrics_list: + for metric in _GetAllTimelineBasedMetrics(): metric.AddResults(self._model, self._renderer_thread, interactions, wrapped_results) @@ -131,8 +123,7 @@ Benchmark.CreateTimelineBasedMeasurementOptions. """ - def __init__(self, overhead_level=NO_OVERHEAD_LEVEL, - get_metrics_from_flags_callback=_GetMetricsFromFlags): + def __init__(self, overhead_level=NO_OVERHEAD_LEVEL): """As the amount of instrumentation increases, so does the overhead. The user of the measurement chooses the overhead level that is appropriate, and the tracing is filtered accordingly. @@ -140,9 +131,6 @@ overhead_level: Can either be a custom TracingCategoryFilter object or one of NO_OVERHEAD_LEVEL, MINIMAL_OVERHEAD_LEVEL or DEBUG_OVERHEAD_LEVEL. - get_metrics_from_flags_callback: Callback function which returns a - a list of metrics based on timeline record flags. See the default - _GetMetricsFromFlags() as an example. """ if (not isinstance(overhead_level, tracing_category_filter.TracingCategoryFilter) and @@ -153,7 +141,6 @@ self._overhead_level = overhead_level self._extra_category_filters = [] - self._get_metrics_from_flags_callback = get_metrics_from_flags_callback def ExtendTraceCategoryFilters(self, filters): self._extra_category_filters.extend(filters) @@ -166,10 +153,6 @@ def overhead_level(self): return self._overhead_level - @property - def get_metrics_from_flags_callback(self): - return self._get_metrics_from_flags_callback - class TimelineBasedMeasurement(object): """Collects multiple metrics based on their interaction records. @@ -244,8 +227,7 @@ for renderer_thread, interaction_records in ( threads_to_records_map.iteritems()): meta_metrics = _TimelineBasedMetrics( - model, renderer_thread, interaction_records, - self._tbm_options.get_metrics_from_flags_callback) + model, renderer_thread, interaction_records) meta_metrics.AddResults(results) def DidRunUserStory(self, tracing_controller):
diff --git a/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py b/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py index e676811d..fe7971b 100644 --- a/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py +++ b/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py
@@ -42,22 +42,6 @@ len(interaction_records))) -FAKE_METRICS_METRICS = { - tir_module.IS_SMOOTH: FakeSmoothMetric, - tir_module.IS_RESPONSIVE: FakeLoadingMetric, -} - - -def GetMetricFromFlags(record_custom_flags): - flags_set = set(record_custom_flags) - unknown_flags = flags_set.difference(FAKE_METRICS_METRICS) - if unknown_flags: - raise Exception("Unknown metric flags: %s" % sorted(unknown_flags)) - - return [metric() for flag, metric in FAKE_METRICS_METRICS.iteritems() - if flag in flags_set] - - class TimelineBasedMetricTestData(object): def __init__(self): @@ -111,13 +95,21 @@ def AddResults(self): for thread, records in self._threads_to_records_map.iteritems(): metric = tbm_module._TimelineBasedMetrics( # pylint: disable=W0212 - self._model, thread, records, GetMetricFromFlags) + self._model, thread, records) metric.AddResults(self._results) self._results.DidRunPage(self._ps.pages[0]) class TimelineBasedMetricsTests(unittest.TestCase): + def setUp(self): + self.actual_get_all_tbm_metrics = tbm_module._GetAllTimelineBasedMetrics + fake_tbm_metrics = (FakeSmoothMetric(), FakeLoadingMetric()) + tbm_module._GetAllTimelineBasedMetrics = lambda: fake_tbm_metrics + + def tearDown(self): + tbm_module._GetAllTimelineBasedMetrics = self.actual_get_all_tbm_metrics + def testGetRendererThreadsToInteractionRecordsMap(self): d = TimelineBasedMetricTestData() # Insert 2 interaction records to renderer_thread and 1 to foo_thread
diff --git a/tools/ubsan/blacklist.txt b/tools/ubsan/blacklist.txt index 5b4751fe..29a2b3a5 100644 --- a/tools/ubsan/blacklist.txt +++ b/tools/ubsan/blacklist.txt
@@ -47,6 +47,10 @@ fun:*DatabaseContext*contextDestroyed* +# FIXME: Cannot handle template function LifecycleObserver<>::setContext, +# so exclude source file for now. +src:*LifecycleObserver.h* + ############################################################################# # static_cast into itself in the constructor. @@ -54,12 +58,14 @@ fun:*ThreadSafeRefCountedGarbageCollected*makeKeepAlive* ############################################################################# -# Accessing data in destructurors where the class has virtual inheritances. +# Accessing data in destructors where the class has virtual inheritances. type:*content*RenderWidgetHost* -# Mangled name for content::RenderViewHostImpl::~RenderViewHostImpl() -fun:*content*RenderViewHostImpl* +# Match mangled name for content::RenderViewHostImpl::~RenderViewHostImpl(). +fun:*content*RenderViewHostImplD* +# Match mangled name for content::RenderThreadImpl::~RenderThreadImpl(). +fun:*content*RenderThreadImplD* ############################################################################# # Using raw pointer values. @@ -94,6 +100,13 @@ ############################################################################# # UBSan seems to be emit false positives when virtual base classes are -# involved, see e.g. chromium:448102 +# involved, see e.g. crbug.com/448102. type:*v8*internal*OFStream* + +############################################################################# +# UBsan is unable to handle static_cast<A*>(nullptr) and crashes on SIGSEGV. +# + +# static_cast<StartPageService*> in StartPageServiceFactory::GetForProfile. +type:*StartPageService*
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt index d6f60966..c429a9f1 100644 --- a/tools/valgrind/drmemory/suppressions.txt +++ b/tools/valgrind/drmemory/suppressions.txt
@@ -742,3 +742,20 @@ *!content::ContentMainRunnerImpl::Run *!content::ContentMain *!content::LaunchTests + +UNINITIALIZED READ +name=http://crbug.com/463204 +skia.dll!_ltod3 +skia.dll!SkPaint::measure_text +skia.dll!SkPaint::measureText +content.dll!content::DoPreSandboxWarmupForTypeface +content.dll!content::`anonymous namespace'::WarmupDirectWrite + +UNADDRESSABLE ACCESS +name=http://crbug.com/463261 +... +blink_web.dll!blink::WebFrameWidgetImpl::selectionBounds +content.dll!content::RenderWidget::GetSelectionBounds +content.dll!content::RenderWidget::UpdateSelectionBounds +content.dll!content::RenderWidget::willBeginCompositorFrame +cc.dll!base::internal::InvokeHelper<>::MakeItSo
diff --git a/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory.txt b/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory.txt index 6d9febd..2ec3183 100644 --- a/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory.txt +++ b/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory.txt
@@ -1,3 +1,6 @@ +# http://crbug.com/293125 +WebRtcBrowserTest.CanMakeEmptyCallThenAddStreamsAndRenegotiate + # crbug.com/395172 WebRtcBrowserTest.CanForwardRemoteStream WebRtcBrowserTest.CanForwardRemoteStream720p @@ -23,8 +26,12 @@ # crbug.com/461489 ServiceWorkerVersionBrowserTest.TimeoutStartingWorker -# http://crbug.com/293125 -WebRtcBrowserTest.CanMakeEmptyCallThenAddStreamsAndRenegotiate - # http://crbug.com/456131 BrowserSideNavigationBrowserTest.BrowserInitiatedNavigations + +# http://crbug.com/464029 +WebRtcBrowserTest.CallAndModifyStream + +# http://crbug.com/464033 +RenderFrameHostImplBrowserTest.IsFocused_AtLoad +RenderFrameHostImplBrowserTest.IsFocused_Widget
diff --git a/tools/valgrind/gtest_exclude/mojo_system_unittests.gtest-drmemory.txt b/tools/valgrind/gtest_exclude/mojo_system_unittests.gtest-drmemory.txt index 24fd314..5149d6c 100644 --- a/tools/valgrind/gtest_exclude/mojo_system_unittests.gtest-drmemory.txt +++ b/tools/valgrind/gtest_exclude/mojo_system_unittests.gtest-drmemory.txt
@@ -2,3 +2,5 @@ RemoteMessagePipeTest.HandlePassing # crbug.com/440828 EmbedderTest.MultiprocessChannels +# crbug.com/464019 +DataPipeImplTest*.TwoPhaseAllOrNone
diff --git a/tools/valgrind/locate_valgrind.sh b/tools/valgrind/locate_valgrind.sh index 5d0a06b..11d4d83 100755 --- a/tools/valgrind/locate_valgrind.sh +++ b/tools/valgrind/locate_valgrind.sh
@@ -36,32 +36,24 @@ PLATFORM="mac_10.7" ;; *) - echo "Unknown platform:" >&2 - uname -a >&2 - echo "We'll try to search for valgrind binaries installed in /usr/local" >&2 - PLATFORM= + (echo "Sorry, your platform is not supported:" && + uname -a + echo + echo "If you're on Mac OS X, please see http://crbug.com/441425") >&2 + exit 42 esac - if [ "$PLATFORM" != "" ] + # The binaries should be in third_party/valgrind + # (checked out from deps/third_party/valgrind/binaries). + CHROME_VALGRIND="$THISDIR/../../third_party/valgrind/$PLATFORM" + + # TODO(timurrrr): readlink -f is not present on Mac... + if [ "$PLATFORM" != "mac" ] && \ + [ "$PLATFORM" != "mac_10.6" ] && \ + [ "$PLATFORM" != "mac_10.7" ] then - # The binaries should be in third_party/valgrind - # (checked out from deps/third_party/valgrind/binaries). - CHROME_VALGRIND="$THISDIR/../../third_party/valgrind/$PLATFORM" - - # TODO(timurrrr): readlink -f is not present on Mac... - if [ "$PLATFORM" != "mac" ] && \ - [ "$PLATFORM" != "mac_10.6" ] && \ - [ "$PLATFORM" != "mac_10.7" ] - then - # Get rid of all "../" dirs - CHROME_VALGRIND=`readlink -f $CHROME_VALGRIND` - fi - - if ! test -x $CHROME_VALGRIND/bin/valgrind - then - # We couldn't find the binaries in third_party/valgrind - CHROME_VALGRIND="" - fi + # Get rid of all "../" dirs + CHROME_VALGRIND=$(readlink -f $CHROME_VALGRIND) fi fi
diff --git a/ui/accessibility/ax_tree_serializer.h b/ui/accessibility/ax_tree_serializer.h index f1cbfce..53e515a 100644 --- a/ui/accessibility/ax_tree_serializer.h +++ b/ui/accessibility/ax_tree_serializer.h
@@ -292,36 +292,39 @@ // with the LCA. AXSourceNode lca = LeastCommonAncestor(node); - if (client_root_) { - bool need_delete = false; - if (tree_->IsValid(lca)) { - // Check for any reparenting within this subtree - if there is - // any, we need to delete and reserialize the whole subtree - // that contains the old and new parents of the reparented node. - if (AnyDescendantWasReparented(lca, &lca)) - need_delete = true; - } - - if (!tree_->IsValid(lca)) { - // If there's no LCA, just tell the client to destroy the whole - // tree and then we'll serialize everything from the new root. - out_update->node_id_to_clear = client_root_->id; - Reset(); - } else if (need_delete) { - // Otherwise, if we need to reserialize a subtree, first we need - // to delete those nodes in our client tree so that - // SerializeChangedNodes() will be sure to send them again. - out_update->node_id_to_clear = tree_->GetId(lca); - ClientTreeNode* client_lca = ClientTreeNodeById(tree_->GetId(lca)); - CHECK(client_lca); - for (size_t i = 0; i < client_lca->children.size(); ++i) { - client_id_map_.erase(client_lca->children[i]->id); - DeleteClientSubtree(client_lca->children[i]); - delete client_lca->children[i]; + // This loop computes the least common ancestor that includes the old + // and new parents of any nodes that have been reparented, and clears the + // whole client subtree of that LCA if necessary. If we do end up clearing + // any client nodes, keep looping because we have to search for more + // nodes that may have been reparented from this new LCA. + bool need_delete; + do { + need_delete = false; + if (client_root_) { + if (tree_->IsValid(lca)) { + // Check for any reparenting within this subtree - if there is + // any, we need to delete and reserialize the whole subtree + // that contains the old and new parents of the reparented node. + if (AnyDescendantWasReparented(lca, &lca)) + need_delete = true; } - client_lca->children.clear(); + + if (!tree_->IsValid(lca)) { + // If there's no LCA, just tell the client to destroy the whole + // tree and then we'll serialize everything from the new root. + out_update->node_id_to_clear = client_root_->id; + Reset(); + } else if (need_delete) { + // Otherwise, if we need to reserialize a subtree, first we need + // to delete those nodes in our client tree so that + // SerializeChangedNodes() will be sure to send them again. + out_update->node_id_to_clear = tree_->GetId(lca); + ClientTreeNode* client_lca = ClientTreeNodeById(tree_->GetId(lca)); + CHECK(client_lca); + DeleteClientSubtree(client_lca); + } } - } + } while (need_delete); // Serialize from the LCA, or from the root if there isn't one. if (!tree_->IsValid(lca))
diff --git a/ui/android/java/src/org/chromium/ui/ColorPickerAdvancedComponent.java b/ui/android/java/src/org/chromium/ui/ColorPickerAdvancedComponent.java index c868f32..ed49e22 100644 --- a/ui/android/java/src/org/chromium/ui/ColorPickerAdvancedComponent.java +++ b/ui/android/java/src/org/chromium/ui/ColorPickerAdvancedComponent.java
@@ -4,6 +4,7 @@ package org.chromium.ui; +import android.annotation.TargetApi; import android.content.Context; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable.Orientation; @@ -82,6 +83,7 @@ * * @param newColors The set of colors representing the interpolation points for the gradient. */ + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public void setGradientColors(int[] newColors) { mGradientColors = newColors.clone(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
diff --git a/ui/android/java/src/org/chromium/ui/base/Clipboard.java b/ui/android/java/src/org/chromium/ui/base/Clipboard.java index aaa500e..67aaca2 100644 --- a/ui/android/java/src/org/chromium/ui/base/Clipboard.java +++ b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
@@ -4,12 +4,13 @@ package org.chromium.ui.base; +import android.annotation.TargetApi; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; +import android.os.Build; import android.widget.Toast; -import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; import org.chromium.ui.R; @@ -20,6 +21,10 @@ */ @JNINamespace("ui") public class Clipboard { + + private static final boolean IS_HTML_CLIPBOARD_SUPPORTED = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; + // Necessary for coercing clipboard contents to text if they require // access to network resources, etceteras (e.g., URI in clipboard) private final Context mContext; @@ -83,9 +88,10 @@ * @return a Java string with the html text if any, or null if there is no html * text or no entries on the primary clip. */ + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @CalledByNative private String getHTMLText() { - if (isHTMLClipboardSupported()) { + if (IS_HTML_CLIPBOARD_SUPPORTED) { final ClipData clip = mClipboardManager.getPrimaryClip(); if (clip != null && clip.getItemCount() > 0) { return clip.getItemAt(0).getHtmlText(); @@ -129,8 +135,9 @@ * @param label The Plain-text label for the HTML content. * @param text Plain-text representation of the HTML content. */ + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public void setHTMLText(final String html, final String label, final String text) { - if (isHTMLClipboardSupported()) { + if (IS_HTML_CLIPBOARD_SUPPORTED) { setPrimaryClipNoException(ClipData.newHtmlText(label, text, html)); } } @@ -150,7 +157,7 @@ @CalledByNative private static boolean isHTMLClipboardSupported() { - return ApiCompatibilityUtils.isHTMLClipboardSupported(); + return IS_HTML_CLIPBOARD_SUPPORTED; } private void setPrimaryClipNoException(ClipData clip) {
diff --git a/ui/android/java/src/org/chromium/ui/gfx/DeviceDisplayInfo.java b/ui/android/java/src/org/chromium/ui/gfx/DeviceDisplayInfo.java index 3856951..da8e026 100644 --- a/ui/android/java/src/org/chromium/ui/gfx/DeviceDisplayInfo.java +++ b/ui/android/java/src/org/chromium/ui/gfx/DeviceDisplayInfo.java
@@ -4,6 +4,7 @@ package org.chromium.ui.gfx; +import android.annotation.TargetApi; import android.content.Context; import android.graphics.PixelFormat; import android.graphics.Point; @@ -57,6 +58,7 @@ /** * @return Real physical display height in physical pixels. */ + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) @CalledByNative public int getPhysicalDisplayHeight() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { @@ -69,6 +71,7 @@ /** * @return Real physical display width in physical pixels. */ + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) @CalledByNative public int getPhysicalDisplayWidth() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
diff --git a/ui/android/java/src/org/chromium/ui/gl/SurfaceTexturePlatformWrapper.java b/ui/android/java/src/org/chromium/ui/gl/SurfaceTexturePlatformWrapper.java index 5f4c598..b3ebd5a 100644 --- a/ui/android/java/src/org/chromium/ui/gl/SurfaceTexturePlatformWrapper.java +++ b/ui/android/java/src/org/chromium/ui/gl/SurfaceTexturePlatformWrapper.java
@@ -4,6 +4,7 @@ package org.chromium.ui.gl; +import android.annotation.TargetApi; import android.graphics.SurfaceTexture; import android.os.Build; import android.util.Log; @@ -25,6 +26,7 @@ return new SurfaceTexture(textureId); } + @TargetApi(Build.VERSION_CODES.KITKAT) @CalledByNative private static SurfaceTexture createSingleBuffered(int textureId) { assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; @@ -53,6 +55,7 @@ } } + @TargetApi(Build.VERSION_CODES.KITKAT) @CalledByNative private static void releaseTexImage(SurfaceTexture surfaceTexture) { assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; @@ -60,22 +63,18 @@ } @CalledByNative - private static void setDefaultBufferSize(SurfaceTexture surfaceTexture, int width, - int height) { - surfaceTexture.setDefaultBufferSize(width, height); - } - - @CalledByNative private static void getTransformMatrix(SurfaceTexture surfaceTexture, float[] matrix) { surfaceTexture.getTransformMatrix(matrix); } + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @CalledByNative private static void attachToGLContext(SurfaceTexture surfaceTexture, int texName) { assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; surfaceTexture.attachToGLContext(texName); } + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @CalledByNative private static void detachFromGLContext(SurfaceTexture surfaceTexture) { assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
diff --git a/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java b/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java index d03c1650..f8647ec 100644 --- a/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java +++ b/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java
@@ -155,11 +155,14 @@ mMinuteSpinner.setMaxValue(59); } - if (step >= HOUR_IN_MILLIS) { + mMinuteSpinner.setValue(minute); + if (step % HOUR_IN_MILLIS == 0) { mMinuteSpinner.setEnabled(false); + // TODO(tkent): We should set minutes value of + // WebDateTimeChooserParams::stepBase. + mMinuteSpinner.setValue(minMinute); } - mMinuteSpinner.setValue(minute); mMinuteSpinner.setFormatter(twoDigitPaddingFormatter); if (step >= MINUTE_IN_MILLIS) {
diff --git a/ui/android/java/src/org/chromium/ui/picker/TwoFieldDatePicker.java b/ui/android/java/src/org/chromium/ui/picker/TwoFieldDatePicker.java index 8d72189..85d28502 100644 --- a/ui/android/java/src/org/chromium/ui/picker/TwoFieldDatePicker.java +++ b/ui/android/java/src/org/chromium/ui/picker/TwoFieldDatePicker.java
@@ -5,6 +5,7 @@ package org.chromium.ui.picker; import android.content.Context; +import android.os.Build; import android.text.format.DateFormat; import android.text.format.DateUtils; import android.view.LayoutInflater; @@ -111,7 +112,12 @@ mYearSpinner.setOnLongPressUpdateInterval(100); mYearSpinner.setOnValueChangedListener(onChangeListener); - reorderSpinners(); + // TODO(tobiasjs): reorderSpinners causes a crash on Android versions before JB MR2 because + // it calls DateFormat.getBestDateTimePattern() which isn't available before then. Fix this + // crash and call reorderSpinners on all devices. http://crbug.com/463719 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + reorderSpinners(); + } } /**
diff --git a/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java b/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java index 5c76f3a..750710d 100644 --- a/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java +++ b/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java
@@ -4,7 +4,9 @@ package org.chromium.ui.widget; +import android.annotation.TargetApi; import android.content.Context; +import android.os.Build; import android.os.Bundle; import android.text.Layout; import android.text.SpannableString; @@ -61,6 +63,7 @@ } @Override + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public boolean performAccessibilityAction(int action, Bundle arguments) { // BrailleBack will generate an accessibility click event directly // on this view, make sure we handle that correctly.
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn index f1fae35..8758ad4 100644 --- a/ui/app_list/BUILD.gn +++ b/ui/app_list/BUILD.gn
@@ -218,69 +218,67 @@ ] } -if (!is_win || link_chrome_on_windows) { - test("app_list_unittests") { - sources = [ - "app_list_item_list_unittest.cc", - "app_list_model_unittest.cc", - "folder_image_unittest.cc", - "pagination_model_unittest.cc", - "search/history_data_store_unittest.cc", - "search/mixer_unittest.cc", - "search/term_break_iterator_unittest.cc", - "search/tokenized_string_char_iterator_unittest.cc", - "search/tokenized_string_match_unittest.cc", - "search/tokenized_string_unittest.cc", - "test/run_all_unittests.cc", +test("app_list_unittests") { + sources = [ + "app_list_item_list_unittest.cc", + "app_list_model_unittest.cc", + "folder_image_unittest.cc", + "pagination_model_unittest.cc", + "search/history_data_store_unittest.cc", + "search/mixer_unittest.cc", + "search/term_break_iterator_unittest.cc", + "search/tokenized_string_char_iterator_unittest.cc", + "search/tokenized_string_match_unittest.cc", + "search/tokenized_string_unittest.cc", + "test/run_all_unittests.cc", + ] + + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + + deps = [ + ":app_list", + ":test_support", + "//base", + "//base/test:test_support", + "//skia", + "//testing/gtest", + "//ui/base", + "//ui/compositor", + "//ui/events", + "//ui/events:test_support", + "//ui/gl", + "//ui/resources", + "//ui/resources:ui_test_pak", + ] + + if (toolkit_views) { + sources += [ + "views/app_list_main_view_unittest.cc", + "views/app_list_view_unittest.cc", + "views/apps_grid_view_unittest.cc", + "views/contents_view_unittest.cc", + "views/folder_header_view_unittest.cc", + "views/search_box_view_unittest.cc", + "views/search_result_list_view_unittest.cc", + "views/speech_view_unittest.cc", + "views/test/apps_grid_view_test_api.cc", + "views/test/apps_grid_view_test_api.h", ] - - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] - - deps = [ - ":app_list", - ":test_support", - "//base", - "//base/test:test_support", - "//skia", - "//testing/gtest", - "//ui/base", - "//ui/compositor", - "//ui/events", - "//ui/events:test_support", - "//ui/gl", - "//ui/resources", - "//ui/resources:ui_test_pak", + deps += [ + "//ui/views", + "//ui/views:test_support", ] + } - if (toolkit_views) { - sources += [ - "views/app_list_main_view_unittest.cc", - "views/app_list_view_unittest.cc", - "views/apps_grid_view_unittest.cc", - "views/contents_view_unittest.cc", - "views/folder_header_view_unittest.cc", - "views/search_box_view_unittest.cc", - "views/search_result_list_view_unittest.cc", - "views/speech_view_unittest.cc", - "views/test/apps_grid_view_test_api.cc", - "views/test/apps_grid_view_test_api.h", - ] - deps += [ - "//ui/views", - "//ui/views:test_support", - ] - } - - if (is_mac) { - sources += [ - "cocoa/app_list_view_controller_unittest.mm", - "cocoa/app_list_window_controller_unittest.mm", - "cocoa/apps_grid_controller_unittest.mm", - "cocoa/apps_search_box_controller_unittest.mm", - "cocoa/apps_search_results_controller_unittest.mm", - "cocoa/test/apps_grid_controller_test_helper.h", - "cocoa/test/apps_grid_controller_test_helper.mm", - ] - } + if (is_mac) { + sources += [ + "cocoa/app_list_view_controller_unittest.mm", + "cocoa/app_list_window_controller_unittest.mm", + "cocoa/apps_grid_controller_unittest.mm", + "cocoa/apps_search_box_controller_unittest.mm", + "cocoa/apps_search_results_controller_unittest.mm", + "cocoa/test/apps_grid_controller_test_helper.h", + "cocoa/test/apps_grid_controller_test_helper.mm", + ] } }
diff --git a/ui/app_list/PRESUBMIT.py b/ui/app_list/PRESUBMIT.py index 3e3d954e..73df615 100644 --- a/ui/app_list/PRESUBMIT.py +++ b/ui/app_list/PRESUBMIT.py
@@ -23,7 +23,7 @@ sources = lambda x: input_api.FilterSourceFile( x, white_list = INCLUDE_CPP_FILES_ONLY, black_list = black_list) return input_api.canned_checks.CheckChangeLintsClean( - input_api, output_api, sources, []) + input_api, output_api, sources, lint_filters=[], verbose_level=1) def CheckChangeOnUpload(input_api, output_api): results = []
diff --git a/ui/app_list/search/dictionary_data_store.cc b/ui/app_list/search/dictionary_data_store.cc index b867be4..45f53ca 100644 --- a/ui/app_list/search/dictionary_data_store.cc +++ b/ui/app_list/search/dictionary_data_store.cc
@@ -64,12 +64,12 @@ scoped_ptr<base::DictionaryValue> DictionaryDataStore::LoadOnBlockingPool() { DCHECK(worker_pool_->RunsTasksOnCurrentThread()); - int error_code = JSONFileValueSerializer::JSON_NO_ERROR; + int error_code = JSONFileValueDeserializer::JSON_NO_ERROR; std::string error_message; - JSONFileValueSerializer serializer(data_file_); - base::Value* value = serializer.Deserialize(&error_code, &error_message); + JSONFileValueDeserializer deserializer(data_file_); + base::Value* value = deserializer.Deserialize(&error_code, &error_message); base::DictionaryValue* dict_value = NULL; - if (error_code != JSONFileValueSerializer::JSON_NO_ERROR || !value || + if (error_code != JSONFileValueDeserializer::JSON_NO_ERROR || !value || !value->GetAsDictionary(&dict_value) || !dict_value) { return nullptr; }
diff --git a/ui/app_list/views/app_list_main_view.cc b/ui/app_list/views/app_list_main_view.cc index dceae0fa..02690dc 100644 --- a/ui/app_list/views/app_list_main_view.cc +++ b/ui/app_list/views/app_list_main_view.cc
@@ -251,22 +251,6 @@ } void AppListMainView::UpdateCustomLauncherPageVisibility() { - if (ShouldShowCustomLauncherPage()) { - // Make the custom page view visible again. - contents_view_->custom_page_view()->SetVisible(true); - } else if (contents_view_->IsStateActive( - AppListModel::STATE_CUSTOM_LAUNCHER_PAGE)) { - // Animate to the start page if currently on the custom page view. The view - // will hide on animation completion. - contents_view_->SetActivePage( - contents_view_->GetPageIndexForState(AppListModel::STATE_START)); - } else { - // Hide the view immediately otherwise. - contents_view_->custom_page_view()->SetVisible(false); - } -} - -void AppListMainView::OnCustomLauncherPageEnabledStateChanged(bool enabled) { views::View* custom_page = contents_view_->custom_page_view(); if (!custom_page) return; @@ -286,9 +270,13 @@ } } +void AppListMainView::OnCustomLauncherPageEnabledStateChanged(bool enabled) { + UpdateCustomLauncherPageVisibility(); +} + void AppListMainView::OnSearchEngineIsGoogleChanged(bool is_google) { if (contents_view_->custom_page_view()) - OnCustomLauncherPageEnabledStateChanged(is_google); + UpdateCustomLauncherPageVisibility(); if (contents_view_->start_page_view()) { contents_view_->start_page_view()->instant_container()->SetVisible(
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc index c1bdb1ed..216abf4 100644 --- a/ui/app_list/views/app_list_view.cc +++ b/ui/app_list/views/app_list_view.cc
@@ -83,6 +83,25 @@ return true; } +// This view forwards the focus to the search box widget by providing it as a +// FocusTraversable when a focus search is provided. +class SearchBoxFocusHost : public views::View { + public: + explicit SearchBoxFocusHost(views::Widget* search_box_widget) + : search_box_widget_(search_box_widget) {} + + ~SearchBoxFocusHost() override {} + + views::FocusTraversable* GetFocusTraversable() override { + return search_box_widget_; + } + + private: + views::Widget* search_box_widget_; + + DISALLOW_COPY_AND_ASSIGN(SearchBoxFocusHost); +}; + // The view for the App List overlay, which appears as a white rounded // rectangle with the given radius. class AppListOverlayView : public views::View { @@ -182,6 +201,7 @@ : delegate_(delegate), app_list_main_view_(nullptr), speech_view_(nullptr), + search_box_focus_host_(nullptr), search_box_widget_(nullptr), search_box_view_(nullptr), overlay_view_(nullptr), @@ -463,6 +483,15 @@ search_box_widget_->Init(search_box_widget_params); search_box_widget_->SetContentsView(search_box_view_); + // The search box will not naturally receive focus by itself (because it is in + // a separate widget). Create this SearchBoxFocusHost in the main widget to + // forward the focus search into to the search box. + search_box_focus_host_ = new SearchBoxFocusHost(search_box_widget_); + AddChildView(search_box_focus_host_); + search_box_widget_->SetFocusTraversableParentView(search_box_focus_host_); + search_box_widget_->SetFocusTraversableParent( + GetWidget()->GetFocusTraversable()); + #if defined(USE_AURA) // Mouse events on the search box shadow should not be captured. aura::Window* window = search_box_widget_->GetNativeWindow();
diff --git a/ui/app_list/views/app_list_view.h b/ui/app_list/views/app_list_view.h index 1634cef..b62f9d35 100644 --- a/ui/app_list/views/app_list_view.h +++ b/ui/app_list/views/app_list_view.h
@@ -173,6 +173,7 @@ AppListMainView* app_list_main_view_; SpeechView* speech_view_; + views::View* search_box_focus_host_; // Owned by the views hierarchy. views::Widget* search_box_widget_; // Owned by the app list's widget. SearchBoxView* search_box_view_; // Owned by |search_box_widget_|.
diff --git a/ui/app_list/views/search_result_page_view.cc b/ui/app_list/views/search_result_page_view.cc index 04c9443..2af6d583 100644 --- a/ui/app_list/views/search_result_page_view.cc +++ b/ui/app_list/views/search_result_page_view.cc
@@ -4,6 +4,8 @@ #include "ui/app_list/views/search_result_page_view.h" +#include <algorithm> + #include "ui/app_list/app_list_constants.h" #include "ui/app_list/app_list_switches.h" #include "ui/app_list/app_list_view_delegate.h"
diff --git a/ui/app_list/views/search_result_tile_item_view.cc b/ui/app_list/views/search_result_tile_item_view.cc index ae3d8b4..1823514 100644 --- a/ui/app_list/views/search_result_tile_item_view.cc +++ b/ui/app_list/views/search_result_tile_item_view.cc
@@ -26,6 +26,10 @@ } void SearchResultTileItemView::SetSearchResult(SearchResult* item) { + // Handle the case where this may be called from a nested run loop while its + // context menu is showing. This cancels the menu (it's for the old item). + context_menu_runner_.reset(); + SetVisible(item != NULL); SearchResult* old_item = item_;
diff --git a/ui/app_list/views/start_page_view.cc b/ui/app_list/views/start_page_view.cc index c546b2d..401aae1 100644 --- a/ui/app_list/views/start_page_view.cc +++ b/ui/app_list/views/start_page_view.cc
@@ -4,6 +4,8 @@ #include "ui/app_list/views/start_page_view.h" +#include <string> + #include "base/i18n/rtl.h" #include "base/metrics/histogram_macros.h" #include "base/strings/utf_string_conversions.h"
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn index 9a330fb..bcf1065 100644 --- a/ui/aura/BUILD.gn +++ b/ui/aura/BUILD.gn
@@ -243,63 +243,61 @@ } } -if (!is_win || link_chrome_on_windows) { - executable("bench") { - output_name = "aura_bench" - testonly = true +executable("bench") { + output_name = "aura_bench" + testonly = true - sources = [ - "bench/bench_main.cc", - ] + sources = [ + "bench/bench_main.cc", + ] - deps = [ - ":test_support", - "//base", - "//base:i18n", - "//cc", - "//gpu/command_buffer/client:gles2_interface", - "//skia", - "//third_party/icu", - "//ui/base", - "//ui/compositor", - "//ui/compositor:test_support", - "//ui/events", - "//ui/gfx", - "//ui/gfx/geometry", - "//ui/gl", - ] + deps = [ + ":test_support", + "//base", + "//base:i18n", + "//cc", + "//gpu/command_buffer/client:gles2_interface", + "//skia", + "//third_party/icu", + "//ui/base", + "//ui/compositor", + "//ui/compositor:test_support", + "//ui/events", + "//ui/gfx", + "//ui/gfx/geometry", + "//ui/gl", + ] - if (use_x11) { - deps += [ "//ui/gfx/x" ] - } + if (use_x11) { + deps += [ "//ui/gfx/x" ] } +} - test("aura_unittests") { - sources = [ - "gestures/gesture_recognizer_unittest.cc", - "test/run_all_unittests.cc", - "window_event_dispatcher_unittest.cc", - "window_targeter_unittest.cc", - "window_unittest.cc", - ] +test("aura_unittests") { + sources = [ + "gestures/gesture_recognizer_unittest.cc", + "test/run_all_unittests.cc", + "window_event_dispatcher_unittest.cc", + "window_targeter_unittest.cc", + "window_unittest.cc", + ] - deps = [ - ":test_support", - "//base/allocator", - "//base/test:test_support", - "//skia", - "//testing/gtest", - "//ui/base:test_support", - "//ui/compositor:test_support", - "//ui/events:test_support", - "//ui/events:gesture_detection", - "//ui/gfx", - "//ui/gfx/geometry", - "//ui/gl", - ] + deps = [ + ":test_support", + "//base/allocator", + "//base/test:test_support", + "//skia", + "//testing/gtest", + "//ui/base:test_support", + "//ui/compositor:test_support", + "//ui/events:test_support", + "//ui/events:gesture_detection", + "//ui/gfx", + "//ui/gfx/geometry", + "//ui/gl", + ] - if (is_linux) { - deps += [ "//third_party/mesa" ] - } + if (is_linux) { + deps += [ "//third_party/mesa" ] } }
diff --git a/ui/aura/demo/demo_main.cc b/ui/aura/demo/demo_main.cc index c589824..e7ed3680 100644 --- a/ui/aura/demo/demo_main.cc +++ b/ui/aura/demo/demo_main.cc
@@ -23,6 +23,7 @@ #include "ui/events/event.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/skia_util.h" #include "ui/gl/gl_surface.h" #if defined(USE_X11) @@ -63,6 +64,14 @@ void OnCaptureLost() override {} void OnPaint(gfx::Canvas* canvas) override { canvas->DrawColor(color_, SkXfermode::kSrc_Mode); + gfx::Rect r; + canvas->GetClipBounds(&r); + // Fill with a non-solid color so that the compositor will exercise its + // texture upload path. + while (!r.IsEmpty()) { + r.Inset(2, 2); + canvas->FillRect(r, color_, SkXfermode::kXor_Mode); + } } void OnDeviceScaleFactorChanged(float device_scale_factor) override {} void OnWindowDestroying(aura::Window* window) override {}
diff --git a/ui/aura/env.cc b/ui/aura/env.cc index d205ae98..4d2db40d 100644 --- a/ui/aura/env.cc +++ b/ui/aura/env.cc
@@ -43,6 +43,11 @@ } // static +Env* Env::GetInstanceDontCreate() { + return lazy_tls_ptr.Pointer()->Get(); +} + +// static void Env::DeleteInstance() { delete lazy_tls_ptr.Pointer()->Get(); }
diff --git a/ui/aura/env.h b/ui/aura/env.h index 4ae2d694..9b84c3b 100644 --- a/ui/aura/env.h +++ b/ui/aura/env.h
@@ -37,6 +37,7 @@ // nativeviewportservice lives in the same process as the viewmanager. static void CreateInstance(bool create_event_source); static Env* GetInstance(); + static Env* GetInstanceDontCreate(); static void DeleteInstance(); void AddObserver(EnvObserver* observer);
diff --git a/ui/aura/window_tree_host_ozone.cc b/ui/aura/window_tree_host_ozone.cc index 0b6df97..1559c24 100644 --- a/ui/aura/window_tree_host_ozone.cc +++ b/ui/aura/window_tree_host_ozone.cc
@@ -4,6 +4,7 @@ #include "ui/aura/window_tree_host_ozone.h" +#include "base/trace_event/trace_event.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/ozone/public/ozone_platform.h" #include "ui/platform_window/platform_window.h" @@ -81,6 +82,7 @@ } void WindowTreeHostOzone::DispatchEvent(ui::Event* event) { + TRACE_EVENT0("input", "WindowTreeHostOzone::DispatchEvent"); SendEventToProcessor(event); }
diff --git a/ui/aura/window_tree_host_x11.cc b/ui/aura/window_tree_host_x11.cc index 8b8da8e..0fb463e 100644 --- a/ui/aura/window_tree_host_x11.cc +++ b/ui/aura/window_tree_host_x11.cc
@@ -150,38 +150,15 @@ const int resolution_x = bounds.width(); const int resolution_y = bounds.height(); - // The "grace area" (10% in this case) is to make it easier for the user to - // navigate to the corner. - const double kGraceAreaFraction = 0.1; if (left_ || right_) { // Offset the x position to the real x -= left_; - // Check if we are in the grace area of the left side. - // Note: We might not want to do this when the gesture is locked? - if (x < 0 && x > -left_ * kGraceAreaFraction) - x = 0; - // Check if we are in the grace area of the right side. - // Note: We might not want to do this when the gesture is locked? - if (x > resolution_x - left_ && - x < resolution_x - left_ + right_ * kGraceAreaFraction) - x = resolution_x - left_; // Scale the screen area back to the full resolution of the screen. x = (x * resolution_x) / (resolution_x - (right_ + left_)); } if (top_ || bottom_) { // When there is a top bezel we add our border, y -= top_; - - // Check if we are in the grace area of the top side. - // Note: We might not want to do this when the gesture is locked? - if (y < 0 && y > -top_ * kGraceAreaFraction) - y = 0; - - // Check if we are in the grace area of the bottom side. - // Note: We might not want to do this when the gesture is locked? - if (y > resolution_y - top_ && - y < resolution_y - top_ + bottom_ * kGraceAreaFraction) - y = resolution_y - top_; // Scale the screen area back to the full resolution of the screen. y = (y * resolution_y) / (resolution_y - (bottom_ + top_)); }
diff --git a/ui/base/l10n/l10n_util.cc b/ui/base/l10n/l10n_util.cc index 80afb84..354db4b 100644 --- a/ui/base/l10n/l10n_util.cc +++ b/ui/base/l10n/l10n_util.cc
@@ -529,6 +529,8 @@ locale_code = "zh-Hant"; else if (locale_code == "tl") locale_code = "fil"; + else if (locale_code == "mo") + locale_code = "ro-MD"; base::string16 display_name; #if defined(OS_ANDROID)
diff --git a/ui/base/l10n/l10n_util_unittest.cc b/ui/base/l10n/l10n_util_unittest.cc index 6474740..43c9ad4 100644 --- a/ui/base/l10n/l10n_util_unittest.cc +++ b/ui/base/l10n/l10n_util_unittest.cc
@@ -453,6 +453,9 @@ result = l10n_util::GetDisplayNameForLocale("es-419", "en", false); EXPECT_EQ(ASCIIToUTF16("Spanish (Latin America)"), result); + result = l10n_util::GetDisplayNameForLocale("mo", "en", false); + EXPECT_EQ(l10n_util::GetDisplayNameForLocale("ro-MD", "en", false), result); + result = l10n_util::GetDisplayNameForLocale("-BR", "en", false); EXPECT_EQ(ASCIIToUTF16("Brazil"), result);
diff --git a/ui/chromeos/BUILD.gn b/ui/chromeos/BUILD.gn index a25e2813..7ec3dc86 100644 --- a/ui/chromeos/BUILD.gn +++ b/ui/chromeos/BUILD.gn
@@ -46,6 +46,7 @@ "//base/third_party/dynamic_annotations", "//chromeos:chromeos", "//chromeos:power_manager_proto", + "//components/device_event_log", "//skia", "//ui/aura", "//ui/base",
diff --git a/ui/events/cocoa/events_mac.mm b/ui/events/cocoa/events_mac.mm index d21184cc..64eb972e 100644 --- a/ui/events/cocoa/events_mac.mm +++ b/ui/events/cocoa/events_mac.mm
@@ -52,9 +52,10 @@ return ET_MOUSE_EXITED; case NSEventTypeSwipe: return ET_SCROLL_FLING_START; - case NSFlagsChanged: case NSAppKitDefined: case NSSystemDefined: + return ET_UNKNOWN; + case NSFlagsChanged: case NSApplicationDefined: case NSPeriodic: case NSCursorUpdate:
diff --git a/ui/events/devices/device_data_manager.cc b/ui/events/devices/device_data_manager.cc index eb96c46..fdf9956 100644 --- a/ui/events/devices/device_data_manager.cc +++ b/ui/events/devices/device_data_manager.cc
@@ -151,6 +151,14 @@ void DeviceDataManager::OnMouseDevicesUpdated( const std::vector<InputDevice>& devices) { + if (devices.size() == mouse_devices_.size() && + std::equal(devices.begin(), + devices.end(), + mouse_devices_.begin(), + InputDeviceEquals)) { + return; + } + mouse_devices_ = devices; FOR_EACH_OBSERVER(InputDeviceEventObserver, observers_, OnMouseDeviceConfigurationChanged()); @@ -158,6 +166,14 @@ void DeviceDataManager::OnTouchpadDevicesUpdated( const std::vector<InputDevice>& devices) { + if (devices.size() == touchpad_devices_.size() && + std::equal(devices.begin(), + devices.end(), + touchpad_devices_.begin(), + InputDeviceEquals)) { + return; + } + touchpad_devices_ = devices; FOR_EACH_OBSERVER(InputDeviceEventObserver, observers_, OnTouchpadDeviceConfigurationChanged());
diff --git a/ui/events/devices/device_data_manager.h b/ui/events/devices/device_data_manager.h index 4896ad86..a0c05ba6 100644 --- a/ui/events/devices/device_data_manager.h +++ b/ui/events/devices/device_data_manager.h
@@ -83,6 +83,8 @@ std::vector<TouchscreenDevice> touchscreen_devices_; std::vector<KeyboardDevice> keyboard_devices_; + std::vector<InputDevice> mouse_devices_; + std::vector<InputDevice> touchpad_devices_; ObserverList<InputDeviceEventObserver> observers_;
diff --git a/ui/events/ozone/evdev/event_converter_evdev.cc b/ui/events/ozone/evdev/event_converter_evdev.cc index b13bdff..eda2e88 100644 --- a/ui/events/ozone/evdev/event_converter_evdev.cc +++ b/ui/events/ozone/evdev/event_converter_evdev.cc
@@ -30,6 +30,8 @@ } void EventConverterEvdev::Stop() { + // TODO(spang): If we reach here due to an error, we should treat it + // as if we have lost sync & release held keys, etc. controller_.StopWatchingFileDescriptor(); } @@ -53,6 +55,10 @@ return false; } +bool EventConverterEvdev::HasCapsLockLed() const { + return false; +} + gfx::Size EventConverterEvdev::GetTouchscreenSize() const { NOTREACHED(); return gfx::Size(); @@ -72,6 +78,33 @@ NOTREACHED(); } +void EventConverterEvdev::SetCapsLockLed(bool enabled) { + if (!HasCapsLockLed()) + return; + + input_event events[2]; + memset(&events, 0, sizeof(events)); + + events[0].type = EV_LED; + events[0].code = LED_CAPSL; + events[0].value = enabled; + + events[1].type = EV_SYN; + events[1].code = SYN_REPORT; + events[1].value = 0; + + ssize_t written = write(fd_, events, sizeof(events)); + + if (written < 0) { + if (errno != ENODEV) + PLOG(ERROR) << "cannot set leds for " << path_.value() << ":"; + Stop(); + } else if (written != sizeof(events)) { + LOG(ERROR) << "short write setting leds for " << path_.value(); + Stop(); + } +} + base::TimeDelta EventConverterEvdev::TimeDeltaFromInputEvent( const input_event& event) { return base::TimeDelta::FromMicroseconds(event.time.tv_sec * 1000000 +
diff --git a/ui/events/ozone/evdev/event_converter_evdev.h b/ui/events/ozone/evdev/event_converter_evdev.h index 4e78d84c..3ca5f0bc 100644 --- a/ui/events/ozone/evdev/event_converter_evdev.h +++ b/ui/events/ozone/evdev/event_converter_evdev.h
@@ -55,6 +55,9 @@ // Returns true if the converter is used for a touchscreen device. virtual bool HasTouchscreen() const; + // Returns true if the converter is used for a device with a caps lock LED. + virtual bool HasCapsLockLed() const; + // Returns the size of the touchscreen device if the converter is used for a // touchscreen device. virtual gfx::Size GetTouchscreenSize() const; @@ -69,6 +72,9 @@ // Allows all keys to be processed. virtual void AllowAllKeys(); + // Update caps lock LED state. + virtual void SetCapsLockLed(bool enabled); + // Helper to generate a base::TimeDelta from an input_event's time static base::TimeDelta TimeDeltaFromInputEvent(const input_event& event);
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.cc b/ui/events/ozone/evdev/event_converter_evdev_impl.cc index ef1a4c5..feaab9a3 100644 --- a/ui/events/ozone/evdev/event_converter_evdev_impl.cc +++ b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
@@ -33,6 +33,7 @@ : EventConverterEvdev(fd, path, id, type), has_keyboard_(devinfo.HasKeyboard()), has_touchpad_(devinfo.HasTouchpad()), + has_caps_lock_led_(devinfo.HasLedEvent(LED_CAPSL)), x_offset_(0), y_offset_(0), cursor_(cursor), @@ -73,6 +74,10 @@ return has_touchpad_; } +bool EventConverterEvdevImpl::HasCapsLockLed() const { + return has_caps_lock_led_; +} + void EventConverterEvdevImpl::SetAllowedKeys( scoped_ptr<std::set<DomCode>> allowed_keys) { DCHECK(HasKeyboard());
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.h b/ui/events/ozone/evdev/event_converter_evdev_impl.h index b04a07d..76e86747 100644 --- a/ui/events/ozone/evdev/event_converter_evdev_impl.h +++ b/ui/events/ozone/evdev/event_converter_evdev_impl.h
@@ -41,6 +41,7 @@ void OnFileCanReadWithoutBlocking(int fd) override; bool HasKeyboard() const override; bool HasTouchpad() const override; + bool HasCapsLockLed() const override; void SetAllowedKeys(scoped_ptr<std::set<DomCode>> allowed_keys) override; void AllowAllKeys() override; @@ -61,6 +62,9 @@ bool has_keyboard_; bool has_touchpad_; + // LEDs for this device. + bool has_caps_lock_led_; + // Save x-axis events of relative devices to be flushed at EV_SYN time. int x_offset_;
diff --git a/ui/events/ozone/evdev/event_modifiers_evdev.cc b/ui/events/ozone/evdev/event_modifiers_evdev.cc index 70a6250..8ead0db 100644 --- a/ui/events/ozone/evdev/event_modifiers_evdev.cc +++ b/ui/events/ozone/evdev/event_modifiers_evdev.cc
@@ -55,8 +55,6 @@ if (down) modifier_flags_locked_ ^= kEventFlagFromModifiers[modifier]; - // TODO(spang): Synchronize with the CapsLock LED. - UpdateFlags(modifier); } @@ -68,8 +66,6 @@ else modifier_flags_locked_ &= ~kEventFlagFromModifiers[modifier]; - // TODO(spang): Synchronize with the CapsLock LED. - UpdateFlags(modifier); }
diff --git a/ui/events/ozone/evdev/input_controller_evdev.cc b/ui/events/ozone/evdev/input_controller_evdev.cc index 19c728b..9e65740 100644 --- a/ui/events/ozone/evdev/input_controller_evdev.cc +++ b/ui/events/ozone/evdev/input_controller_evdev.cc
@@ -22,6 +22,7 @@ button_map_(button_map), has_mouse_(false), has_touchpad_(false), + caps_lock_led_state_(false), weak_ptr_factory_(this) { } @@ -33,6 +34,7 @@ input_device_factory_ = input_device_factory; UpdateDeviceSettings(); + UpdateCapsLockLed(); } void InputControllerEvdev::set_has_mouse(bool has_mouse) { @@ -57,6 +59,7 @@ void InputControllerEvdev::SetCapsLockEnabled(bool enabled) { keyboard_->SetCapsLockEnabled(enabled); + UpdateCapsLockLed(); } void InputControllerEvdev::SetNumLockEnabled(bool enabled) { @@ -178,4 +181,13 @@ settings_update_pending_ = false; } +void InputControllerEvdev::UpdateCapsLockLed() { + if (!input_device_factory_) + return; + bool caps_lock_state = IsCapsLockEnabled(); + if (caps_lock_state != caps_lock_led_state_) + input_device_factory_->SetCapsLockLed(caps_lock_state); + caps_lock_led_state_ = caps_lock_state; +} + } // namespace ui
diff --git a/ui/events/ozone/evdev/input_controller_evdev.h b/ui/events/ozone/evdev/input_controller_evdev.h index ecd08a0..8791a77 100644 --- a/ui/events/ozone/evdev/input_controller_evdev.h +++ b/ui/events/ozone/evdev/input_controller_evdev.h
@@ -70,6 +70,9 @@ // Send settings update to input_device_factory_. void UpdateDeviceSettings(); + // Send caps lock update to input_device_factory_. + void UpdateCapsLockLed(); + // Configuration that needs to be passed on to InputDeviceFactory. InputDeviceSettingsEvdev input_device_settings_; @@ -89,6 +92,9 @@ bool has_mouse_; bool has_touchpad_; + // LED state. + bool caps_lock_led_state_; + base::WeakPtrFactory<InputControllerEvdev> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(InputControllerEvdev);
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.cc b/ui/events/ozone/evdev/input_device_factory_evdev.cc index e2140f66..c9d0baa 100644 --- a/ui/events/ozone/evdev/input_device_factory_evdev.cc +++ b/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -142,7 +142,7 @@ TRACE_EVENT1("ozone", "OpenInputDevice", "path", path.value()); - int fd = open(path.value().c_str(), O_RDONLY | O_NONBLOCK); + int fd = open(path.value().c_str(), O_RDWR | O_NONBLOCK); if (fd < 0) { PLOG(ERROR) << "Cannot open '" << path.value(); reply_runner->PostTask( @@ -200,6 +200,7 @@ keyboard_list_dirty_(false), mouse_list_dirty_(false), touchpad_list_dirty_(false), + caps_lock_led_enabled_(false), weak_ptr_factory_(this) { } @@ -229,7 +230,7 @@ base::WorkerPool::PostTask(FROM_HERE, base::Bind(&OpenInputDevice, base::Passed(¶ms), task_runner_, reply_callback), - true /* task_is_slow */); + false /* task_is_slow */); } void InputDeviceFactoryEvdev::RemoveInputDevice(const base::FilePath& path) { @@ -256,6 +257,7 @@ // Sync settings to new device. ApplyInputDeviceSettings(); + ApplyCapsLockLed(); } if (--pending_device_changes_ == 0) @@ -328,6 +330,11 @@ } } +void InputDeviceFactoryEvdev::SetCapsLockLed(bool enabled) { + caps_lock_led_enabled_ = enabled; + ApplyCapsLockLed(); +} + void InputDeviceFactoryEvdev::UpdateInputDeviceSettings( const InputDeviceSettingsEvdev& settings) { input_device_settings_ = settings; @@ -385,6 +392,13 @@ input_device_settings_.tap_to_click_paused); } +void InputDeviceFactoryEvdev::ApplyCapsLockLed() { + for (const auto& it : converters_) { + EventConverterEvdev* converter = it.second; + converter->SetCapsLockLed(caps_lock_led_enabled_); + } +} + void InputDeviceFactoryEvdev::UpdateDirtyFlags( const EventConverterEvdev* converter) { if (converter->HasTouchscreen())
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.h b/ui/events/ozone/evdev/input_device_factory_evdev.h index 58acdc2..976de0dd7 100644 --- a/ui/events/ozone/evdev/input_device_factory_evdev.h +++ b/ui/events/ozone/evdev/input_device_factory_evdev.h
@@ -63,6 +63,9 @@ // Enables all keys on the internal keyboard. void EnableInternalKeyboard(); + // LED state. + void SetCapsLockLed(bool enabled); + // Bits from InputController that have to be answered on IO. void UpdateInputDeviceSettings(const InputDeviceSettingsEvdev& settings); void GetTouchDeviceStatus(const GetTouchDeviceStatusReply& reply); @@ -80,6 +83,7 @@ // Sync input_device_settings_ to attached devices. void ApplyInputDeviceSettings(); + void ApplyCapsLockLed(); // Update observers on device changes. void UpdateDirtyFlags(const EventConverterEvdev* converter); @@ -120,6 +124,9 @@ bool mouse_list_dirty_; bool touchpad_list_dirty_; + // LEDs. + bool caps_lock_led_enabled_; + // Device settings. These primarily affect libgestures behavior. InputDeviceSettingsEvdev input_device_settings_;
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc b/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc index cc23da3..2bade2f 100644 --- a/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc +++ b/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc
@@ -80,6 +80,12 @@ input_device_factory_)); } +void InputDeviceFactoryEvdevProxy::SetCapsLockLed(bool enabled) { + task_runner_->PostTask(FROM_HERE, + base::Bind(&InputDeviceFactoryEvdev::SetCapsLockLed, + input_device_factory_, enabled)); +} + void InputDeviceFactoryEvdevProxy::UpdateInputDeviceSettings( const InputDeviceSettingsEvdev& settings) { task_runner_->PostTask(
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev_proxy.h b/ui/events/ozone/evdev/input_device_factory_evdev_proxy.h index 0268b5dd..3cabdc4e 100644 --- a/ui/events/ozone/evdev/input_device_factory_evdev_proxy.h +++ b/ui/events/ozone/evdev/input_device_factory_evdev_proxy.h
@@ -45,6 +45,7 @@ void DisableInternalKeyboardExceptKeys( scoped_ptr<std::set<DomCode>> excepted_keys); void EnableInternalKeyboard(); + void SetCapsLockLed(bool enabled); void UpdateInputDeviceSettings(const InputDeviceSettingsEvdev& settings); void GetTouchDeviceStatus(const GetTouchDeviceStatusReply& reply); void GetTouchEventLog(const base::FilePath& out_dir,
diff --git a/ui/events/ozone/evdev/keyboard_evdev.h b/ui/events/ozone/evdev/keyboard_evdev.h index 7974a95..f536e3d 100644 --- a/ui/events/ozone/evdev/keyboard_evdev.h +++ b/ui/events/ozone/evdev/keyboard_evdev.h
@@ -52,6 +52,7 @@ private: void UpdateModifier(int modifier_flag, bool down); + void UpdateCapsLockLed(); void UpdateKeyRepeat(unsigned int key, bool down); void StartKeyRepeat(unsigned int key); void StopKeyRepeat();
diff --git a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc index 4f4dac5..e2cadeca 100644 --- a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc +++ b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
@@ -35,6 +35,7 @@ has_keyboard_(devinfo.HasKeyboard()), has_mouse_(devinfo.HasMouse()), has_touchpad_(devinfo.HasTouchpad()), + has_caps_lock_led_(devinfo.HasLedEvent(LED_CAPSL)), delegate_(delegate.Pass()) { memset(&evdev_, 0, sizeof(evdev_)); evdev_.log = OnLogMessage; @@ -82,6 +83,10 @@ return has_touchpad_; } +bool EventReaderLibevdevCros::HasCapsLockLed() const { + return has_caps_lock_led_; +} + void EventReaderLibevdevCros::SetAllowedKeys( scoped_ptr<std::set<DomCode>> allowed_keys) { DCHECK(HasKeyboard());
diff --git a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h index 2579cb5..0e17325 100644 --- a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h +++ b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h
@@ -48,13 +48,14 @@ InputDeviceType type, const EventDeviceInfo& devinfo, scoped_ptr<Delegate> delegate); - ~EventReaderLibevdevCros(); + ~EventReaderLibevdevCros() override; // EventConverterEvdev: void OnFileCanReadWithoutBlocking(int fd) override; bool HasKeyboard() const override; bool HasMouse() const override; bool HasTouchpad() const override; + bool HasCapsLockLed() const override; void SetAllowedKeys(scoped_ptr<std::set<DomCode>> allowed_keys) override; void AllowAllKeys() override; @@ -69,6 +70,9 @@ bool has_mouse_; bool has_touchpad_; + // LEDs for this device. + bool has_caps_lock_led_; + // Libevdev state. Evdev evdev_;
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_feedback.cc b/ui/events/ozone/evdev/libgestures_glue/gesture_feedback.cc index 25ce024..dd329dc 100644 --- a/ui/events/ozone/evdev/libgestures_glue/gesture_feedback.cc +++ b/ui/events/ozone/evdev/libgestures_glue/gesture_feedback.cc
@@ -23,7 +23,6 @@ // Binary paths. const char kGzipCommand[] = "/bin/gzip"; -const char kDateCommand[] = "/bin/date"; const size_t kTouchLogTimestampMaxSize = 80;
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 393cb8e1..b5fc0d9 100644 --- a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc +++ b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc
@@ -680,7 +680,6 @@ public: explicit MatchDeviceType(const std::string& arg); ~MatchDeviceType() override {} - virtual bool Match(const DevicePtr device) = 0; protected: bool value_;
diff --git a/ui/events/platform/x11/x11_hotplug_event_handler.cc b/ui/events/platform/x11/x11_hotplug_event_handler.cc index ddd3aec..fcac274 100644 --- a/ui/events/platform/x11/x11_hotplug_event_handler.cc +++ b/ui/events/platform/x11/x11_hotplug_event_handler.cc
@@ -46,20 +46,37 @@ const char* kCachedAtomList[] = { "Abs MT Position X", "Abs MT Position Y", + XI_KEYBOARD, + XI_MOUSE, + XI_TOUCHPAD, + XI_TOUCHSCREEN, NULL, }; +enum DeviceType { + DEVICE_TYPE_KEYBOARD, + DEVICE_TYPE_MOUSE, + DEVICE_TYPE_TOUCHPAD, + DEVICE_TYPE_TOUCHSCREEN, + DEVICE_TYPE_OTHER +}; + typedef base::Callback<void(const std::vector<KeyboardDevice>&)> KeyboardDeviceCallback; typedef base::Callback<void(const std::vector<TouchscreenDevice>&)> TouchscreenDeviceCallback; +typedef base::Callback<void(const std::vector<InputDevice>&)> + InputDeviceCallback; + // Used for updating the state on the UI thread once device information is // parsed on helper threads. struct UiCallbacks { KeyboardDeviceCallback keyboard_callback; TouchscreenDeviceCallback touchscreen_callback; + InputDeviceCallback mouse_callback; + InputDeviceCallback touchpad_callback; }; // Stores a copy of the XIValuatorClassInfo values so X11 device processing can @@ -92,11 +109,13 @@ }; struct DeviceInfo { - DeviceInfo(const XIDeviceInfo& device, const base::FilePath& path) + DeviceInfo(const XIDeviceInfo& device, + DeviceType type, + const base::FilePath& path) : id(device.deviceid), name(device.name), use(device.use), - enabled(device.enabled), + type(type), path(path) { for (int i = 0; i < device.num_classes; ++i) { switch (device.classes[i]->type) { @@ -126,8 +145,8 @@ // Device type (ie: XIMasterPointer) int use; - // Specifies if the device is enabled and can send events. - bool enabled; + // Specifies the type of the device. + DeviceType type; // Path to the actual device (ie: /dev/input/eventXX) base::FilePath path; @@ -147,8 +166,10 @@ // Returns true if |name| is the name of a known invalid keyboard device. Note, // this may return false negatives. bool IsKnownInvalidKeyboardDevice(const std::string& name) { + std::string trimmed(name); + base::TrimWhitespaceASCII(name, base::TRIM_TRAILING, &trimmed); for (const char* device_name : kKnownInvalidKeyboardDeviceNames) { - if (name == device_name) + if (trimmed == device_name) return true; } return false; @@ -156,7 +177,7 @@ // Returns true if |name| is the name of a known XTEST device. Note, this may // return false negatives. -bool IsTestKeyboard(const std::string& name) { +bool IsTestDevice(const std::string& name) { return name.find("XTEST") != std::string::npos; } @@ -216,13 +237,11 @@ std::vector<KeyboardDevice> devices; for (const DeviceInfo& device_info : device_infos) { - if (!device_info.enabled || device_info.use != XISlaveKeyboard) + if (device_info.type != DEVICE_TYPE_KEYBOARD) + continue; + if (device_info.use != XISlaveKeyboard) continue; // Assume all keyboards are keyboard slaves - std::string device_name(device_info.name); - base::TrimWhitespaceASCII(device_name, base::TRIM_TRAILING, &device_name); - if (IsTestKeyboard(device_name)) - continue; // Skip test devices. - if (IsKnownInvalidKeyboardDevice(device_name)) + if (IsKnownInvalidKeyboardDevice(device_info.name)) continue; // Skip invalid devices. InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path); devices.push_back(KeyboardDevice(device_info.id, type)); @@ -231,6 +250,44 @@ reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); } +// Helper used to parse mouse information. When it is done it uses +// |reply_runner| and |callback| to update the state on the UI thread. +void HandleMouseDevicesInWorker(const std::vector<DeviceInfo>& device_infos, + scoped_refptr<base::TaskRunner> reply_runner, + const InputDeviceCallback& callback) { + std::vector<InputDevice> devices; + for (const DeviceInfo& device_info : device_infos) { + if (device_info.type != DEVICE_TYPE_MOUSE || + device_info.use != XISlavePointer) { + continue; + } + + InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path); + devices.push_back(InputDevice(device_info.id, type)); + } + + reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); +} + +// Helper used to parse touchpad information. When it is done it uses +// |reply_runner| and |callback| to update the state on the UI thread. +void HandleTouchpadDevicesInWorker(const std::vector<DeviceInfo>& device_infos, + scoped_refptr<base::TaskRunner> reply_runner, + const InputDeviceCallback& callback) { + std::vector<InputDevice> devices; + for (const DeviceInfo& device_info : device_infos) { + if (device_info.type != DEVICE_TYPE_TOUCHPAD || + device_info.use != XISlavePointer) { + continue; + } + + InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path); + devices.push_back(InputDevice(device_info.id, type)); + } + + reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); +} + // Helper used to parse touchscreen information. When it is done it uses // |reply_runner| and |callback| to update the state on the UI thread. void HandleTouchscreenDevicesInWorker( @@ -243,15 +300,19 @@ display_state.mt_position_y == None) return; - std::set<int> no_match_touchscreen; for (const DeviceInfo& device_info : device_infos) { - if (!device_info.enabled || (device_info.use != XIFloatingSlave - && device_info.use != XISlavePointer)) + if (device_info.type != DEVICE_TYPE_TOUCHSCREEN || + (device_info.use != XIFloatingSlave && + device_info.use != XISlavePointer)) { + continue; + } + + // Touchscreens should be direct touch devices. + if (device_info.touch_class_info.mode != XIDirectTouch) continue; double max_x = -1.0; double max_y = -1.0; - bool is_direct_touch = false; for (const ValuatorClassInfo& valuator : device_info.valuator_class_infos) { if (display_state.mt_position_x == valuator.label) { @@ -269,12 +330,8 @@ } } - if (device_info.touch_class_info.mode) - is_direct_touch = device_info.touch_class_info.mode == XIDirectTouch; - - // Touchscreens should have absolute X and Y axes, and be direct touch - // devices. - if (max_x > 0.0 && max_y > 0.0 && is_direct_touch) { + // Touchscreens should have absolute X and Y axes. + if (max_x > 0.0 && max_y > 0.0) { InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path); // |max_x| and |max_y| are inclusive values, so we need to add 1 to get // the size. @@ -297,6 +354,9 @@ devices, display_state, reply_runner, callbacks.touchscreen_callback); HandleKeyboardDevicesInWorker( devices, reply_runner, callbacks.keyboard_callback); + HandleMouseDevicesInWorker(devices, reply_runner, callbacks.mouse_callback); + HandleTouchpadDevicesInWorker(devices, reply_runner, + callbacks.touchpad_callback); } DeviceHotplugEventObserver* GetHotplugEventObserver() { @@ -311,6 +371,14 @@ GetHotplugEventObserver()->OnTouchscreenDevicesUpdated(devices); } +void OnMouseDevices(const std::vector<InputDevice>& devices) { + GetHotplugEventObserver()->OnMouseDevicesUpdated(devices); +} + +void OnTouchpadDevices(const std::vector<InputDevice>& devices) { + GetHotplugEventObserver()->OnTouchpadDevicesUpdated(devices); +} + } // namespace X11HotplugEventHandler::X11HotplugEventHandler() @@ -321,14 +389,45 @@ } void X11HotplugEventHandler::OnHotplugEvent() { - const XIDeviceList& device_list = - DeviceListCacheX11::GetInstance()->GetXI2DeviceList(gfx::GetXDisplay()); Display* display = gfx::GetXDisplay(); + const XDeviceList& device_list_xi = + DeviceListCacheX11::GetInstance()->GetXDeviceList(display); + const XIDeviceList& device_list_xi2 = + DeviceListCacheX11::GetInstance()->GetXI2DeviceList(display); + + const int kMaxDeviceNum = 128; + DeviceType device_types[kMaxDeviceNum]; + for (int i = 0; i < kMaxDeviceNum; ++i) + device_types[i] = DEVICE_TYPE_OTHER; + + for (int i = 0; i < device_list_xi.count; ++i) { + int id = device_list_xi[i].id; + if (id < 0 || id >= kMaxDeviceNum) + continue; + + Atom type = device_list_xi[i].type; + if (type == atom_cache_.GetAtom(XI_KEYBOARD)) + device_types[id] = DEVICE_TYPE_KEYBOARD; + else if (type == atom_cache_.GetAtom(XI_MOUSE)) + device_types[id] = DEVICE_TYPE_MOUSE; + else if (type == atom_cache_.GetAtom(XI_TOUCHPAD)) + device_types[id] = DEVICE_TYPE_TOUCHPAD; + else if (type == atom_cache_.GetAtom(XI_TOUCHSCREEN)) + device_types[id] = DEVICE_TYPE_TOUCHSCREEN; + } std::vector<DeviceInfo> device_infos; - for (int i = 0; i < device_list.count; ++i) { - const XIDeviceInfo& device = device_list[i]; - device_infos.push_back(DeviceInfo(device, GetDevicePath(display, device))); + for (int i = 0; i < device_list_xi2.count; ++i) { + const XIDeviceInfo& device = device_list_xi2[i]; + if (!device.enabled || IsTestDevice(device.name)) + continue; + + DeviceType device_type = + (device.deviceid >= 0 && device.deviceid < kMaxDeviceNum) + ? device_types[device.deviceid] + : DEVICE_TYPE_OTHER; + device_infos.push_back( + DeviceInfo(device, device_type, GetDevicePath(display, device))); } // X11 is not thread safe, so first get all the required state. @@ -339,8 +438,8 @@ UiCallbacks callbacks; callbacks.keyboard_callback = base::Bind(&OnKeyboardDevices); callbacks.touchscreen_callback = base::Bind(&OnTouchscreenDevices); - // TODO(pkotwicz): Compute the lists of mice and touchpads and send the new - // lists to DeviceHotplugEventObserver. + callbacks.mouse_callback = base::Bind(&OnMouseDevices); + callbacks.touchpad_callback = base::Bind(&OnTouchpadDevices); // Parsing the device information may block, so delegate the operation to a // worker thread. Once the device information is extracted the parsed devices
diff --git a/ui/file_manager/audio_player/audio_player.html b/ui/file_manager/audio_player/audio_player.html index 3d95596..0b225f9 100644 --- a/ui/file_manager/audio_player/audio_player.html +++ b/ui/file_manager/audio_player/audio_player.html
@@ -40,10 +40,11 @@ <script src="../file_manager/foreground/js/metadata/content_metadata_provider.js"></script> <script src="../file_manager/foreground/js/metadata/external_metadata_provider.js"></script> - <script src="../file_manager/foreground/js/metadata/file_system_metadata.js"></script> <script src="../file_manager/foreground/js/metadata/file_system_metadata_provider.js"></script> <script src="../file_manager/foreground/js/metadata/metadata_cache_item.js"></script> <script src="../file_manager/foreground/js/metadata/metadata_item.js"></script> + <script src="../file_manager/foreground/js/metadata/metadata_model.js"></script> + <script src="../file_manager/foreground/js/metadata/multi_metadata_provider.js"></script> <script src="../file_manager/foreground/js/metadata/thumbnail_model.js"></script> <script src="js/audio_player.js"></script>
diff --git a/ui/file_manager/audio_player/js/audio_player.js b/ui/file_manager/audio_player/js/audio_player.js index f5e172d..a4d81efd 100644 --- a/ui/file_manager/audio_player/js/audio_player.js +++ b/ui/file_manager/audio_player/js/audio_player.js
@@ -17,8 +17,7 @@ this.container_ = container; this.volumeManager_ = new VolumeManagerWrapper( VolumeManagerWrapper.DriveEnabledStatus.DRIVE_ENABLED); - this.fileSystemMetadata_ = FileSystemMetadata.create( - new MetadataProviderCache(), this.volumeManager_); + this.metadataModel_ = new MetadataModel.create(this.volumeManager_); this.selectedEntry_ = null; this.model_ = new AudioPlayerModel(); @@ -238,7 +237,7 @@ * @private */ AudioPlayer.prototype.fetchMetadata_ = function(entry, callback) { - this.fileSystemMetadata_.get( + this.metadataModel_.get( [entry], ['mediaTitle', 'mediaArtist', 'present']).then( function(generation, metadata) { // Do nothing if another load happened since the metadata request.
diff --git a/ui/file_manager/audio_player/js/audio_player_scripts.js b/ui/file_manager/audio_player/js/audio_player_scripts.js index a4d5a978..db67180 100644 --- a/ui/file_manager/audio_player/js/audio_player_scripts.js +++ b/ui/file_manager/audio_player/js/audio_player_scripts.js
@@ -35,10 +35,11 @@ <include src="../../file_manager/foreground/js/metadata/content_metadata_provider.js"> <include src="../../file_manager/foreground/js/metadata/external_metadata_provider.js"> -<include src="../../file_manager/foreground/js/metadata/file_system_metadata.js"> <include src="../../file_manager/foreground/js/metadata/file_system_metadata_provider.js"> <include src="../../file_manager/foreground/js/metadata/metadata_cache_item.js"> <include src="../../file_manager/foreground/js/metadata/metadata_item.js"> +<include src="../../file_manager/foreground/js/metadata/metadata_model.js"> +<include src="../../file_manager/foreground/js/metadata/multi_metadata_provider.js"> <include src="../../file_manager/foreground/js/metadata/thumbnail_model.js"> <include src="audio_player.js"/>
diff --git a/ui/file_manager/audio_player/js/background.js b/ui/file_manager/audio_player/js/background.js index 073ffeb..edc25e5d 100644 --- a/ui/file_manager/audio_player/js/background.js +++ b/ui/file_manager/audio_player/js/background.js
@@ -105,7 +105,8 @@ /** * Opens player window. * @param {Object} playlist List of audios to play and index to start playing. - * @param {Promise} Promise to be fulfilled on success, or rejected on error. + * @param {boolean} reopen + * @return {Promise} Promise to be fulfilled on success, or rejected on error. */ function open(playlist, reopen) { var items = playlist.items; @@ -152,7 +153,9 @@ // Opens the audio player panel. return new Promise(function(fulfill, reject) { var urls = util.entriesToURLs(audioEntries); - audioPlayer.launch({items: urls, position: position}, reopen, fulfill); + audioPlayer.launch({items: urls, position: position}, + reopen, + fulfill.bind(null, null)); }); }).then(function() { audioPlayer.setIcon('icons/audio-player-64.png');
diff --git a/ui/file_manager/audio_player/js/compiled_resources.gyp b/ui/file_manager/audio_player/js/compiled_resources.gyp new file mode 100644 index 0000000..1f8f6f34 --- /dev/null +++ b/ui/file_manager/audio_player/js/compiled_resources.gyp
@@ -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. +{ + 'targets': [ + { + 'target_name': 'background', + 'variables': { + 'depends': [ + '../../../../third_party/jstemplate/compiled_resources.gyp:jstemplate', + '../../../webui/resources/js/cr.js', + '../../../webui/resources/js/cr/event_target.js', + '../../../webui/resources/js/cr/ui.js', + '../../../webui/resources/js/cr/ui/array_data_model.js', + # Referenced in common/js/util.js. + '../../../webui/resources/js/cr/ui/dialogs.js', + '../../../webui/resources/js/load_time_data.js', + '../../../webui/resources/js/util.js', + '../../file_manager/common/js/util.js', + '../../file_manager/common/js/async_util.js', + '../../file_manager/common/js/file_type.js', + '../../file_manager/common/js/volume_manager_common.js', + '../../file_manager/background/js/app_window_wrapper.js', + '../../file_manager/background/js/background_base.js', + '../../file_manager/background/js/test_util_base.js', + '../../file_manager/background/js/volume_manager.js', + 'error_util.js', + 'background.js', + ], + 'externs': [ + '<(CLOSURE_DIR)/externs/chrome_send_externs.js', + '<(CLOSURE_DIR)/externs/chrome_extensions.js', + '<(CLOSURE_DIR)/externs/file_manager_private.js', + '../../externs/chrome_test.js', + '../../externs/platform.js', + ], + }, + 'includes': [ + '../../../../third_party/closure_compiler/compile_js.gypi' + ], + } + ], +} +
diff --git a/ui/file_manager/audio_player/js/error_util.js b/ui/file_manager/audio_player/js/error_util.js new file mode 100644 index 0000000..38e37f27 --- /dev/null +++ b/ui/file_manager/audio_player/js/error_util.js
@@ -0,0 +1,14 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * This variable is checked in SelectFileDialogExtensionBrowserTest. + * @type {number} + */ +window.JSErrorCount = 0; + +/** + * Counts uncaught exceptions. + */ +window.onerror = function() { window.JSErrorCount++; };
diff --git a/ui/file_manager/audio_player/manifest.json b/ui/file_manager/audio_player/manifest.json index 3e8f278f..263dbdf 100644 --- a/ui/file_manager/audio_player/manifest.json +++ b/ui/file_manager/audio_player/manifest.json
@@ -49,8 +49,11 @@ "scripts": [ "chrome://resources/js/cr.js", "chrome://resources/js/cr/event_target.js", + "chrome://resources/js/cr/ui.js", "chrome://resources/js/cr/ui/array_data_model.js", + "chrome://resources/js/cr/ui/dialogs.js", "chrome://resources/js/load_time_data.js", + "chrome://resources/js/util.js", "chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/common/js/util.js", "chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/common/js/async_util.js", "chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/common/js/file_type.js", @@ -59,6 +62,7 @@ "chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/background/js/background_base.js", "chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/background/js/test_util_base.js", "chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/background/js/volume_manager.js", + "js/error_util.js", // The main background script must be at the end. "js/background.js" ]
diff --git a/ui/file_manager/file_manager/audio_player.html b/ui/file_manager/file_manager/audio_player.html index da8dd98..875cef7b 100644 --- a/ui/file_manager/file_manager/audio_player.html +++ b/ui/file_manager/file_manager/audio_player.html
@@ -33,7 +33,6 @@ <script src="common/js/util.js"></script> <script src="common/js/volume_manager_common.js"></script> <script src="foreground/js/volume_manager_wrapper.js"></script> - <script src="foreground/js/metadata/metadata_cache.js"></script> <script src="audio_player/js/audio_player.js"></script>
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js index 821407c..ff342837 100644 --- a/ui/file_manager/file_manager/common/js/util.js +++ b/ui/file_manager/file_manager/common/js/util.js
@@ -767,7 +767,10 @@ */ util.entriesToURLs = function(entries) { return entries.map(function(entry) { - return entry.toURL(); + // When building background.js, cachedUrl is not refered other than here. + // Thus closure compiler raises an error if we refer the property like + // entry.cachedUrl. + return entry['cachedUrl'] || entry.toURL(); }); };
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css index 3f48669..9ec64fc 100644 --- a/ui/file_manager/file_manager/foreground/css/file_manager.css +++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -301,16 +301,12 @@ rgb(90, 90, 90); } -.dialog-header .icon-button:hover, .dialog-header .icon-button:focus, -.dialog-header .combobutton:hover, .dialog-header .combobutton:focus { background-color: rgba(90, 90, 90, 0.15); } -body.check-select .dialog-header .icon-button:hover, body.check-select .dialog-header .icon-button:focus, -body.check-select .dialog-header .combobutton:hover, body.check-select .dialog-header .combobutton:focus { background-color: rgba(153, 153, 153, 0.20); } @@ -1247,6 +1243,15 @@ } } +@-webkit-keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + /* Table splitter element */ .table-header-splitter { background-image: -webkit-image-set( @@ -1370,24 +1375,32 @@ } #list-container list li .detail-thumbnail { + height: 28px; + overflow: hidden; + position: absolute; + width: 28px; +} + +#list-container list li .detail-thumbnail > .thumbnail { -webkit-user-drag: none; background-color: rgb(245, 245, 245); background-position: center; background-size: cover; border-radius: 14px; - height: 28px; - opacity: 0; - overflow: hidden; - position: absolute; - transition: opacity 220ms ease; - width: 28px; -} - -#list-container list li .detail-thumbnail.loaded { + height: 100%; opacity: 1; + position: absolute; + width: 100%; } -body.check-select #list-container list li[selected] .detail-thumbnail.loaded { +#list-container list li .detail-thumbnail > .thumbnail.animate { + -webkit-animation: fadeIn 220ms ease; +} + +body.check-select #list-container list li[selected] .detail-thumbnail +> .thumbnail { + /* Fade out after checkmark fades in. */ + -webkit-animation: fadeOut 0ms 220ms ease backwards; opacity: 0; }
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 1a651b4..4466c22 100644 --- a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp +++ b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
@@ -89,12 +89,12 @@ './launch_param.js', './metadata/content_metadata_provider.js', './metadata/external_metadata_provider.js', - './metadata/file_system_metadata.js', './metadata/file_system_metadata_provider.js', - './metadata/metadata_cache.js', './metadata/metadata_cache_item.js', './metadata/metadata_cache_set.js', './metadata/metadata_item.js', + './metadata/metadata_model.js', + './metadata/multi_metadata_provider.js', './metadata/new_metadata_provider.js', './metadata/thumbnail_model.js', './metadata_update_controller.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 0505c5d3..aa49006 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
@@ -9,7 +9,7 @@ * @param {DialogType} dialogType Dialog type. * @param {!DialogFooter} dialogFooter Dialog footer. * @param {!DirectoryModel} directoryModel Directory model. - * @param {!FileSystemMetadata} fileSystemMetadata Metadata cache. + * @param {!MetadataModel} metadataModel Metadata cache. * @param {!VolumeManagerWrapper} volumeManager Volume manager. * @param {!FileFilter} fileFilter File filter model. * @param {!NamingController} namingController Naming controller. @@ -23,7 +23,7 @@ dialogType, dialogFooter, directoryModel, - fileSystemMetadata, + metadataModel, volumeManager, fileFilter, namingController, @@ -51,11 +51,11 @@ this.directoryModel_ = directoryModel; /** - * @type {!FileSystemMetadata} + * @type {!MetadataModel} * @const * @private */ - this.fileSystemMetadata_ = fileSystemMetadata; + this.metadataModel_ = metadataModel; /** * @type {!VolumeManagerWrapper} @@ -369,7 +369,7 @@ // TODO(mtomasz): Use Entry instead of URLs, if possible. util.URLsToEntries(selection.urls, function(entries) { - this.fileSystemMetadata_.get(entries, ['present']).then(onProperties); + this.metadataModel_.get(entries, ['present']).then(onProperties); }.bind(this)); };
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js index 9fbab186..8668e66 100644 --- a/ui/file_manager/file_manager/foreground/js/directory_contents.js +++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -393,18 +393,18 @@ /** * File list. - * @param {!FileSystemMetadata} fileSystemMetadata + * @param {!MetadataModel} metadataModel * @constructor * @extends {cr.ui.ArrayDataModel} */ -function FileListModel(fileSystemMetadata) { +function FileListModel(metadataModel) { cr.ui.ArrayDataModel.call(this, []); /** - * @private {!FileSystemMetadata} + * @private {!MetadataModel} * @const */ - this.fileSystemMetadata_ = fileSystemMetadata; + this.metadataModel_ = metadataModel; // Initialize compare functions. this.setCompareFunction('name', @@ -483,7 +483,7 @@ return a.isDirectory === this.isDescendingOrder_ ? 1 : -1; var properties = - this.fileSystemMetadata_.getCache([a, b], ['modificationTime']); + this.metadataModel_.getCache([a, b], ['modificationTime']); var aTime = properties[0].modificationTime || 0; var bTime = properties[1].modificationTime || 0; @@ -508,7 +508,7 @@ if (a.isDirectory !== b.isDirectory) return a.isDirectory === this.isDescendingOrder_ ? 1 : -1; - var properties = this.fileSystemMetadata_.getCache([a, b], ['size']); + var properties = this.metadataModel_.getCache([a, b], ['size']); var aSize = properties[0].size || 0; var bSize = properties[1].size || 0; @@ -539,20 +539,20 @@ * TODO(yoshiki): remove this. crbug.com/224869. * * @param {FileFilter} fileFilter The file-filter context. - * @param {!FileSystemMetadata} fileSystemMetadata + * @param {!MetadataModel} metadataModel * @constructor */ -function FileListContext(fileFilter, fileSystemMetadata) { +function FileListContext(fileFilter, metadataModel) { /** * @type {FileListModel} */ - this.fileList = new FileListModel(fileSystemMetadata); + this.fileList = new FileListModel(metadataModel); /** - * @public {!FileSystemMetadata} + * @public {!MetadataModel} * @const */ - this.fileSystemMetadata = fileSystemMetadata; + this.metadataModel = metadataModel; /** * @type {FileFilter} @@ -580,6 +580,11 @@ for (var i = 0; i < Command.METADATA_PREFETCH_PROPERTY_NAMES.length; i++) { set[Command.METADATA_PREFETCH_PROPERTY_NAMES[i]] = true; } + for (var i = 0; + i < FileSelection.METADATA_PREFETCH_PROPERTY_NAMES.length; + i++) { + set[FileSelection.METADATA_PREFETCH_PROPERTY_NAMES[i]] = true; + } return Object.keys(set); }; @@ -656,7 +661,7 @@ DirectoryContents.prototype.createMetadataSnapshot = function() { var snapshot = {}; var entries = /** @type {!Array<!Entry>} */ (this.fileList_.slice()); - var metadata = this.context_.fileSystemMetadata.getCache( + var metadata = this.context_.metadataModel.getCache( entries, ['modificationTime']); for (var i = 0; i < entries.length; i++) { snapshot[entries[i].toURL()] = metadata[i]; @@ -693,7 +698,7 @@ if (this.metadataSnapshot_) { var updatedIndexes = []; var entries = /** @type {!Array<!Entry>} */ (this.fileList_.slice()); - var newMetadatas = this.context_.fileSystemMetadata.getCache( + var newMetadatas = this.context_.metadataModel.getCache( entries, ['modificationTime']); for (var i = 0; i < entries.length; i++) { @@ -789,6 +794,7 @@ } var updatedList = []; + var updatedIndexes = []; for (var i = 0; i < this.fileList_.length; i++) { var url = this.fileList_.item(i).toURL(); @@ -800,17 +806,21 @@ if (url in updatedMap) { updatedList.push(updatedMap[url]); + updatedIndexes.push(i); delete updatedMap[url]; } } + if (updatedIndexes.length > 0) + this.fileList_.updateIndexes(updatedIndexes); + var addedList = []; for (var url in updatedMap) { addedList.push(updatedMap[url]); } if (removedUrls.length > 0) - this.context_.fileSystemMetadata.notifyEntriesRemoved(removedUrls); + this.context_.metadataModel.notifyEntriesRemoved(removedUrls); this.prefetchMetadata(updatedList, true, function() { this.onNewEntries_(true, addedList); @@ -975,8 +985,8 @@ DirectoryContents.prototype.prefetchMetadata = function(entries, refresh, callback) { if (refresh) - this.context_.fileSystemMetadata.notifyEntriesChanged(entries); - this.context_.fileSystemMetadata.get( + this.context_.metadataModel.notifyEntriesChanged(entries); + this.context_.metadataModel.get( entries, this.context_.prefetchPropertyNames).then(callback); };
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js index 188499b..bb014b7 100644 --- a/ui/file_manager/file_manager/foreground/js/directory_model.js +++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -14,8 +14,7 @@ * @param {boolean} singleSelection True if only one file could be selected * at the time. * @param {FileFilter} fileFilter Instance of FileFilter. - * @param {!MetadataProviderCache} metadataProviderCache Metadata cache. - * @param {!FileSystemMetadata} fileSystemMetadata Metadata model. + * @param {!MetadataModel} metadataModel Metadata model. * service. * @param {VolumeManagerWrapper} volumeManager The volume manager. * @param {!FileOperationManager} fileOperationManager File operation manager. @@ -23,7 +22,7 @@ * @extends {cr.EventTarget} */ function DirectoryModel(singleSelection, fileFilter, - metadataProviderCache, fileSystemMetadata, + metadataModel, volumeManager, fileOperationManager) { this.fileListSelection_ = singleSelection ? new FileListSingleSelectionModel() : new FileListSelectionModel(); @@ -43,12 +42,11 @@ this.onFilterChanged_.bind(this)); this.currentFileListContext_ = - new FileListContext(fileFilter, fileSystemMetadata); + new FileListContext(fileFilter, metadataModel); this.currentDirContents_ = DirectoryContents.createForDirectory(this.currentFileListContext_, null); - this.metadataProviderCache_ = metadataProviderCache; - this.fileSystemMetadata_ = fileSystemMetadata; + this.metadataModel_ = metadataModel; this.volumeManager_ = volumeManager; this.volumeManager_.volumeInfoList.addEventListener( @@ -496,7 +494,7 @@ }.bind(this); // Clear the table, and start scanning. - this.metadataProviderCache_.clearAll(); + this.metadataModel_.clearAllCache(); cr.dispatchSimpleEvent(this, 'scan-started'); var fileList = this.getFileList(); fileList.splice(0, fileList.length); @@ -846,7 +844,7 @@ then(function(newEntry) { // Refresh the cache. - this.fileSystemMetadata_.notifyEntriesCreated([newEntry]); + this.metadataModel_.notifyEntriesCreated([newEntry]); return new Promise(function(onFulfilled, onRejected) { dirContents.prefetchMetadata( [newEntry], false, onFulfilled.bind(null, newEntry));
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 1d00a42..aa993f4a 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -54,15 +54,9 @@ this.mediaImportHandler_ = null; /** - * @private {!MetadataProviderCache} - * @const + * @private {MetadataModel} */ - this.metadataProviderCache_ = new MetadataProviderCache(); - - /** - * @private {FileSystemMetadata} - */ - this.fileSystemMetadata_ = null; + this.metadataModel_ = null; /** * @private {ThumbnailModel} @@ -490,7 +484,7 @@ this.ui_.multiProfileShareDialog, assert(this.backgroundPage_.background.progressCenter), assert(this.fileOperationManager_), - assert(this.fileSystemMetadata_), + assert(this.metadataModel_), assert(this.thumbnailModel_), assert(this.directoryModel_), assert(this.volumeManager_), @@ -694,10 +688,8 @@ // Create the metadata cache. assert(this.volumeManager_); - this.fileSystemMetadata_ = FileSystemMetadata.create( - this.metadataProviderCache_, - this.volumeManager_); - this.thumbnailModel_ = new ThumbnailModel(this.fileSystemMetadata_); + this.metadataModel_ = MetadataModel.create(this.volumeManager_); + this.thumbnailModel_ = new ThumbnailModel(this.metadataModel_); // Create the root view of FileManager. assert(this.dialogDom_); @@ -722,11 +714,11 @@ * @private */ FileManager.prototype.initAdditionalUI_ = function(callback) { - assert(this.fileSystemMetadata_); + assert(this.metadataModel_); assert(this.volumeManager_); assert(this.historyLoader_); assert(this.dialogDom_); - assert(this.fileSystemMetadata_); + assert(this.metadataModel_); // Cache nodes we'll be manipulating. var dom = this.dialogDom_; @@ -741,14 +733,14 @@ table.importEnabled = false; FileTable.decorate( table, - this.fileSystemMetadata_, + this.metadataModel_, this.volumeManager_, this.historyLoader_, this.dialogType == DialogType.FULL_PAGE); var grid = queryRequiredElement(dom, '.thumbnail-grid'); FileGrid.decorate( grid, - this.fileSystemMetadata_, + this.metadataModel_, this.volumeManager_, this.historyLoader_); @@ -839,12 +831,11 @@ assert(this.volumeManager_); assert(this.fileOperationManager_); - assert(this.fileSystemMetadata_); + assert(this.metadataModel_); this.directoryModel_ = new DirectoryModel( singleSelection, this.fileFilter_, - this.metadataProviderCache_, - this.fileSystemMetadata_, + this.metadataModel_, this.volumeManager_, this.fileOperationManager_); @@ -887,14 +878,13 @@ this.metadataUpdateController_ = new MetadataUpdateController( this.ui_.listContainer, this.directoryModel_, - this.metadataProviderCache_, - this.fileSystemMetadata_); + this.metadataModel_); // Create task controller. this.taskController_ = new TaskController( this.dialogType, this.ui_, - this.fileSystemMetadata_, + this.metadataModel_, this.selectionHandler_, this.metadataUpdateController_, function() { return new FileTasks(this); }.bind(this)); @@ -929,7 +919,7 @@ this.dialogType, this.ui_.dialogFooter, this.directoryModel_, - this.fileSystemMetadata_, + this.metadataModel_, this.volumeManager_, this.fileFilter_, this.namingController_, @@ -948,7 +938,7 @@ DirectoryTree.decorate(directoryTree, assert(this.directoryModel_), assert(this.volumeManager_), - assert(this.fileSystemMetadata_), + assert(this.metadataModel_), fakeEntriesVisible); directoryTree.dataModel = new NavigationListModel( this.volumeManager_, this.folderShortcutsModel_); @@ -1282,10 +1272,10 @@ }; /** - * @return {!FileSystemMetadata} + * @return {!MetadataModel} */ - FileManager.prototype.getFileSystemMetadata = function() { - return assert(this.fileSystemMetadata_); + FileManager.prototype.getMetadataModel = function() { + return assert(this.metadataModel_); }; /**
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 5443c9fa..5786fe70 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
@@ -133,7 +133,7 @@ hasDirectory = hasDirectory || entry.isDirectory; if (!entry || hasDirectory) return false; - var metadata = fileManager.getFileSystemMetadata().getCache( + var metadata = fileManager.getMetadataModel().getCache( [entry], ['hosted', 'pinned'])[0]; if (metadata.hosted) return false; @@ -892,7 +892,7 @@ return; var currentEntry; var error = false; - var fileSystemMetadata = fileManager.getFileSystemMetadata(); + var metadataModel = fileManager.getMetadataModel(); var steps = { // Pick an entry and pin it. start: function() { @@ -911,14 +911,14 @@ // Convert to boolean. error = !!chrome.runtime.lastError; if (error && pin) { - fileSystemMetadata.get([currentEntry], ['size']).then( + metadataModel.get([currentEntry], ['size']).then( function(results) { steps.showError(results[0].size); }); return; } - fileSystemMetadata.notifyEntriesChanged([currentEntry]); - fileSystemMetadata.get([currentEntry], ['pinned']).then(steps.updateUI); + metadataModel.notifyEntriesChanged([currentEntry]); + metadataModel.get([currentEntry], ['pinned']).then(steps.updateUI); }, // Update the user interface according to the cache state.
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 edbf40e..fc47d17 100644 --- a/ui/file_manager/file_manager/foreground/js/file_selection.js +++ b/ui/file_manager/file_manager/foreground/js/file_selection.js
@@ -104,12 +104,23 @@ } /** + * Metadata property names used by FileSelection. + * These metadata is expected to be cached to accelerate completeInit() of + * FileSelection. crbug.com/458915. + * @const {!Array<string>} + */ +FileSelection.METADATA_PREFETCH_PROPERTY_NAMES = [ + 'availableOffline', + 'contentMimeType', +]; + +/** * Computes data required to get file tasks and requests the tasks. * @return {!Promise} */ FileSelection.prototype.completeInit = function() { if (!this.asyncInitPromise_) { - this.asyncInitPromise_ = this.fileManager_.getFileSystemMetadata().get( + this.asyncInitPromise_ = this.fileManager_.getMetadataModel().get( this.entries, ['availableOffline', 'contentMimeType'] ).then(function(props) { var present = props.filter(function(p) { return p.availableOffline; });
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js index 5b405aa..b8459df9 100644 --- a/ui/file_manager/file_manager/foreground/js/file_tasks.js +++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -504,14 +504,14 @@ }; var fm = this.fileManager_; - var fileSystemMetadata = this.fileManager_.getFileSystemMetadata(); + var metadataModel = this.fileManager_.getMetadataModel(); var entries = assert(this.entries_); var isDriveOffline = fm.volumeManager.getDriveConnectionState().type === VolumeManagerCommon.DriveConnectionType.OFFLINE; if (fm.isOnDrive() && isDriveOffline) { - fileSystemMetadata.get(entries, ['availableOffline', 'hosted']).then( + metadataModel.get(entries, ['availableOffline', 'hosted']).then( function(props) { if (areAll(props, 'availableOffline')) { callback(); @@ -539,7 +539,7 @@ VolumeManagerCommon.DriveConnectionType.METERED; if (fm.isOnDrive() && isOnMetered) { - fileSystemMetadata.get(entries, ['availableWhenMetered', 'size']).then( + metadataModel.get(entries, ['availableWhenMetered', 'size']).then( function(props) { if (areAll(props, 'availableWhenMetered')) { callback();
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js index 6d5bb8d..f5e4809 100644 --- a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
@@ -55,7 +55,7 @@ openSuggestAppsDialog: function( entry, onSuccess, onCancelled, onFailure) {} }, - getFileSystemMetadata: function() {} + getMetadataModel: function() {} }; }
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 adc9be54..26acbe0 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
@@ -24,7 +24,7 @@ * @param {!ProgressCenter} progressCenter To notify starting copy operation. * @param {!FileOperationManager} fileOperationManager File operation manager * instance. - * @param {!FileSystemMetadata} fileSystemMetadata Metadata cache service. + * @param {!MetadataModel} metadataModel Metadata cache service. * @param {!ThumbnailModel} thumbnailModel * @param {!DirectoryModel} directoryModel Directory model instance. * @param {!VolumeManagerWrapper} volumeManager Volume manager instance. @@ -38,7 +38,7 @@ multiProfileShareDialog, progressCenter, fileOperationManager, - fileSystemMetadata, + metadataModel, thumbnailModel, directoryModel, volumeManager, @@ -65,11 +65,11 @@ this.fileOperationManager_ = fileOperationManager; /** - * @type {!FileSystemMetadata} + * @type {!MetadataModel} * @private * @const */ - this.fileSystemMetadata_ = fileSystemMetadata; + this.metadataModel_ = metadataModel; /** * @type {!ThumbnailModel} @@ -1093,9 +1093,11 @@ // asynchronous operations. if (!containsDirectory) { for (var i = 0; i < fileEntries.length; i++) { - fileEntries[i].file(function(data, file) { - data.file = file; - }.bind(null, asyncData[fileEntries[i].toURL()])); + (function(fileEntry) { + fileEntry.file(function(file) { + asyncData[fileEntry.toURL()].file = file; + }); + })(fileEntries[i]); } } @@ -1106,7 +1108,7 @@ this.preloadThumbnailImage_(entries[0]); } - this.fileSystemMetadata_.get(entries, ['externalFileUrl']).then( + this.metadataModel_.get(entries, ['externalFileUrl']).then( function(metadataList) { // |Copy| is the only menu item affected by allDriveFilesAvailable_. // It could be open right now, update its UI.
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js index 3909d2e..adabbaa8 100644 --- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js +++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
@@ -343,6 +343,10 @@ */ ListThumbnailLoader.Task.prototype.fetch = function() { return this.thumbnailModel_.get([this.entry_]).then(function(metadatas) { + // When an error happens during metadata fetch, abort here. + if (metadatas[0].thumbnail.urlError) + throw metadatas[0].thumbnail.urlError; + return new this.thumbnailLoaderConstructor_( this.entry_, ThumbnailLoader.LoaderType.IMAGE, metadatas[0]) .loadAsDataUrl();
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js index 171e45a..a6b5c9980 100644 --- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js
@@ -92,7 +92,7 @@ function resolveGetLatestCallback(entries) { var key = getKeyOfGetCallback_(entries); assert(getCallbacks[key]); - getCallbacks[key](entries.map(function() { return {}; })); + getCallbacks[key](entries.map(function() { return { thumbnail: {} }; })); delete getCallbacks[key]; }
diff --git a/ui/file_manager/file_manager/foreground/js/main_scripts.js b/ui/file_manager/file_manager/foreground/js/main_scripts.js index fdc23be..76d4d63 100644 --- a/ui/file_manager/file_manager/foreground/js/main_scripts.js +++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js
@@ -109,11 +109,11 @@ //<include src="launch_param.js"> //<include src="metadata/content_metadata_provider.js"> //<include src="metadata/external_metadata_provider.js"> -//<include src="metadata/file_system_metadata.js"> //<include src="metadata/file_system_metadata_provider.js"> -//<include src="metadata/metadata_cache.js"> //<include src="metadata/metadata_cache_item.js"> //<include src="metadata/metadata_item.js"> +//<include src="metadata/metadata_model.js"> +//<include src="metadata/multi_metadata_provider.js"> //<include src="metadata/thumbnail_model.js"> //<include src="metadata_update_controller.js"> //<include src="naming_controller.js">
diff --git a/ui/file_manager/file_manager/foreground/js/main_window_component.js b/ui/file_manager/file_manager/foreground/js/main_window_component.js index 754d3363..1a33690 100644 --- a/ui/file_manager/file_manager/foreground/js/main_window_component.js +++ b/ui/file_manager/file_manager/foreground/js/main_window_component.js
@@ -282,7 +282,7 @@ selection.indexes[0]); // If the item is in renaming process, we don't allow to change // directory. - if (!item.hasAttribute('renaming')) { + if (item && !item.hasAttribute('renaming')) { event.preventDefault(); this.directoryModel_.changeDirectoryEntry(selection.entries[0]); }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/compiled_resources.gyp b/ui/file_manager/file_manager/foreground/js/metadata/compiled_resources.gyp index 669a54c..15bcbaf 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/compiled_resources.gyp +++ b/ui/file_manager/file_manager/foreground/js/metadata/compiled_resources.gyp
@@ -18,6 +18,7 @@ 'function_parallel.js', ], 'externs': [ + '../../../../externs/exif_entry.js', '../../../../externs/platform_worker.js', ] },
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js index d245b95..8dcfe73 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js
@@ -3,17 +3,15 @@ // found in the LICENSE file. /** - * @param {!MetadataProviderCache} cache * @param {!MessagePort=} opt_messagePort Message port overriding the default * worker port. * @extends {NewMetadataProvider} * @constructor * @struct */ -function ContentMetadataProvider(cache, opt_messagePort) { +function ContentMetadataProvider(opt_messagePort) { NewMetadataProvider.call( this, - cache, ContentMetadataProvider.PROPERTY_NAMES); /** @@ -85,6 +83,8 @@ item.contentThumbnailUrl = metadata['thumbnailURL']; item.exifLittleEndian = metadata['littleEndian']; item.ifd = metadata['ifd']; + item.imageHeight = metadata['height']; + item.imageWidth = metadata['width']; item.mediaArtist = metadata['artist']; item.mediaMimeType = metadata['mimeType']; item.mediaTitle = metadata['title']; @@ -96,11 +96,14 @@ /** * @override */ -ContentMetadataProvider.prototype.getImpl = function(requests) { +ContentMetadataProvider.prototype.get = function(requests) { + if (!requests.length) + return Promise.resolve([]); + var promises = []; for (var i = 0; i < requests.length; i++) { promises.push(new Promise(function(request, fulfill) { - this.fetch(request.entry, request.names, fulfill); + this.getImpl_(request.entry, request.names, fulfill); }.bind(this, requests[i]))); } return Promise.all(promises); @@ -112,8 +115,9 @@ * @param {!Array<string>} names Requested metadata type. * @param {function(Object)} callback Callback expects a map from metadata type * to metadata value. This callback is called asynchronously. + * @private */ -ContentMetadataProvider.prototype.fetch = function(entry, names, callback) { +ContentMetadataProvider.prototype.getImpl_ = function(entry, names, callback) { if (entry.isDirectory) { setTimeout(callback.bind(null, {}), 0); return; @@ -139,7 +143,11 @@ this.onInitialized_(data.arguments[0]); break; case 'result': - this.onResult_(data.arguments[0], data.arguments[1]); + this.onResult_( + data.arguments[0], + data.arguments[1] ? + ContentMetadataProvider.convertContentMetadata(data.arguments[1]) : + new MetadataItem()); break; case 'error': this.onError_( @@ -178,17 +186,14 @@ /** * Handles the 'result' message from the worker. * @param {string} url File url. - * @param {Object} metadata The metadata. + * @param {!MetadataItem} metadataItem The metadata item. * @private */ -ContentMetadataProvider.prototype.onResult_ = function(url, metadata) { +ContentMetadataProvider.prototype.onResult_ = function(url, metadataItem) { var callbacks = this.callbacks_[url]; delete this.callbacks_[url]; for (var i = 0; i < callbacks.length; i++) { - callbacks[i]( - metadata ? - ContentMetadataProvider.convertContentMetadata(metadata) : - new MetadataItem()); + callbacks[i](metadataItem); } }; @@ -196,16 +201,31 @@ * Handles the 'error' message from the worker. * @param {string} url File entry. * @param {string} step Step failed. - * @param {string} error Error description. + * @param {string} errorDescription Error description. * @param {Object?} metadata The metadata, if available. * @private */ ContentMetadataProvider.prototype.onError_ = function( - url, step, error, metadata) { + url, step, errorDescription, metadata) { console.error( 'ContentMetadataProvider failed to obtain metadata: '+ - url + ': ' + step + ': ' + error); - this.onResult_(url, new MetadataItem()); + url + ': ' + step + ': ' + errorDescription); + + // For error case, fill all fields with error object. + var error = new ContentMetadataProvider.Error(url, step, errorDescription); + var item = new MetadataItem(); + item.contentImageTransformError = error; + item.contentThumbnailTransformError = error; + item.contentThumbnailUrlError = error; + item.exifLittleEndianError = error; + item.ifdError = error; + item.imageHeightError = error; + item.imageWidthError = error; + item.mediaArtistError = error; + item.mediaMimeTypeError = error; + item.mediaTitleError = error; + + this.onResult_(url, item); }; /** @@ -216,3 +236,32 @@ ContentMetadataProvider.prototype.onLog_ = function(arglist) { console.log.apply(console, ['ContentMetadataProvider log:'].concat(arglist)); }; + +/** + * Content metadata provider error. + * @param {string} url File Entry. + * @param {string} step Step failed. + * @param {string} errorDescription Error description. + * @constructor + * @struct + * @extends {Error} + * @suppress {checkStructDictInheritance} + */ +ContentMetadataProvider.Error = function(url, step, errorDescription) { + /** + * @public {string} + */ + this.url = url; + + /** + * @public {string} + */ + this.step = step; + + /** + * @public {string} + */ + this.errorDescription = errorDescription; +}; + +ContentMetadataProvider.Error.prototype.__proto__ = Error.prototype;
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.js index e60977b..d77ec3c 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.js
@@ -31,20 +31,21 @@ }, start: function() {} }; - var cache = new MetadataProviderCache(); - var provider = new ContentMetadataProvider(cache, port); - reportPromise(provider.get( - [entryA, entryB], - ['contentThumbnailUrl', 'contentThumbnailTransform']).then( - function(results) { - assertEquals(2, results.length); - assertEquals('filesystem://A,url', results[0].contentThumbnailUrl); - assertEquals( - 'filesystem://A,transform', - results[0].contentThumbnailTransform); - assertEquals('filesystem://B,url', results[1].contentThumbnailUrl); - assertEquals( - 'filesystem://B,transform', - results[1].contentThumbnailTransform); - }), callback); + var provider = new ContentMetadataProvider(port); + reportPromise(provider.get([ + new MetadataRequest( + entryA, ['contentThumbnailUrl', 'contentThumbnailTransform']), + new MetadataRequest( + entryB, ['contentThumbnailUrl', 'contentThumbnailTransform']) + ]).then(function(results) { + assertEquals(2, results.length); + assertEquals('filesystem://A,url', results[0].contentThumbnailUrl); + assertEquals( + 'filesystem://A,transform', + results[0].contentThumbnailTransform); + assertEquals('filesystem://B,url', results[1].contentThumbnailUrl); + assertEquals( + 'filesystem://B,transform', + results[1].contentThumbnailTransform); + }), callback); }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js index f6cc007..261072053 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
@@ -6,14 +6,12 @@ * Metadata provider for FileEntry#getMetadata. * TODO(hirono): Rename thumbnailUrl with externalThumbnailUrl. * - * @param {!MetadataProviderCache} cache * @constructor * @extends {NewMetadataProvider} * @struct */ -function ExternalMetadataProvider(cache) { - NewMetadataProvider.call( - this, cache, ExternalMetadataProvider.PROPERTY_NAMES); +function ExternalMetadataProvider() { + NewMetadataProvider.call(this, ExternalMetadataProvider.PROPERTY_NAMES); } /** @@ -44,7 +42,9 @@ /** * @override */ -ExternalMetadataProvider.prototype.getImpl = function(requests) { +ExternalMetadataProvider.prototype.get = function(requests) { + if (!requests.length) + return Promise.resolve([]); return new Promise(function(fulfill) { var urls = []; for (var i = 0; i < requests.length; i++) {
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js index b5a0509..198ef3e 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js
@@ -34,20 +34,19 @@ }, runtime: {lastError: null} }; - var cache = new MetadataProviderCache(); - var provider = new ExternalMetadataProvider(cache); - reportPromise(provider.get( - [entryA, entryB], - ['modificationTime', 'size']).then( - function(results) { - assertEquals(2, results.length); - assertEquals( - new Date(2015, 0, 1).toString(), - results[0].modificationTime.toString()); - assertEquals(1024, results[0].size); - assertEquals( - new Date(2015, 1, 2).toString(), - results[1].modificationTime.toString()); - assertEquals(2048, results[1].size); - }), callback); + var provider = new ExternalMetadataProvider(); + reportPromise(provider.get([ + new MetadataRequest(entryA, ['modificationTime', 'size']), + new MetadataRequest(entryB, ['modificationTime', 'size']), + ]).then(function(results) { + assertEquals(2, results.length); + assertEquals( + new Date(2015, 0, 1).toString(), + results[0].modificationTime.toString()); + assertEquals(1024, results[0].size); + assertEquals( + new Date(2015, 1, 2).toString(), + results[1].modificationTime.toString()); + assertEquals(2048, results[1].size); + }), callback); }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata.js deleted file mode 100644 index 8841cf1..0000000 --- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata.js +++ /dev/null
@@ -1,199 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @param {!MetadataProviderCache} cache - * @param {!FileSystemMetadataProvider} fileSystemMetadataProvider - * @param {!ExternalMetadataProvider} externalMetadataProvider - * @param {!ContentMetadataProvider} contentMetadataProvider - * @param {!VolumeManagerCommon.VolumeInfoProvider} volumeManager - * @constructor - * @struct - */ -function FileSystemMetadata( - cache, - fileSystemMetadataProvider, - externalMetadataProvider, - contentMetadataProvider, - volumeManager) { - /** - * @private {!MetadataProviderCache} - * @const - */ - this.cache_ = cache; - - /** - * @private {!FileSystemMetadataProvider} - * @const - */ - this.fileSystemMetadataProvider_ = fileSystemMetadataProvider; - - /** - * @private {!ExternalMetadataProvider} - * @const - */ - this.externalMetadataProvider_ = externalMetadataProvider; - - /** - * @private {!ContentMetadataProvider} - * @const - */ - this.contentMetadataProvider_ = contentMetadataProvider; - - /** - * @private {!VolumeManagerCommon.VolumeInfoProvider} - * @const - */ - this.volumeManager_ = volumeManager; -} - -/** - * @param {!MetadataProviderCache} cache - * @param {!VolumeManagerCommon.VolumeInfoProvider} volumeManager - * @return {!FileSystemMetadata} - */ -FileSystemMetadata.create = function(cache, volumeManager) { - return new FileSystemMetadata( - cache, - new FileSystemMetadataProvider(cache), - new ExternalMetadataProvider(cache), - new ContentMetadataProvider(cache), - volumeManager); -}; - -/** - * Obtains metadata for entries. - * @param {!Array<!Entry>} entries Entries. - * @param {!Array<string>} names Metadata property names to be obtained. - * @return {!Promise<!Array<!MetadataItem>>} - */ -FileSystemMetadata.prototype.get = function(entries, names) { - var localEntries = []; - var externalEntries = []; - for (var i = 0; i < entries.length; i++) { - var volumeInfo = this.volumeManager_.getVolumeInfo(entries[i]); - if (volumeInfo && - (volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DRIVE || - volumeInfo.volumeType === VolumeManagerCommon.VolumeType.PROVIDED)) { - externalEntries.push(entries[i]); - } else { - localEntries.push(entries[i]); - } - } - - // Group property names. - var fileSystemPropertyNames = []; - var externalPropertyNames = []; - var contentPropertyNames = []; - var fallbackContentPropertyNames = []; - for (var i = 0; i < names.length; i++) { - var name = names[i]; - var isFileSystemProperty = - FileSystemMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1; - var isExternalProperty = - ExternalMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1; - var isContentProperty = - ContentMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1; - assert(isFileSystemProperty || isExternalProperty || isContentProperty); - assert(!(isFileSystemProperty && isContentProperty)); - // If the property can be obtained both from ExternalProvider and from - // ContentProvider, we can obtain the property from ExternalProvider without - // fetching file content. On the other hand, the values from - // ExternalProvider may be out of sync if the file is 'dirty'. Thus we - // fallback to ContentProvider if the file is dirty. See below. - if (isExternalProperty && isContentProperty) { - externalPropertyNames.push(name); - fallbackContentPropertyNames.push(name); - continue; - } - if (isFileSystemProperty) - fileSystemPropertyNames.push(name); - if (isExternalProperty) - externalPropertyNames.push(name); - if (isContentProperty) - contentPropertyNames.push(name); - } - - // Obtain each group of property names. - var resultPromises = []; - var get = function(provider, entries, names) { - return provider.get(entries, names).then(function(results) { - return {entries: entries, results: results}; - }); - }; - resultPromises.push(get( - this.fileSystemMetadataProvider_, localEntries, fileSystemPropertyNames)); - resultPromises.push(get( - this.externalMetadataProvider_, externalEntries, externalPropertyNames)); - resultPromises.push(get( - this.contentMetadataProvider_, entries, contentPropertyNames)); - if (fallbackContentPropertyNames.length) { - var dirtyEntriesPromise = this.externalMetadataProvider_.get( - externalEntries, ['dirty']).then(function(results) { - return externalEntries.filter(function(entry, index) { - return results[index].dirty; - }); - }); - resultPromises.push(dirtyEntriesPromise.then(function(dirtyEntries) { - return get( - this.contentMetadataProvider_, - localEntries.concat(dirtyEntries), - fallbackContentPropertyNames); - }.bind(this))); - } - - // Merge results. - return Promise.all(resultPromises).then(function(resultsList) { - var integratedResults = {}; - for (var i = 0; i < resultsList.length; i++) { - var inEntries = resultsList[i].entries; - var results = resultsList[i].results; - for (var j = 0; j < inEntries.length; j++) { - var url = inEntries[j].toURL(); - integratedResults[url] = integratedResults[url] || new MetadataItem(); - for (var name in results[j]) { - integratedResults[url][name] = results[j][name]; - } - } - } - return entries.map(function(entry) { - return integratedResults[entry.toURL()]; - }); - }); -}; - -/** - * Obtains metadata cache for entries. - * @param {!Array<!Entry>} entries Entries. - * @param {!Array<string>} names Metadata property names to be obtained. - * @return {!Array<!MetadataItem>} - */ -FileSystemMetadata.prototype.getCache = function(entries, names) { - return this.cache_.get(entries, names); -}; - -/** - * Clears old metadata for newly created entries. - * @param {!Array<!Entry>} entries - */ -FileSystemMetadata.prototype.notifyEntriesCreated = function(entries) { - this.cache_.clear(util.entriesToURLs(entries)); -}; - -/** - * Clears metadata for deleted entries. - * @param {!Array<string>} urls Note it is not an entry list because we cannot - * obtain entries after removing them from the file system. - */ -FileSystemMetadata.prototype.notifyEntriesRemoved = function(urls) { - this.cache_.clear(urls); -}; - -/** - * Invalidates metadata for updated entries. - * @param {!Array<!Entry>} entries - */ -FileSystemMetadata.prototype.notifyEntriesChanged = function(entries) { - this.cache_.invalidate(this.cache_.generateRequestId(), entries); -};
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js index 01c8519..41b40f6f 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
@@ -5,14 +5,12 @@ /** * Metadata provider for FileEntry#getMetadata. * - * @param {!MetadataProviderCache} cache * @constructor * @extends {NewMetadataProvider} * @struct */ -function FileSystemMetadataProvider(cache) { - NewMetadataProvider.call( - this, cache, FileSystemMetadataProvider.PROPERTY_NAMES); +function FileSystemMetadataProvider() { + NewMetadataProvider.call(this, FileSystemMetadataProvider.PROPERTY_NAMES); } /** @@ -27,7 +25,9 @@ /** * @override */ -FileSystemMetadataProvider.prototype.getImpl = function(requests) { +FileSystemMetadataProvider.prototype.get = function(requests) { + if (!requests.length) + return Promise.resolve([]); return Promise.all(requests.map(function(request) { return Promise.all([ new Promise(function(fulfill, reject) {
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.js index 3f81abd..bd90df8 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.js
@@ -40,45 +40,44 @@ } function testFileSystemMetadataProviderBasic(callback) { - var cache = new MetadataProviderCache(); - var provider = new FileSystemMetadataProvider(cache); - reportPromise(provider.get( - [entryA, entryB], - ['modificationTime', 'size', 'contentMimeType', - 'present', 'availableOffline']).then( - function(results) { - assertEquals(2, results.length); - assertEquals( - new Date(2015, 1, 1).toString(), - results[0].modificationTime.toString()); - assertEquals(1024, results[0].size); - assertEquals('application/A', results[0].contentMimeType); - assertTrue(results[0].present); - assertTrue(results[0].availableOffline); - assertEquals( - new Date(2015, 2, 2).toString(), - results[1].modificationTime.toString()); - assertEquals(2048, results[1].size); - assertEquals('application/B', results[1].contentMimeType); - assertTrue(results[1].present); - assertTrue(results[1].availableOffline); - }), callback); + var provider = new FileSystemMetadataProvider(); + var names = [ + 'modificationTime', 'size', 'contentMimeType', 'present', + 'availableOffline']; + reportPromise(provider.get([ + new MetadataRequest(entryA, names), + new MetadataRequest(entryB, names) + ]).then(function(results) { + assertEquals(2, results.length); + assertEquals( + new Date(2015, 1, 1).toString(), + results[0].modificationTime.toString()); + assertEquals(1024, results[0].size); + assertEquals('application/A', results[0].contentMimeType); + assertTrue(results[0].present); + assertTrue(results[0].availableOffline); + assertEquals( + new Date(2015, 2, 2).toString(), + results[1].modificationTime.toString()); + assertEquals(2048, results[1].size); + assertEquals('application/B', results[1].contentMimeType); + assertTrue(results[1].present); + assertTrue(results[1].availableOffline); + }), callback); } function testFileSystemMetadataProviderPartialRequest(callback) { - var cache = new MetadataProviderCache(); - var provider = new FileSystemMetadataProvider(cache); + var provider = new FileSystemMetadataProvider(); reportPromise(provider.get( - [entryA], - ['modificationTime', 'size']).then( - function(results) { - assertEquals(1, results.length); - assertEquals( - new Date(2015, 1, 1).toString(), - results[0].modificationTime.toString()); - assertEquals(1024, results[0].size); - // When contentMimeType is not requested, this shouldn't try to get - // MIME type. - assertFalse(chrome.fileManagerPrivate.isGetMimeTypeCalled_); - }), callback); + [new MetadataRequest(entryA, ['modificationTime', 'size'])]).then( + function(results) { + assertEquals(1, results.length); + assertEquals( + new Date(2015, 1, 1).toString(), + results[0].modificationTime.toString()); + assertEquals(1024, results[0].size); + // When contentMimeType is not requested, this shouldn't try to get + // MIME type. + assertFalse(chrome.fileManagerPrivate.isGetMimeTypeCalled_); + }), callback); }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.html deleted file mode 100644 index 7c23ebc7..0000000 --- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.html +++ /dev/null
@@ -1,24 +0,0 @@ -<!DOCTYPE html> -<!-- Copyright 2015 The Chromium Authors. All rights reserved. - -- Use of this source code is governed by a BSD-style license that can be - -- found in the LICENSE file. - --> -<!-- Base classes --> -<script src="../../../../../webui/resources/js/cr.js"></script> -<script src="../../../../../webui/resources/js/cr/event_target.js"></script> -<script src="metadata_cache_set.js"></script> -<script src="new_metadata_provider.js"></script> - -<!-- Others --> -<script src="../../../../../webui/resources/js/assert.js"></script> -<script src="../../../common/js/lru_cache.js"></script> -<script src="../../../common/js/unittest_util.js"></script> -<script src="../../../common/js/volume_manager_common.js"></script> -<script src="content_metadata_provider.js"></script> -<script src="external_metadata_provider.js"></script> -<script src="file_system_metadata.js"></script> -<script src="file_system_metadata_provider.js"></script> -<script src="metadata_cache_item.js"></script> -<script src="metadata_item.js"></script> - -<script src="file_system_metadata_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.js deleted file mode 100644 index 1650b7c..0000000 --- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.js +++ /dev/null
@@ -1,141 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -var entryA = { - toURL: function() { return 'filesystem://A'; } -}; - -var entryB = { - toURL: function() { return 'filesystem://B'; } -}; - -var entryC = { - toURL: function() { return 'filesystem://C'; } -}; - -var volumeManager = { - getVolumeInfo: function(entry) { - if (entry.toURL() === 'filesystem://A') { - return { - volumeType: VolumeManagerCommon.VolumeType.DOWNLOADS - }; - } else if (entry.toURL() === 'filesystem://B') { - return { - volumeType: VolumeManagerCommon.VolumeType.DRIVE - }; - } else if (entry.toURL() === 'filesystem://C') { - return { - volumeType: VolumeManagerCommon.VolumeType.DRIVE - }; - } - assertNotReached(); - } -}; - -function testFileSystemMetadataBasic(callback) { - var cache = new MetadataProviderCache(); - var model = new FileSystemMetadata( - cache, - // Mocking FileSystemMetadataProvider. - { - get: function(entries, names) { - assertEquals(1, entries.length); - assertEquals('filesystem://A', entries[0].toURL()); - assertArrayEquals(['size', 'modificationTime'], names); - return Promise.resolve( - [{modificationTime: new Date(2015, 0, 1), size: 1024}]); - } - }, - // Mocking ExternalMetadataProvider. - { - get: function(entries, names) { - assertEquals(1, entries.length); - assertEquals('filesystem://B', entries[0].toURL()); - assertArrayEquals(['size', 'modificationTime'], names); - return Promise.resolve( - [{modificationTime: new Date(2015, 1, 2), size: 2048}]); - } - }, - // Mocking ContentMetadataProvider. - { - get: function(entries, names) { - assertEquals(2, entries.length); - assertEquals('filesystem://A', entries[0].toURL()); - assertEquals('filesystem://B', entries[1].toURL()); - assertArrayEquals(['contentThumbnailUrl'], names); - return Promise.resolve([ - {contentThumbnailUrl: 'THUMBNAIL_URL_A'}, - {contentThumbnailUrl: 'THUMBNAIL_URL_B'} - ]); - } - }, - // Mocking VolumeManagerWrapper. - volumeManager); - reportPromise( - model.get( - [entryA, entryB], - ['size', 'modificationTime', 'contentThumbnailUrl']).then( - function(results) { - assertEquals(2, results.length); - assertEquals( - new Date(2015, 0, 1).toString(), - results[0].modificationTime.toString()); - assertEquals(1024, results[0].size); - assertEquals('THUMBNAIL_URL_A', results[0].contentThumbnailUrl); - assertEquals( - new Date(2015, 1, 2).toString(), - results[1].modificationTime.toString()); - assertEquals(2048, results[1].size); - assertEquals('THUMBNAIL_URL_B', results[1].contentThumbnailUrl); - }), callback); -} - -function testFileSystemMetadataExternalAndContentProperty(callback) { - var cache = new MetadataProviderCache(); - var model = new FileSystemMetadata( - cache, - // Mocking FileSystemMetadataProvider. - { - get: function(entries, names) { - assertEquals(0, names.length); - return Promise.resolve([{}]); - } - }, - // Mocking ExternalMetadataProvider. - { - get: function(entries, names) { - assertEquals(2, entries.length); - assertEquals('filesystem://B', entries[0].toURL()); - assertEquals('filesystem://C', entries[1].toURL()); - return Promise.resolve([ - {dirty: false, imageWidth: 200}, - {dirty: true, imageWidth: 400} - ]); - } - }, - // Mocking ContentMetadataProvider. - { - get: function(entries, names) { - if (names.length == 0) - return Promise.resolve(entries.map(function() { return {}; })); - assertEquals(2, entries.length); - assertEquals('filesystem://A', entries[0].toURL()); - assertEquals('filesystem://C', entries[1].toURL()); - assertArrayEquals(['imageWidth'], names); - return Promise.resolve([ - {imageWidth: 100}, - {imageWidth: 300} - ]); - } - }, - // Mocking VolumeManagerWrapper. - volumeManager); - reportPromise(model.get([entryA, entryB, entryC], ['imageWidth']).then( - function(results) { - assertEquals(3, results.length); - assertEquals(100, results[0].imageWidth); - assertEquals(200, results[1].imageWidth); - assertEquals(300, results[2].imageWidth); - }), callback); -}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache.js deleted file mode 100644 index f92bc17a..0000000 --- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache.js +++ /dev/null
@@ -1,1136 +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. - -/** - * MetadataCache is a map from Entry to an object containing properties. - * Properties are divided by types, and all properties of one type are accessed - * at once. - * Some of the properties: - * { - * filesystem: size, modificationTime - * external: pinned, present, hosted, availableOffline, externalFileUrl - * - * Following are not fetched for non-present external files. - * media: artist, album, title, width, height, imageTransform, etc. - * thumbnail: url, transform - * - * Following are always fetched from content, and so force the downloading - * of external files. One should use this for required content metadata, - * i.e. image orientation. - * fetchedMedia: width, height, etc. - * } - * - * Typical usages: - * { - * cache.get([entry1, entry2], 'external|filesystem', function(metadata) { - * if (metadata[0].external.pinned && metadata[1].filesystem.size === 0) - * alert("Pinned and empty!"); - * }); - * - * cache.set(entry, 'external', {present: true}); - * - * cache.clear([fileEntry1, fileEntry2], 'filesystem'); - * - * // Getting fresh value. - * cache.clear(entry, 'thumbnail'); - * cache.getOne(entry, 'thumbnail', function(thumbnail) { - * img.src = thumbnail.url; - * }); - * - * var cached = cache.getCached(entry, 'filesystem'); - * var size = (cached && cached.size) || UNKNOWN_SIZE; - * } - * - * @param {Array.<MetadataProvider>} providers Metadata providers. - * @constructor - * @struct - */ -function MetadataCache(providers) { - /** - * Map from Entry (using Entry.toURL) to metadata. Metadata contains - * |properties| - an hierarchical object of values, and an object for each - * metadata provider: <prodiver-id>: {time, callbacks} - * @private - */ - this.cache_ = {}; - - /** - * List of metadata providers. - * @private - */ - this.providers_ = providers; - - /** - * List of observers added. Each one is an object with fields: - * re - regexp of urls; - * type - metadata type; - * callback - the callback. - * @private - */ - this.observers_ = []; - this.observerId_ = 0; - - this.batchCount_ = 0; - this.totalCount_ = 0; - - this.currentCacheSize_ = 0; - - /** - * Time of first get query of the current batch. Items updated later than this - * will not be evicted. - * - * @type {Date} - * @private - */ - this.lastBatchStart_ = new Date(); -} - -/** - * Observer type: it will be notified if the changed Entry is exactly the same - * as the observed Entry. - */ -MetadataCache.EXACT = 0; - -/** - * Observer type: it will be notified if the changed Entry is an immediate child - * of the observed Entry. - */ -MetadataCache.CHILDREN = 1; - -/** - * Observer type: it will be notified if the changed Entry is a descendant of - * of the observer Entry. - */ -MetadataCache.DESCENDANTS = 2; - -/** - * Margin of the cache size. This amount of caches may be kept in addition. - */ -MetadataCache.EVICTION_THRESHOLD_MARGIN = 500; - -/** - * @param {VolumeManagerCommon.VolumeInfoProvider} volumeManager Volume manager - * instance. - * @return {MetadataCache!} The cache with all providers. - */ -MetadataCache.createFull = function(volumeManager) { - // ExternalProvider should be prior to FileSystemProvider, because it covers - // FileSystemProvider for files on the external backend, eg. Drive. - return new MetadataCache([ - new ExternalProvider(volumeManager), - new FilesystemProvider(), - new ContentProvider() - ]); -}; - -/** - * Clones metadata entry. Metadata entries may contain scalars, arrays, - * hash arrays and Date object. Other objects are not supported. - * @param {!Object} metadata Metadata object. - * @return {!Object} Cloned entry. - */ -MetadataCache.cloneMetadata = function(metadata) { - if (metadata instanceof Array) { - var result = []; - for (var index = 0; index < metadata.length; index++) { - result[index] = MetadataCache.cloneMetadata(metadata[index]); - } - return result; - } else if (metadata instanceof Date) { - var result = new Date(); - result.setTime(metadata.getTime()); - return result; - } else if (metadata instanceof Object) { // Hash array only. - var result = {}; - for (var property in metadata) { - if (metadata.hasOwnProperty(property)) - result[property] = MetadataCache.cloneMetadata(metadata[property]); - } - return result; - } else { - return metadata; - } -}; - -/** - * @return {boolean} Whether all providers are ready. - */ -MetadataCache.prototype.isInitialized = function() { - for (var index = 0; index < this.providers_.length; index++) { - if (!this.providers_[index].isInitialized()) return false; - } - return true; -}; - -/** - * Changes the size of cache by delta value. The actual cache size may be larger - * than the given value. - * - * @param {number} delta The delta size to be changed the cache size by. - */ -MetadataCache.prototype.resizeBy = function(delta) { - this.currentCacheSize_ += delta; - if (this.currentCacheSize_ < 0) - this.currentCacheSize_ = 0; - - if (this.totalCount_ > this.currentEvictionThreshold_()) - this.evict_(); -}; - -/** - * Returns the current threshold to evict caches. When the number of caches - * exceeds this, the cache should be evicted. - * @return {number} Threshold to evict caches. - * @private - */ -MetadataCache.prototype.currentEvictionThreshold_ = function() { - return this.currentCacheSize_ * 2 + MetadataCache.EVICTION_THRESHOLD_MARGIN; -}; - -/** - * Fetches the metadata, puts it in the cache, and passes to callback. - * If required metadata is already in the cache, does not fetch it again. - * - * @param {Array.<Entry>} entries The list of entries. - * @param {string} type The metadata type. - * @param {?function(Object)} callback The metadata is passed to callback. - * The callback is called asynchronously. - */ -MetadataCache.prototype.get = function(entries, type, callback) { - this.getInternal_(entries, type, false, callback); -}; - -/** - * Fetches the metadata, puts it in the cache, and passes to callback. - * Even if required metadata is already in the cache, fetches it again. - * - * @param {Array.<Entry>} entries The list of entries. - * @param {string} type The metadata type. - * @param {?function(Object)} callback The metadata is passed to callback. - * The callback is called asynchronously. - */ -MetadataCache.prototype.getLatest = function(entries, type, callback) { - this.getInternal_(entries, type, true, callback); -}; - -/** - * Fetches the metadata, puts it in the cache. This is only for internal use. - * - * @param {Array.<Entry>} entries The list of entries. - * @param {string} type The metadata type. - * @param {boolean} refresh True to get the latest value and refresh the cache, - * false to get the value from the cache. - * @param {?function(Object)} callback The metadata is passed to callback. - * The callback is called asynchronously. - * @private - */ -MetadataCache.prototype.getInternal_ = - function(entries, type, refresh, callback) { - if (entries.length === 0) { - if (callback) setTimeout(callback.bind(null, []), 0); - return; - } - - var result = []; - var remaining = entries.length; - this.startBatchUpdates(); - - var onOneItem = function(index, value) { - result[index] = value; - remaining--; - if (remaining === 0) { - this.endBatchUpdates(); - if (callback) callback(result); - } - }; - - for (var index = 0; index < entries.length; index++) { - result.push(null); - this.getOneInternal_(entries[index], - type, - refresh, - onOneItem.bind(this, index)); - } -}; - -/** - * Fetches the metadata for one Entry. See comments to |get|. - * If required metadata is already in the cache, does not fetch it again. - * - * @param {Entry} entry The entry. - * @param {string} type Metadata type. - * @param {function(Object)} callback The metadata is passed to callback. - * The callback is called asynchronously. - */ -MetadataCache.prototype.getOne = function(entry, type, callback) { - this.getOneInternal_(entry, type, false, callback); -}; - -/** - * Fetches the metadata for one Entry. This is only for internal use. - * - * @param {Entry} entry The entry. - * @param {string} type Metadata type. - * @param {boolean} refresh True to get the latest value and refresh the cache, - * false to get the value from the cache. - * @param {function(Object)} callback The metadata is passed to callback. - * The callback is called asynchronously. - * @private - */ -MetadataCache.prototype.getOneInternal_ = - function(entry, type, refresh, callback) { - if (type.indexOf('|') !== -1) { - var types = type.split('|'); - var result = {}; - var typesLeft = types.length; - - var onOneType = function(requestedType, metadata) { - result[requestedType] = metadata; - typesLeft--; - if (typesLeft === 0) callback(result); - }; - - for (var index = 0; index < types.length; index++) { - this.getOneInternal_(entry, types[index], refresh, - onOneType.bind(null, types[index])); - } - return; - } - - callback = callback || function() {}; - - var entryURL = entry.toURL(); - if (!(entryURL in this.cache_)) { - this.cache_[entryURL] = this.createEmptyItem_(); - this.totalCount_++; - } - - var item = this.cache_[entryURL]; - - if (!refresh && type in item.properties) { - // Uses cache, if available and not on the 'refresh' mode. - setTimeout(callback.bind(null, item.properties[type]), 0); - return; - } - - this.startBatchUpdates(); - var providers = this.providers_.slice(); - var currentProvider; - var self = this; - - var queryProvider = function() { - var id = currentProvider.getId(); - - // If on 'refresh'-mode, replaces the callback array. The previous - // array may be remaining in the closure captured by previous tasks. - if (refresh) - item[id].callbacks = []; - var fetchedCallbacks = item[id].callbacks; - - var onFetched = function() { - if (type in item.properties) { - self.endBatchUpdates(); - // Got properties from provider. - callback(item.properties[type]); - } else { - tryNextProvider(); - } - }; - - var onProviderProperties = function(properties) { - var callbacks = fetchedCallbacks.splice(0); - item.time = new Date(); - self.mergeProperties_(entry, properties); - - for (var index = 0; index < callbacks.length; index++) { - callbacks[index](); - } - }; - - fetchedCallbacks.push(onFetched); - - // Querying now. - if (fetchedCallbacks.length === 1) - currentProvider.fetch(entry, type, onProviderProperties); - }; - - var tryNextProvider = function() { - if (providers.length === 0) { - // If not found, then mark the property as unavailable, so it's not - // retrieved again. - if (!(type in item.properties)) - item.properties[type] = null; - - self.endBatchUpdates(); - setTimeout(callback.bind(null, item.properties[type]), 0); - return; - } - - currentProvider = providers.shift(); - if (currentProvider.supportsEntry(entry) && - currentProvider.providesType(type)) { - queryProvider(); - } else { - tryNextProvider(); - } - }; - - tryNextProvider(); -}; - -/** - * Returns the cached metadata value, or |null| if not present. - * @param {Entry} entry Entry. - * @param {string} type The metadata type. - * @return {Object} The metadata or null. - */ -MetadataCache.prototype.getCached = function(entry, type) { - // Entry.cachedUrl may be set in DirectoryContents.onNewEntries_(). - // See the comment there for detail. - var entryURL = entry.cachedUrl || entry.toURL(); - var cache = this.cache_[entryURL]; - return cache ? (cache.properties[type] || null) : null; -}; - -/** - * Puts the metadata into cache - * @param {Entry|Array.<Entry>} entries The list of entries. May be just a - * single entry. - * @param {string} type The metadata type. - * @param {Array.<Object>} values List of corresponding metadata values. - */ -MetadataCache.prototype.set = function(entries, type, values) { - if (!(entries instanceof Array)) { - entries = [entries]; - values = [values]; - } - - this.startBatchUpdates(); - for (var index = 0; index < entries.length; index++) { - var entryURL = entries[index].toURL(); - if (!(entryURL in this.cache_)) { - this.cache_[entryURL] = this.createEmptyItem_(); - this.totalCount_++; - } - this.cache_[entryURL].properties[type] = values[index]; - this.notifyObservers_(entries[index], type); - } - this.endBatchUpdates(); -}; - -/** - * Clears the cached metadata values. - * @param {Entry|Array.<Entry>} entries The list of entries. May be just a - * single entry. - * @param {string} type The metadata types or * for any type. - */ -MetadataCache.prototype.clear = function(entries, type) { - if (!(entries instanceof Array)) - entries = [entries]; - - this.clearByUrl( - entries.map(function(entry) { return entry.toURL(); }), - type); -}; - -/** - * Clears the cached metadata values. This method takes an URL since some items - * may be already removed and can't be fetches their entry. - * - * @param {Array.<string>} urls The list of URLs. - * @param {string} type The metadata types or * for any type. - */ -MetadataCache.prototype.clearByUrl = function(urls, type) { - var types = type.split('|'); - - for (var index = 0; index < urls.length; index++) { - var entryURL = urls[index]; - if (entryURL in this.cache_) { - if (type === '*') { - this.cache_[entryURL].properties = {}; - } else { - for (var j = 0; j < types.length; j++) { - var type = types[j]; - delete this.cache_[entryURL].properties[type]; - } - } - } - } -}; - -/** - * Clears the cached metadata values recursively. - * @param {Entry} entry An entry to be cleared recursively from cache. - * @param {string} type The metadata types or * for any type. - */ -MetadataCache.prototype.clearRecursively = function(entry, type) { - var types = type.split('|'); - var keys = Object.keys(this.cache_); - var entryURL = entry.toURL(); - - for (var index = 0; index < keys.length; index++) { - var cachedEntryURL = keys[index]; - if (cachedEntryURL.substring(0, entryURL.length) === entryURL) { - if (type === '*') { - this.cache_[cachedEntryURL].properties = {}; - } else { - for (var j = 0; j < types.length; j++) { - var type = types[j]; - delete this.cache_[cachedEntryURL].properties[type]; - } - } - } - } -}; - -/** - * Adds an observer, which will be notified when metadata changes. - * @param {Entry} entry The root entry to look at. - * @param {number} relation This defines, which items will trigger the observer. - * See comments to |MetadataCache.EXACT| and others. - * @param {string} type The metadata type. - * @param {function(Array.<Entry>, Object.<string, Object>)} observer Map of - * entries and corresponding metadata values are passed to this callback. - * @return {number} The observer id, which can be used to remove it. - */ -MetadataCache.prototype.addObserver = function( - entry, relation, type, observer) { - var entryURL = entry.toURL(); - - // Escape following regexp special characters: - // \^$.*+?|&{}[]()<> - var escapedEntryURL = entryURL.replace( - /([\\\^\$\.\*\+\?\|\&\{\}\[\]\(\)\<\>])/g, - '\\$1'); - - var re; - if (relation === MetadataCache.CHILDREN) - re = escapedEntryURL + '(/[^/]*)?'; - else if (relation === MetadataCache.DESCENDANTS) - re = escapedEntryURL + '(/.*)?'; - else - re = escapedEntryURL; - - var id = ++this.observerId_; - this.observers_.push({ - re: new RegExp('^' + re + '$'), - type: type, - callback: observer, - id: id, - pending: {} - }); - - return id; -}; - -/** - * Removes the observer. - * @param {number} id Observer id. - * @return {boolean} Whether observer was removed or not. - */ -MetadataCache.prototype.removeObserver = function(id) { - for (var index = 0; index < this.observers_.length; index++) { - if (this.observers_[index].id === id) { - this.observers_.splice(index, 1); - return true; - } - } - return false; -}; - -/** - * Start batch updates. - */ -MetadataCache.prototype.startBatchUpdates = function() { - this.batchCount_++; - if (this.batchCount_ === 1) - this.lastBatchStart_ = new Date(); -}; - -/** - * End batch updates. Notifies observers if all nested updates are finished. - */ -MetadataCache.prototype.endBatchUpdates = function() { - this.batchCount_--; - if (this.batchCount_ !== 0) return; - if (this.totalCount_ > this.currentEvictionThreshold_()) - this.evict_(); - for (var index = 0; index < this.observers_.length; index++) { - var observer = this.observers_[index]; - var entries = []; - var properties = {}; - for (var entryURL in observer.pending) { - if (observer.pending.hasOwnProperty(entryURL) && - entryURL in this.cache_) { - var entry = observer.pending[entryURL]; - entries.push(entry); - properties[entryURL] = - this.cache_[entryURL].properties[observer.type] || null; - } - } - observer.pending = {}; - if (entries.length > 0) { - observer.callback(entries, properties); - } - } -}; - -/** - * Notifies observers or puts the data to pending list. - * @param {Entry} entry Changed entry. - * @param {string} type Metadata type. - * @private - */ -MetadataCache.prototype.notifyObservers_ = function(entry, type) { - var entryURL = entry.toURL(); - for (var index = 0; index < this.observers_.length; index++) { - var observer = this.observers_[index]; - if (observer.type === type && observer.re.test(entryURL)) { - if (this.batchCount_ === 0) { - // Observer expects array of urls and map of properties. - var property = {}; - property[entryURL] = this.cache_[entryURL].properties[type] || null; - observer.callback( - [entry], property); - } else { - observer.pending[entryURL] = entry; - } - } - } -}; - -/** - * Removes the oldest items from the cache. - * This method never removes the items from last batch. - * @private - */ -MetadataCache.prototype.evict_ = function() { - var toRemove = []; - - // We leave only a half of items, so we will not call evict_ soon again. - var desiredCount = this.currentEvictionThreshold_(); - var removeCount = this.totalCount_ - desiredCount; - for (var url in this.cache_) { - if (this.cache_.hasOwnProperty(url) && - this.cache_[url].time < this.lastBatchStart_) { - toRemove.push(url); - } - } - - toRemove.sort(function(a, b) { - var aTime = this.cache_[a].time; - var bTime = this.cache_[b].time; - return aTime < bTime ? -1 : aTime > bTime ? 1 : 0; - }.bind(this)); - - removeCount = Math.min(removeCount, toRemove.length); - this.totalCount_ -= removeCount; - for (var index = 0; index < removeCount; index++) { - delete this.cache_[toRemove[index]]; - } -}; - -/** - * @return {Object} Empty cache item. - * @private - */ -MetadataCache.prototype.createEmptyItem_ = function() { - var item = {properties: {}}; - for (var index = 0; index < this.providers_.length; index++) { - item[this.providers_[index].getId()] = {callbacks: []}; - } - return item; -}; - -/** - * Caches all the properties from data to cache entry for the entry. - * @param {Entry} entry The file entry. - * @param {Object} data The properties. - * @private - */ -MetadataCache.prototype.mergeProperties_ = function(entry, data) { - if (data === null) return; - var entryURL = entry.toURL(); - if (!(entryURL in this.cache_)) { - this.cache_[entryURL] = this.createEmptyItem_(); - this.totalCount_++; - } - var properties = this.cache_[entryURL].properties; - for (var type in data) { - if (data.hasOwnProperty(type)) { - properties[type] = data[type]; - this.notifyObservers_(entry, type); - } - } -}; - -/** - * Base class for metadata providers. - * @constructor - */ -function MetadataProvider() { -} - -/** - * @param {Entry} entry The entry. - * @return {boolean} Whether this provider supports the entry. - */ -MetadataProvider.prototype.supportsEntry = function(entry) { return false; }; - -/** - * @param {string} type The metadata type. - * @return {boolean} Whether this provider provides this metadata. - */ -MetadataProvider.prototype.providesType = function(type) { return false; }; - -/** - * @return {string} Unique provider id. - */ -MetadataProvider.prototype.getId = function() { return ''; }; - -/** - * @return {boolean} Whether provider is ready. - */ -MetadataProvider.prototype.isInitialized = function() { return true; }; - -/** - * Fetches the metadata. It's suggested to return all the metadata this provider - * can fetch at once. - * @param {Entry} entry File entry. - * @param {string} type Requested metadata type. - * @param {function(Object)} callback Callback expects a map from metadata type - * to metadata value. This callback must be called asynchronously. - */ -MetadataProvider.prototype.fetch = function(entry, type, callback) { - throw new Error('Default metadata provider cannot fetch.'); -}; - - -/** - * Provider of filesystem metadata. - * This provider returns the following objects: - * filesystem: { size, modificationTime } - * @constructor - * @extends {MetadataProvider} - */ -function FilesystemProvider() { - MetadataProvider.call(this); -} - -FilesystemProvider.prototype = { - __proto__: MetadataProvider.prototype -}; - -/** - * @param {Entry} entry The entry. - * @return {boolean} Whether this provider supports the entry. - */ -FilesystemProvider.prototype.supportsEntry = function(entry) { - return true; -}; - -/** - * @param {string} type The metadata type. - * @return {boolean} Whether this provider provides this metadata. - */ -FilesystemProvider.prototype.providesType = function(type) { - return type === 'filesystem'; -}; - -/** - * @return {string} Unique provider id. - */ -FilesystemProvider.prototype.getId = function() { return 'filesystem'; }; - -/** - * Fetches the metadata. - * @param {Entry} entry File entry. - * @param {string} type Requested metadata type. - * @param {function(Object)} callback Callback expects a map from metadata type - * to metadata value. This callback is called asynchronously. - */ -FilesystemProvider.prototype.fetch = function( - entry, type, callback) { - function onError(error) { - callback(null); - } - - function onMetadata(entry, metadata) { - callback({ - filesystem: { - size: (entry.isFile ? (metadata.size || 0) : -1), - modificationTime: metadata.modificationTime - } - }); - } - - entry.getMetadata(onMetadata.bind(null, entry), onError); -}; - -/** - * Provider of metadata for entries on the external file system backend. - * This provider returns the following objects: - * external: { pinned, hosted, present, customIconUrl, etc. } - * thumbnail: { url, transform } - * @param {VolumeManagerCommon.VolumeInfoProvider} volumeManager Volume manager - * instance. - * @constructor - * @extends {MetadataProvider} - */ -function ExternalProvider(volumeManager) { - MetadataProvider.call(this); - - /** - * @type {VolumeManagerCommon.VolumeInfoProvider} - * @private - */ - this.volumeManager_ = volumeManager; - - // We batch metadata fetches into single API call. - this.entries_ = []; - this.callbacks_ = []; - this.scheduled_ = false; - - this.callApiBound_ = this.callApi_.bind(this); -} - -ExternalProvider.prototype = { - __proto__: MetadataProvider.prototype -}; - -/** - * @param {Entry} entry The entry. - * @return {boolean} Whether this provider supports the entry. - */ -ExternalProvider.prototype.supportsEntry = function(entry) { - var volumeInfo = this.volumeManager_.getVolumeInfo(entry); - if (!volumeInfo) - return false; - return volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DRIVE || - volumeInfo.volumeType === VolumeManagerCommon.VolumeType.PROVIDED; -}; - -/** - * @param {string} type The metadata type. - * @return {boolean} Whether this provider provides this metadata. - */ -ExternalProvider.prototype.providesType = function(type) { - return type === 'external' || type === 'thumbnail' || - type === 'media' || type === 'filesystem'; -}; - -/** - * @return {string} Unique provider id. - */ -ExternalProvider.prototype.getId = function() { return 'external'; }; - -/** - * Fetches the metadata. - * @param {Entry} entry File entry. - * @param {string} type Requested metadata type. - * @param {function(Object)} callback Callback expects a map from metadata type - * to metadata value. This callback is called asynchronously. - */ -ExternalProvider.prototype.fetch = function(entry, type, callback) { - this.entries_.push(entry); - this.callbacks_.push(callback); - if (!this.scheduled_) { - this.scheduled_ = true; - setTimeout(this.callApiBound_, 0); - } -}; - -/** - * Schedules the API call. - * @private - */ -ExternalProvider.prototype.callApi_ = function() { - this.scheduled_ = false; - - var entries = this.entries_; - var callbacks = this.callbacks_; - this.entries_ = []; - this.callbacks_ = []; - var self = this; - - // TODO(mtomasz): Move conversion from entry to url to custom bindings. - // crbug.com/345527. - var entryURLs = util.entriesToURLs(entries); - chrome.fileManagerPrivate.getEntryProperties( - entryURLs, - ['size', 'modificationTime', 'thumbnailUrl', 'imageWidth', 'imageHeight', - 'imageRotation', 'pinned', 'present', 'hosted', 'availableOffline', - 'availableWhenMetered', 'dirty', 'customIconUrl', 'contentMimeType', - 'sharedWithMe', 'shared', 'externalFileUrl'], - function(propertiesList) { - console.assert(propertiesList.length === callbacks.length); - for (var i = 0; i < callbacks.length; i++) { - callbacks[i](self.convert_(propertiesList[i], entries[i])); - } - }); -}; - -/** - * Converts API metadata to internal format. - * @param {!EntryProperties} data Metadata from API call. - * @param {!Entry} entry File entry. - * @return {!Object} Metadata in internal format. - * @private - */ -ExternalProvider.prototype.convert_ = function(data, entry) { - var result = {}; - result.external = { - present: data.present, - pinned: data.pinned, - hosted: data.hosted, - dirty: data.dirty, - imageWidth: data.imageWidth, - imageHeight: data.imageHeight, - imageRotation: data.imageRotation, - availableOffline: data.availableOffline, - availableWhenMetered: data.availableWhenMetered, - customIconUrl: data.customIconUrl || '', - contentMimeType: data.contentMimeType || '', - sharedWithMe: data.sharedWithMe, - shared: data.shared, - thumbnailUrl: data.thumbnailUrl, // Thumbnail passed from external server. - externalFileUrl: data.externalFileUrl - }; - - result.filesystem = { - size: (entry.isFile ? (data.size || 0) : -1), - modificationTime: new Date(data.modificationTime) - }; - - // TODO(mtomasz): Remove all of the if logic in the new metadata cache. - // If the file is not present, then use the thumbnail url instead of - // extracting the thumbnail from contents. - if (data.present === false) { - if ('thumbnailUrl' in data) { - result.thumbnail = { - url: data.thumbnailUrl, - transform: null - }; - } else { - // Not present in cache, so do not allow to generate it by next providers. - result.thumbnail = {url: '', transform: null}; - } - } - - // If not present in cache, then do not allow to fetch media by next - // providers. - if (data.present === false) - result.media = {}; - - return result; -}; - - -/** - * Provider of content metadata. - * This provider returns the following objects: - * thumbnail: { url, transform } - * media: { artist, album, title, width, height, imageTransform, etc. } - * fetchedMedia: { same fields here } - * @param {!MessagePort=} opt_messagePort Message port overriding the default - * worker port. - * @constructor - * @extends {MetadataProvider} - */ -function ContentProvider(opt_messagePort) { - MetadataProvider.call(this); - - // Pass all URLs to the metadata reader until we have a correct filter. - this.urlFilter_ = /.*/; - - var dispatcher = opt_messagePort ? - opt_messagePort : new SharedWorker(ContentProvider.WORKER_SCRIPT).port; - dispatcher.onmessage = this.onMessage_.bind(this); - dispatcher.postMessage({verb: 'init'}); - dispatcher.start(); - this.dispatcher_ = dispatcher; - - // Initialization is not complete until the Worker sends back the - // 'initialized' message. See below. - this.initialized_ = false; - - /** - * Map from Entry.toURL() to callback. - * Note that simultaneous requests for same url are handled in MetadataCache. - * @type {!Object<!string, !Array<function(Object)>>} - * @const - * @private - */ - this.callbacks_ = {}; -} - -/** - * Path of a worker script. - * @type {string} - */ -ContentProvider.WORKER_SCRIPT = - 'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/' + - 'foreground/js/metadata/metadata_dispatcher.js'; - -ContentProvider.prototype = { - __proto__: MetadataProvider.prototype -}; - -/** - * @param {Entry} entry The entry. - * @return {boolean} Whether this provider supports the entry. - */ -ContentProvider.prototype.supportsEntry = function(entry) { - return !!entry.toURL().match(this.urlFilter_); -}; - -/** - * @param {string} type The metadata type. - * @return {boolean} Whether this provider provides this metadata. - */ -ContentProvider.prototype.providesType = function(type) { - return type === 'thumbnail' || type === 'fetchedMedia' || type === 'media'; -}; - -/** - * @return {string} Unique provider id. - */ -ContentProvider.prototype.getId = function() { return 'content'; }; - -/** - * Fetches the metadata. - * @param {Entry} entry File entry. - * @param {string} type Requested metadata type. - * @param {function(Object)} callback Callback expects a map from metadata type - * to metadata value. This callback is called asynchronously. - */ -ContentProvider.prototype.fetch = function(entry, type, callback) { - if (entry.isDirectory) { - setTimeout(callback.bind(null, {}), 0); - return; - } - var url = entry.toURL(); - if (this.callbacks_[url]) { - this.callbacks_[url].push(callback); - } else { - this.callbacks_[url] = [callback]; - this.dispatcher_.postMessage({verb: 'request', arguments: [url]}); - } -}; - -/** - * Dispatch a message from a metadata reader to the appropriate on* method. - * @param {Object} event The event. - * @private - */ -ContentProvider.prototype.onMessage_ = function(event) { - var data = event.data; - - var methodName = - 'on' + data.verb.substr(0, 1).toUpperCase() + data.verb.substr(1) + '_'; - - if (!(methodName in this)) { - console.error('Unknown message from metadata reader: ' + data.verb, data); - return; - } - - this[methodName].apply(this, data.arguments); -}; - -/** - * @return {boolean} Whether provider is ready. - */ -ContentProvider.prototype.isInitialized = function() { - return this.initialized_; -}; - -/** - * Handles the 'initialized' message from the metadata reader Worker. - * @param {Object} regexp Regexp of supported urls. - * @private - */ -ContentProvider.prototype.onInitialized_ = function(regexp) { - this.urlFilter_ = regexp; - - // Tests can monitor for this state with - // ExtensionTestMessageListener listener("worker-initialized"); - // ASSERT_TRUE(listener.WaitUntilSatisfied()); - // Automated tests need to wait for this, otherwise we crash in - // browser_test cleanup because the worker process still has - // URL requests in-flight. - util.testSendMessage('worker-initialized'); - this.initialized_ = true; -}; - -/** - * Converts content metadata from parsers to the internal format. - * @param {Object} metadata The content metadata. - * @param {Object=} opt_result The internal metadata object ot put result in. - * @return {Object!} Converted metadata. - */ -ContentProvider.ConvertContentMetadata = function(metadata, opt_result) { - var result = opt_result || {}; - - if ('thumbnailURL' in metadata) { - metadata.thumbnailTransform = metadata.thumbnailTransform || null; - result.thumbnail = { - url: metadata.thumbnailURL, - transform: metadata.thumbnailTransform - }; - } - - for (var key in metadata) { - if (metadata.hasOwnProperty(key)) { - if (!result.media) - result.media = {}; - result.media[key] = metadata[key]; - } - } - - if (result.media) - result.fetchedMedia = result.media; - - return result; -}; - -/** - * Handles the 'result' message from the worker. - * @param {string} url File url. - * @param {Object} metadata The metadata. - * @private - */ -ContentProvider.prototype.onResult_ = function(url, metadata) { - var callbacks = this.callbacks_[url]; - delete this.callbacks_[url]; - for (var i = 0; i < callbacks.length; i++) { - callbacks[i](ContentProvider.ConvertContentMetadata(metadata)); - } -}; - -/** - * Handles the 'error' message from the worker. - * @param {string} url File entry. - * @param {string} step Step failed. - * @param {string} error Error description. - * @param {Object?} metadata The metadata, if available. - * @private - */ -ContentProvider.prototype.onError_ = function(url, step, error, metadata) { - if (MetadataCache.log) // Avoid log spam by default. - console.warn('metadata: ' + url + ': ' + step + ': ' + error); - metadata = metadata || {}; - // Prevent asking for thumbnail again. - metadata.thumbnailURL = ''; - this.onResult_(url, metadata); -}; - -/** - * Handles the 'log' message from the worker. - * @param {Array.<*>} arglist Log arguments. - * @private - */ -ContentProvider.prototype.onLog_ = function(arglist) { - if (MetadataCache.log) // Avoid log spam by default. - console.log.apply(console, ['metadata:'].concat(arglist)); -};
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item.js index 5f0b8a2f4..ec2bd71d 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item.js
@@ -25,6 +25,7 @@ var loadRequested = []; for (var i = 0; i < names.length; i++) { var name = names[i]; + assert(!/Error$/.test(name)); // Check if the property needs to be updated. if (this.properties_[name] && this.properties_[name].state !== @@ -44,6 +45,7 @@ MetadataCacheItem.prototype.startRequests = function(requestId, names) { for (var i = 0; i < names.length; i++) { var name = names[i]; + assert(!/Error$/.test(name)); if (!this.properties_[name]) this.properties_[name] = new MetadataCacheItemProperty(); this.properties_[name].requestId = requestId; @@ -61,6 +63,12 @@ var changed = false; var object = /** @type {!Object} */(typedObject); for (var name in object) { + if (/.Error$/.test(name) && object[name]) + object[name.substr(0, name.length - 5)] = undefined; + } + for (var name in object) { + if (/.Error$/.test(name)) + continue; if (!this.properties_[name]) this.properties_[name] = new MetadataCacheItemProperty(); if (requestId < this.properties_[name].requestId || @@ -71,6 +79,7 @@ changed = true; this.properties_[name].requestId = requestId; this.properties_[name].value = object[name]; + this.properties_[name].error = object[name + 'Error']; this.properties_[name].state = MetadataCacheItemPropertyState.FULFILLED; } return changed; @@ -100,8 +109,11 @@ var result = /** @type {!Object} */(new MetadataItem()); for (var i = 0; i < names.length; i++) { var name = names[i]; - if (this.properties_[name]) + assert(!/Error$/.test(name)); + if (this.properties_[name]) { result[name] = this.properties_[name].value; + result[name + 'Error'] = this.properties_[name].error; + } } return /** @type {!MetadataItem} */(result); }; @@ -116,6 +128,7 @@ var property = this.properties_[name]; clonedItem.properties_[name] = new MetadataCacheItemProperty(); clonedItem.properties_[name].value = property.value; + clonedItem.properties_[name].error = property.error; clonedItem.properties_[name].requestId = property.requestId; clonedItem.properties_[name].state = property.state; } @@ -160,6 +173,11 @@ this.value = null; /** + * @public {Error} + */ + this.error = null; + + /** * Last request ID. * @public {number} */
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item_unittest.js index 4a5a04a..e9801d60f 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item_unittest.js
@@ -81,10 +81,27 @@ assertTrue(item.hasFreshCache(['propertyA'])); } -function testMetadataCacheShouldNotUpdateBeforeInvalidation() { +function testMetadataCacheItemShouldNotUpdateBeforeInvalidation() { var item = new MetadataCacheItem(); item.startRequests(1, item.createRequests(['property'])); item.storeProperties(1, {property: 'value1'}); item.storeProperties(2, {property: 'value2'}); assertEquals('value1', item.get(['property']).property); } + +function testMetadataCacheItemError() { + var item = new MetadataCacheItem(); + item.startRequests(1, item.createRequests(['property'])); + item.storeProperties( + 1, {property: 'value1', propertyError: new Error('Error')}); + assertEquals(undefined, item.get(['property']).property); + assertEquals('Error', item.get(['property']).propertyError.message); +} + +function testMetadataCacheItemErrorShouldNotFetchedDirectly() { + var item = new MetadataCacheItem(); + item.startRequests(1, item.createRequests(['property'])); + item.storeProperties( + 1, {property: 'value1', propertyError: new Error('Error')}); + assertThrows(function() { item.get(['propertyError']); }); +}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set.js index c4f2ea46..1356943 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set.js
@@ -30,9 +30,10 @@ * @return {!Array<!MetadataRequest>} */ MetadataCacheSet.prototype.createRequests = function(entries, names) { + var urls = util.entriesToURLs(entries); var requests = []; for (var i = 0; i < entries.length; i++) { - var item = this.items_.peek(entries[i].toURL()); + var item = this.items_.peek(urls[i]); var requestedNames = item ? item.createRequests(names) : names; if (requestedNames.length) requests.push(new MetadataRequest(entries[i], requestedNames)); @@ -48,7 +49,7 @@ MetadataCacheSet.prototype.startRequests = function(requestId, requests) { for (var i = 0; i < requests.length; i++) { var request = requests[i]; - var url = request.entry.toURL(); + var url = requests[i].entry.cachedUrl || requests[i].entry.toURL(); var item = this.items_.peek(url); if (!item) { item = new MetadataCacheItem(); @@ -69,8 +70,9 @@ MetadataCacheSet.prototype.storeProperties = function( requestId, entries, results) { var changedEntries = []; + var urls = util.entriesToURLs(entries); for (var i = 0; i < entries.length; i++) { - var url = entries[i].toURL(); + var url = urls[i]; var item = this.items_.peek(url); if (item && item.storeProperties(requestId, results[i])) changedEntries.push(entries[i]); @@ -93,8 +95,9 @@ */ MetadataCacheSet.prototype.get = function(entries, names) { var results = []; + var urls = util.entriesToURLs(entries); for (var i = 0; i < entries.length; i++) { - var item = this.items_.get(entries[i].toURL()); + var item = this.items_.get(urls[i]); results.push(item ? item.get(names) : {}); } return results; @@ -108,8 +111,9 @@ * @param {!Array<!Entry>} entries */ MetadataCacheSet.prototype.invalidate = function(requestId, entries) { + var urls = util.entriesToURLs(entries); for (var i = 0; i < entries.length; i++) { - var item = this.items_.peek(entries[i].toURL()); + var item = this.items_.peek(urls[i]); if (item) item.invalidate(requestId); } @@ -138,8 +142,9 @@ */ MetadataCacheSet.prototype.createSnapshot = function(entries) { var items = {}; + var urls = util.entriesToURLs(entries); for (var i = 0; i < entries.length; i++) { - var url = entries[i].toURL(); + var url = urls[i]; var item = this.items_.peek(url); if (item) items[url] = item.clone(); @@ -156,8 +161,9 @@ MetadataCacheSet.prototype.hasFreshCache = function(entries, names) { if (!names.length) return true; + var urls = util.entriesToURLs(entries); for (var i = 0; i < entries.length; i++) { - var item = this.items_.peek(entries[i].toURL()); + var item = this.items_.peek(urls[i]); if (!(item && item.hasFreshCache(names))) return false; }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set_unittest.html index b6f8d05..624306e 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set_unittest.html +++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set_unittest.html
@@ -11,6 +11,7 @@ <!-- Others --> <script src="../../../../../webui/resources/js/assert.js"></script> <script src="../../../common/js/unittest_util.js"></script> +<script src="../../../common/js/util.js"></script> <script src="metadata_cache_item.js"></script> <script src="metadata_cache_set.js"></script> <script src="metadata_item.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_unittest.html deleted file mode 100644 index d10fd381..0000000 --- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_unittest.html +++ /dev/null
@@ -1,11 +0,0 @@ -<!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. - --> -<script src="../../../../../webui/resources/js/assert.js"></script> -<script src="../../../common/js/mock_entry.js"></script> -<script src="../../../common/js/unittest_util.js"></script> -<script src="metadata_cache.js"></script> - -<script src="metadata_cache_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_unittest.js deleted file mode 100644 index 857d354ae..0000000 --- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_unittest.js +++ /dev/null
@@ -1,451 +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. - -/** @type {!MockFileSystem} */ -var fileSystem; - -function setUp() { - fileSystem = new MockFileSystem('volumeId'); -} - -/** - * Mock of MetadataProvider. - * - * @param {string} type Type of metadata provided by the class. - * @constructor - */ -function MockProvider(type) { - MetadataProvider.call(this); - this.type = type; - this.callbackPool = []; - Object.freeze(this); -} - -MockProvider.prototype = { - __proto__: MetadataProvider.prototype -}; - -MockProvider.prototype.supportsEntry = function(entry) { - return true; -}; - -MockProvider.prototype.providesType = function(type) { - return type === this.type; -}; - -MockProvider.prototype.getId = function() { - return this.type; -}; - -MockProvider.prototype.fetch = function(entry, type, callback) { - this.callbackPool.push(callback); -}; - -/** - * Short hand for the metadataCache.get. - * - * @param {MetadataCache} meatadataCache Metadata cache. - * @param {Array.<Entry>} entries Entries. - * @param {string} type Metadata type. - * @return {Promise} Promise to be fulfilled with the result metadata. - */ -function getMetadata(metadataCache, entries, type) { - return new Promise(metadataCache.get.bind(metadataCache, entries, type)); -}; - -/** - * Short hand for the metadataCache.getLatest. - * @param {MetadataCache} meatadataCache Metadata cache. - * @param {Array.<Entry>} entries Entries. - * @param {string} type Metadata type. - * @return {Promise} Promise to be fulfilled with the result metadata. - */ -function getLatest(metadataCache, entries, type) { - return new Promise(metadataCache.getLatest.bind( - metadataCache, entries, type)); -} - -/** - * Confirms metadata is cached for the same entry. - * - * @param {function(boolean=)} callback Callback to be called when test - * completes. If the test fails, true is passed to the function. - */ -function testCache(callback) { - var provider = new MockProvider('instrument'); - var metadataCache = new MetadataCache([provider]); - var entry = new MockFileEntry(fileSystem, '/music.txt'); - - var metadataFromProviderPromise = - getMetadata(metadataCache, [entry], 'instrument'); - var cachedBeforeFetchingPromise = - getMetadata(metadataCache, [entry], 'instrument'); - assertEquals(1, provider.callbackPool.length); - provider.callbackPool[0]({instrument: {name: 'banjo'}}); - var cachedAfterFethingPromise = - getMetadata(metadataCache, [entry], 'instrument'); - - // Provide should be called only once. - assertEquals(1, provider.callbackPool.length); - - reportPromise(Promise.all([ - metadataFromProviderPromise, - cachedBeforeFetchingPromise, - cachedAfterFethingPromise - ]).then(function(metadata) { - assertDeepEquals([{name: 'banjo'}], metadata[0]); - assertDeepEquals([{name: 'banjo'}], metadata[1]); - assertDeepEquals([{name: 'banjo'}], metadata[1]); - }), callback); -} - -/** - * Confirms metadata is not cached for different entries. - * - * @param {function(boolean=)} callback Callback to be called when test - * completes. If the test fails, true is passed to the function. - */ -function testNoCacheForDifferentEntries(callback) { - var provider = new MockProvider('instrument'); - var metadataCache = new MetadataCache([provider]); - - var entry1 = new MockFileEntry(fileSystem, '/music1.txt'); - var entry2 = new MockFileEntry(fileSystem, '/music2.txt'); - - var entry1MetadataPromise = - getMetadata(metadataCache, [entry1], 'instrument'); - var entry2MetadataPromise = - getMetadata(metadataCache, [entry2], 'instrument'); - - // Provide should be called for each entry. - assertEquals(2, provider.callbackPool.length); - - provider.callbackPool[0]({instrument: {name: 'banjo'}}); - provider.callbackPool[1]({instrument: {name: 'fiddle'}}); - - reportPromise(Promise.all([ - entry1MetadataPromise, - entry2MetadataPromise - ]).then(function(metadata) { - assertDeepEquals([{name: 'banjo'}], metadata[0]); - assertDeepEquals([{name: 'fiddle'}], metadata[1]); - }), callback); -} - -/** - * Confirms metadata is not cached for different entries. - * - * @param {function(boolean=)} callback Callback to be called when test - * completes. If the test fails, true is passed to the function. - */ -function testNoCacheForDifferentTypes(callback) { - var providers = [ - new MockProvider('instrument'), - new MockProvider('beat') - ]; - var metadataCache = new MetadataCache(providers); - - var entry = new MockFileEntry(fileSystem, '/music.txt'); - var instrumentMedatataPromise = - getMetadata(metadataCache, [entry], 'instrument'); - var beatMetadataPromise = getMetadata(metadataCache, [entry], 'beat'); - assertEquals(1, providers[0].callbackPool.length); - assertEquals(1, providers[1].callbackPool.length); - - providers[0].callbackPool[0]({instrument: {name: 'banjo'}}); - providers[1].callbackPool[0]({beat: {number: 2}}); - reportPromise(Promise.all([ - instrumentMedatataPromise, - beatMetadataPromise - ]).then(function(metadata) { - assertDeepEquals([{name: 'banjo'}], metadata[0]); - assertDeepEquals([{number: 2}], metadata[1]); - }), callback); -} - -/** - * Tests to call MetadataCache.get in verious order. - * - * @param {function(boolean=)} callback Callback to be called when test - * completes. If the test fails, true is passed to the function. - */ -function testGetDiffrentTypesInVeriousOrders(callback) { - var providers = [ - new MockProvider('instrument'), - new MockProvider('beat') - ]; - var metadataCache = new MetadataCache(providers); - - var getAndCheckMetadata = function(entry, type, expected) { - return getMetadata(metadataCache, [entry], type).then(function(metadata) { - assertDeepEquals([expected], metadata); - }); - }; - - var entry1 = new MockFileEntry(fileSystem, '/music1.txt'); - var promise1 = Promise.all([ - getAndCheckMetadata(entry1, 'instrument', {name: 'banjo'}), - getAndCheckMetadata(entry1, 'beat', {number: 2}), - getAndCheckMetadata( - entry1, - 'instrument|beat', - {instrument: {name: 'banjo'}, beat: {number: 2}}) - ]); - assertEquals(1, providers[0].callbackPool.length); - assertEquals(1, providers[1].callbackPool.length); - - var entry2 = new MockFileEntry(fileSystem, '/music2.txt'); - var promise2 = Promise.all([ - getAndCheckMetadata(entry2, 'instrument', {name: 'banjo'}), - getAndCheckMetadata( - entry2, - 'instrument|beat', - {instrument: {name: 'banjo'}, beat: {number: 2}}), - getAndCheckMetadata(entry2, 'beat', {number: 2}) - ]); - assertEquals(2, providers[0].callbackPool.length); - assertEquals(2, providers[1].callbackPool.length); - - var entry3 = new MockFileEntry(fileSystem, '/music3.txt'); - var promise3 = Promise.all([ - getAndCheckMetadata( - entry3, - 'instrument|beat', - {instrument: {name: 'banjo'}, beat: {number: 2}}), - getAndCheckMetadata(entry3, 'instrument', {name: 'banjo'}), - getAndCheckMetadata(entry3, 'beat', {number: 2}) - ]); - assertEquals(3, providers[0].callbackPool.length); - assertEquals(3, providers[1].callbackPool.length); - - for (var i = 0; i < providers[0].callbackPool.length; i++) { - providers[0].callbackPool[i]({instrument: {name: 'banjo'}}); - } - for (var i = 0; i < providers[1].callbackPool.length; i++) { - providers[1].callbackPool[i]({beat: {number: 2}}); - } - - reportPromise( - Promise.all([promise1, promise2, promise3]), - callback); -} - -/** - * Tests MetadataCache.getCached. - * - * @param {function(boolean=)} callback Callback to be called when test - * completes. If the test fails, true is passed to the function. - */ -function testGetCached(callback) { - var provider = new MockProvider('instrument'); - var metadataCache = new MetadataCache([provider]); - - var entry = new MockFileEntry(fileSystem, '/music.txt'); - - // Check the cache does exist before calling getMetadata. - assertEquals(null, metadataCache.getCached(entry, 'instrument')); - var promise = getMetadata(metadataCache, [entry], 'instrument'); - - // Check the cache does exist after calling getMetadata but before receiving - // metadata from a provider. - assertEquals(null, metadataCache.getCached(entry, 'instrument')); - - provider.callbackPool[0]({instrument: {name: 'banjo'}}); - reportPromise(promise.then(function(metadata) { - assertDeepEquals([{name: 'banjo'}], metadata); - assertDeepEquals( - {name: 'banjo'}, - metadataCache.getCached(entry, 'instrument')); - }), callback); -} - -/** - * Tests MetadataCache.getLatest. - * - * @param {function(boolean=)} callback Callback to be called when test - * completes. If the test fails, true is passed to the function. - */ -function testGetLatest(callback) { - var provider = new MockProvider('instrument'); - var metadataCache = new MetadataCache([provider]); - var entry = new MockFileEntry(fileSystem, '/music.txt'); - - var promise = getLatest(metadataCache, [entry], 'instrument'); - assertEquals(1, provider.callbackPool.length); - provider.callbackPool[0]({instrument: {name: 'banjo'}}); - - reportPromise(promise.then(function(metadata) { - assertDeepEquals([{name: 'banjo'}], metadata); - }), callback); -}; - -/** - * Tests that MetadataCache.getLatest ignore the existing cache. - * - * @param {function(boolean=)} callback Callback to be called when test - * completes. If the test fails, true is passed to the function. - */ -function testGetLatestToIgnoreCache(callback) { - var provider = new MockProvider('instrument'); - var metadataCache = new MetadataCache([provider]); - var entry = new MockFileEntry(fileSystem, '/music.txt'); - - var promise1 = getMetadata(metadataCache, [entry], 'instrument'); - assertEquals(1, provider.callbackPool.length); - provider.callbackPool[0]({instrument: {name: 'banjo'}}); - assertDeepEquals( - {name: 'banjo'}, metadataCache.getCached(entry, 'instrument')); - var promise2 = getLatest(metadataCache, [entry], 'instrument'); - assertEquals(2, provider.callbackPool.length); - assertDeepEquals( - {name: 'banjo'}, metadataCache.getCached(entry, 'instrument')); - provider.callbackPool[1]({instrument: {name: 'fiddle'}}); - assertDeepEquals( - {name: 'fiddle'}, metadataCache.getCached(entry, 'instrument')); - - reportPromise(Promise.all([promise1, promise2]).then(function(metadata) { - assertDeepEquals([{name: 'banjo'}], metadata[0]); - assertDeepEquals([{name: 'fiddle'}], metadata[1]); - }), callback); -} - -/** - * Tests that the result of getLatest does not passed to the previous call of - * getMetadata. - * - * @param {function(boolean=)} callback Callback to be called when test - * completes. If the test fails, true is passed to the function. - */ -function testGetLatestAndPreviousCall(callback) { - var provider = new MockProvider('instrument'); - var metadataCache = new MetadataCache([provider]); - var entry = new MockFileEntry(fileSystem, '/music.txt'); - - var promise1 = getMetadata(metadataCache, [entry], 'instrument'); - assertEquals(1, provider.callbackPool.length); - var promise2 = getLatest(metadataCache, [entry], 'instrument'); - assertEquals(2, provider.callbackPool.length); - - provider.callbackPool[1]({instrument: {name: 'fiddle'}}); - provider.callbackPool[0]({instrument: {name: 'banjo'}}); - assertDeepEquals( - {name: 'banjo'}, metadataCache.getCached(entry, 'instrument')); - - reportPromise(Promise.all([promise1, promise2]).then(function(metadata) { - assertDeepEquals([{name: 'banjo'}], metadata[0]); - assertDeepEquals([{name: 'fiddle'}], metadata[1]); - }), callback); -} - -/** - * Tests the MetadataCache#clear method. - * - * @param {function(boolean=)} callback Callback to be called when test - * completes. If the test fails, true is passed to the function. - */ -function testClear(callback) { - var providers = [ - new MockProvider('instrument'), - new MockProvider('beat') - ]; - var metadataCache = new MetadataCache(providers); - var entry = new MockFileEntry(fileSystem, '/music.txt'); - - var promise1 = getMetadata(metadataCache, [entry], 'instrument'); - var promise2 = getMetadata(metadataCache, [entry], 'beat'); - assertEquals(1, providers[0].callbackPool.length); - assertEquals(1, providers[1].callbackPool.length); - providers[0].callbackPool[0]({instrument: {name: 'banjo'}}); - providers[1].callbackPool[0]({beat: {number: 2}}); - assertDeepEquals( - {name: 'banjo'}, metadataCache.getCached(entry, 'instrument')); - assertDeepEquals({number: 2}, metadataCache.getCached(entry, 'beat')); - - metadataCache.clear([entry], 'instrument'); - assertEquals( - null, metadataCache.getCached(entry, 'instrument')); - assertDeepEquals({number: 2}, metadataCache.getCached(entry, 'beat')); - - var promise3 = getMetadata(metadataCache, [entry], 'instrument'); - assertEquals(2, providers[0].callbackPool.length); - providers[0].callbackPool[1]({instrument: {name: 'fiddle'}}); - assertDeepEquals( - {name: 'fiddle'}, metadataCache.getCached(entry, 'instrument')); - - reportPromise(Promise.all([promise1, promise2, promise3]).then( - function(metadata) { - assertDeepEquals([{name: 'banjo'}], metadata[0]); - assertDeepEquals([{number: 2}], metadata[1]); - assertDeepEquals([{name: 'fiddle'}], metadata[2]); - }), callback); -} - -/** - * Tests the MetadataCache#addObserver method. - */ -function testAddObserver() { - var providers = [ - new MockProvider('instrument'), - new MockProvider('beat') - ]; - var metadataCache = new MetadataCache(providers); - - var directoryEntry = new MockFileEntry( - fileSystem, - '/mu\\^$.*.+?|&{}[si]()<>cs'); - var observerCalls = []; - var observerCallback = function(entries, properties) { - observerCalls.push({entries: entries, properties: properties}); - }; - - metadataCache.addObserver(directoryEntry, MetadataCache.CHILDREN, - 'filesystem', observerCallback); - - var fileEntry1 = new MockFileEntry(fileSystem, - '/mu\\^$.*.+?|&{}[si]()<>cs/foo.mp3'); - var fileEntry1URL = fileEntry1.toURL(); - metadataCache.set(fileEntry1, 'filesystem', 'test1'); - assertEquals(1, observerCalls.length); - assertArrayEquals([fileEntry1], observerCalls[0].entries); - assertEquals('test1', observerCalls[0].properties[fileEntry1URL]); - - var fileEntry2 = new MockFileEntry(fileSystem, - '/mu\\^$.*.+?|&{}[si]()<>cs/f.[o]o.mp3'); - var fileEntry2URL = fileEntry2.toURL(); - metadataCache.set(fileEntry2, 'filesystem', 'test2'); - assertEquals(2, observerCalls.length); - assertArrayEquals([fileEntry2], observerCalls[1].entries); - assertEquals('test2', observerCalls[1].properties[fileEntry2URL]); - - // Descendant case does not invoke the observer. - var fileEntry3 = new MockFileEntry(fileSystem, - '/mu\\^$.*.+?|&{}[si]()<>cs/foo/bar.mp3'); - metadataCache.set(fileEntry3, 'filesystem', 'test3'); - assertEquals(2, observerCalls.length); - - // This case does not invoke the observer. - // (This is a case which matches when regexp special chars are not escaped). - var fileEntry4 = new MockFileEntry(fileSystem, '/&{}i<>cs/foo.mp3'); - metadataCache.set(fileEntry4); - assertEquals(2, observerCalls.length); -} - -/** - * Tests content provider. - */ -function testContentProvider(callback) { - var entry = new MockFileEntry(fileSystem, '/sample.txt'); - var metadataCache = new MetadataCache([new ContentProvider({ - start: function() {}, - postMessage: function(message) { - if (message.verb == 'request') { - Promise.resolve().then(function() { - this.onmessage( - {data: {verb: 'result', arguments: [entry.toURL(), {}]}}); - }.bind(this)); - } - } - })]); - reportPromise(getLatest(metadataCache, [entry], 'media|thumbnail'), callback); -}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js index 6bd1664..5c089ae 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js
@@ -12,6 +12,7 @@ var ImageTransformation; /** + * Each property of MetadataItem has error property also. * @constructor * @struct */ @@ -23,123 +24,233 @@ this.size; /** + * @public {Error|undefined} + */ + this.sizeError; + + /** * @public {!Date|undefined} */ this.modificationTime; /** + * @public {Error|undefined} + */ + this.modificationTimeError; + + /** * Thumbnail URL obtained from external provider. * @public {string|undefined} */ this.thumbnailUrl; /** + * @public {Error|undefined} + */ + this.thumbnailUrlError; + + /** * @public {number|undefined} */ this.imageWidth; /** + * @public {Error|undefined} + */ + this.imageWidthError; + + /** * @public {number|undefined} */ this.imageHeight; /** + * @public {Error|undefined} + */ + this.imageHeightError; + + /** * @public {number|undefined} */ this.imageRotation; /** + * @public {Error|undefined} + */ + this.imageRotationError; + + /** * Thumbnail obtained from content provider. * @public {string|undefined} */ this.contentThumbnailUrl; /** + * @public {Error|undefined} + */ + this.contentThumbnailUrlError; + + /** * Thumbnail transformation obtained from content provider. * @public {!ImageTransformation|undefined} */ this.contentThumbnailTransform; /** + * @public {Error|undefined} + */ + this.contentThumbnailTransformError; + + /** * Image transformation obtained from content provider. * @public {!ImageTransformation|undefined} */ this.contentImageTransform; /** + * @public {Error|undefined} + */ + this.contentImageTransformError; + + /** * Whether the entry is pinned for ensuring it is available offline. * @public {boolean|undefined} */ this.pinned; /** + * @public {Error|undefined} + */ + this.pinnedError; + + /** * Whether the entry is cached locally. * @public {boolean|undefined} */ this.present; /** + * @public {Error|undefined} + */ + this.presentError; + + /** * Whether the entry is hosted document of google drive. * @public {boolean|undefined} */ this.hosted; /** + * @public {Error|undefined} + */ + this.hostedError; + + /** * Whether the entry is modified locally and not synched yet. * @public {boolean|undefined} */ this.dirty; /** + * @public {Error|undefined} + */ + this.dirtyError; + + /** * Whether the entry is present or hosted; * @public {boolean|undefined} */ this.availableOffline; /** + * @public {Error|undefined} + */ + this.availableOfflineError; + + /** * @public {boolean|undefined} */ this.availableWhenMetered; /** + * @public {Error|undefined} + */ + this.availableWhenMeteredError; + + /** * @public {string|undefined} */ this.customIconUrl; /** + * @public {Error|undefined} + */ + this.customIconUrlError; + + /** * @public {string|undefined} */ this.contentMimeType; /** + * @public {Error|undefined} + */ + this.contentMimeTypeError; + + /** * Whether the entry is shared explicitly with me. * @public {boolean|undefined} */ this.sharedWithMe; /** + * @public {Error|undefined} + */ + this.sharedWithMeError; + + /** * Whether the entry is shared publicly. * @public {boolean|undefined} */ this.shared; /** + * @public {Error|undefined} + */ + this.sharedError; + + /** * URL for open a file in browser tab. * @public {string|undefined} */ this.externalFileUrl; /** + * @public {Error|undefined} + */ + this.externalFileUrlError; + + /** * @public {string|undefined} */ this.mediaTitle; /** + * @public {Error|undefined} + */ + this.mediaTitleError; + + /** * @public {string|undefined} */ this.mediaArtist; /** + * @public {Error|undefined} + */ + this.mediaArtistError; + + /** * Mime type obtained by content provider based on URL. * TODO(hirono): Remove the mediaMimeType. * @public {string|undefined} @@ -147,13 +258,28 @@ this.mediaMimeType; /** + * @public {Error|undefined} + */ + this.mediaMimeTypeError; + + /** * "Image File Directory" obtained from EXIF header. * @public {!Object|undefined} */ this.ifd; /** + * @public {Error|undefined} + */ + this.ifdError; + + /** * @public {boolean|undefined} */ this.exifLittleEndian; + + /** + * @public {Error|undefined} + */ + this.exifLittleEndianError; }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_model.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model.js new file mode 100644 index 0000000..bd46fa8 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model.js
@@ -0,0 +1,240 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @param {!NewMetadataProvider} rawProvider + * @constructor + * @struct + */ +function MetadataModel(rawProvider) { + /** + * @private {!NewMetadataProvider} + * @const + */ + this.rawProvider_ = rawProvider; + + /** + * @private {!MetadataProviderCache} + * @const + */ + this.cache_ = new MetadataProviderCache(); + + /** + * @private {!Array<!MetadataProviderCallbackRequest<T>>} + * @const + */ + this.callbackRequests_ = []; +} + +/** + * @param {!VolumeManagerCommon.VolumeInfoProvider} volumeManager + * @return {!MetadataModel} + */ +MetadataModel.create = function(volumeManager) { + return new MetadataModel( + new MultiMetadataProvider( + new FileSystemMetadataProvider(), + new ExternalMetadataProvider(), + new ContentMetadataProvider(), + volumeManager)); +}; + +/** + * @return {!NewMetadataProvider} + */ +MetadataModel.prototype.getProvider = function() { + return this.rawProvider_; +}; + +/** + * Obtains metadata for entries. + * @param {!Array<!Entry>} entries Entries. + * @param {!Array<string>} names Metadata property names to be obtained. + * @return {!Promise<!Array<!MetadataItem>>} + */ +MetadataModel.prototype.get = function(entries, names) { + this.rawProvider_.checkPropertyNames(names); + + // Check if the results are cached or not. + if (this.cache_.hasFreshCache(entries, names)) + return Promise.resolve(this.getCache(entries, names)); + + // The LRU cache may be cached out when the callback is completed. + // To hold cached values, create snapshot of the cache for entries. + var requestId = this.cache_.generateRequestId(); + var snapshot = this.cache_.createSnapshot(entries); + var requests = snapshot.createRequests(entries, names); + snapshot.startRequests(requestId, requests); + this.cache_.startRequests(requestId, requests); + + // Register callback. + var promise = new Promise(function(fulfill) { + this.callbackRequests_.push(new MetadataProviderCallbackRequest( + entries, names, snapshot, fulfill)); + }.bind(this)); + + // If the requests are not empty, call the requests. + if (requests.length) { + this.rawProvider_.get(requests).then(function(list) { + // Obtain requested entries and ensure all the requested properties are + // contained in the result. + var requestedEntries = []; + for (var i = 0; i < requests.length; i++) { + requestedEntries.push(requests[i].entry); + for (var j = 0; j < requests[i].names.length; j++) { + var name = requests[i].names[j]; + if (!(name in list[i])) + list[i][name] = undefined; + } + } + + // Store cache. + this.cache_.storeProperties(requestId, requestedEntries, list); + + // Invoke callbacks. + var i = 0; + while (i < this.callbackRequests_.length) { + if (this.callbackRequests_[i].storeProperties( + requestId, requestedEntries, list)) { + // Callback was called. + this.callbackRequests_.splice(i, 1); + } else { + i++; + } + } + }.bind(this)); + } + + return promise; +}; + +/** + * Obtains metadata cache for entries. + * @param {!Array<!Entry>} entries Entries. + * @param {!Array<string>} names Metadata property names to be obtained. + * @return {!Array<!MetadataItem>} + */ +MetadataModel.prototype.getCache = function(entries, names) { + // Check if the property name is correct or not. + this.rawProvider_.checkPropertyNames(names); + return this.cache_.get(entries, names); +}; + +/** + * Clears old metadata for newly created entries. + * @param {!Array<!Entry>} entries + */ +MetadataModel.prototype.notifyEntriesCreated = function(entries) { + this.cache_.clear(util.entriesToURLs(entries)); +}; + +/** + * Clears metadata for deleted entries. + * @param {!Array<string>} urls Note it is not an entry list because we cannot + * obtain entries after removing them from the file system. + */ +MetadataModel.prototype.notifyEntriesRemoved = function(urls) { + this.cache_.clear(urls); +}; + +/** + * Invalidates metadata for updated entries. + * @param {!Array<!Entry>} entries + */ +MetadataModel.prototype.notifyEntriesChanged = function(entries) { + this.cache_.invalidate(this.cache_.generateRequestId(), entries); +}; + +/** + * Clears all cache. + */ +MetadataModel.prototype.clearAllCache = function() { + this.cache_.clearAll(); +}; + +/** + * Adds event listener to internal cache object. + * @param {string} type + * @param {function(Event):undefined} callback + */ +MetadataModel.prototype.addEventListener = function(type, callback) { + this.cache_.addEventListener(type, callback); +}; + +/** + * @param {!Array<!Entry>} entries + * @param {!Array<string>} names + * @param {!MetadataCacheSet} cache + * @param {function(!MetadataItem):undefined} fulfill + * @constructor + * @struct + */ +function MetadataProviderCallbackRequest(entries, names, cache, fulfill) { + /** + * @private {!Array<!Entry>} + * @const + */ + this.entries_ = entries; + + /** + * @private {!Array<string>} + * @const + */ + this.names_ = names; + + /** + * @private {!MetadataCacheSet} + * @const + */ + this.cache_ = cache; + + /** + * @private {function(!MetadataItem):undefined} + * @const + */ + this.fulfill_ = fulfill; +} + +/** + * Stores properties to snapshot cache of the callback request. + * If all the requested property are served, it invokes the callback. + * @param {number} requestId + * @param {!Array<!Entry>} entries + * @param {!Array<!MetadataItem>} objects + * @return {boolean} Whether the callback is invoked or not. + */ +MetadataProviderCallbackRequest.prototype.storeProperties = function( + requestId, entries, objects) { + this.cache_.storeProperties(requestId, entries, objects); + if (this.cache_.hasFreshCache(this.entries_, this.names_)) { + this.fulfill_(this.cache_.get(this.entries_, this.names_)); + return true; + } + return false; +}; + +/** + * Helper wrapper for LRUCache. + * @constructor + * @extends {MetadataCacheSet} + * @struct + */ +function MetadataProviderCache() { + MetadataCacheSet.call(this, new MetadataCacheSetStorageForObject({})); + + /** + * @private {number} + */ + this.requestIdCounter_ = 0; +} + +MetadataProviderCache.prototype.__proto__ = MetadataCacheSet.prototype; + +/** + * Generates a unique request ID every time when it is called. + * @return {number} + */ +MetadataProviderCache.prototype.generateRequestId = function() { + return this.requestIdCounter_++; +};
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.html new file mode 100644 index 0000000..8772ad45 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<!-- Copyright 2015 The Chromium Authors. All rights reserved. + -- Use of this source code is governed by a BSD-style license that can be + -- found in the LICENSE file. + --> +<!-- Base class --> +<script src="../../../../../webui/resources/js/cr.js"></script> +<script src="../../../../../webui/resources/js/cr/event_target.js"></script> +<script src="metadata_cache_set.js"></script> + +<!-- Others --> +<script src="../../../../../webui/resources/js/assert.js"></script> +<script src="../../../common/js/lru_cache.js"></script> +<script src="../../../common/js/unittest_util.js"></script> +<script src="../../../common/js/util.js"></script> +<script src="metadata_cache_item.js"></script> +<script src="metadata_item.js"></script> +<script src="metadata_model.js"></script> +<script src="new_metadata_provider.js"></script> + +<script src="metadata_model_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.js new file mode 100644 index 0000000..64dd6c9e --- /dev/null +++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.js
@@ -0,0 +1,172 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function TestMetadataProvider() { + NewMetadataProvider.call(this, ['property', 'propertyA', 'propertyB']); + this.requestCount = 0; +} + +TestMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype; + +TestMetadataProvider.prototype.get = function(requests) { + this.requestCount++; + return Promise.resolve(requests.map(function(request) { + var entry = request.entry; + var names = request.names; + var result = {}; + for (var i = 0; i < names.length; i++) { + result[names[i]] = entry.toURL() + ':' + names[i]; + } + return result; + })); +}; + +function TestEmptyMetadataProvider() { + NewMetadataProvider.call(this, ['property']); +} + +TestEmptyMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype; + +TestEmptyMetadataProvider.prototype.get = function(requests) { + return Promise.resolve(requests.map(function() { + return {}; + })); +}; + +function ManualTestMetadataProvider() { + NewMetadataProvider.call( + this, ['propertyA', 'propertyB', 'propertyC']); + this.callback = []; +} + +ManualTestMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype; + +ManualTestMetadataProvider.prototype.get = function(requests) { + return new Promise(function(fulfill) { + this.callback.push(fulfill); + }.bind(this)); +}; + +var entryA = { + toURL: function() { return "filesystem://A"; } +}; + +var entryB = { + toURL: function() { return "filesystem://B"; } +}; + +function testMetadataModelBasic(callback) { + var model = new MetadataModel(new TestMetadataProvider()); + reportPromise(model.get([entryA, entryB], ['property']).then( + function(results) { + assertEquals(1, model.getProvider().requestCount); + assertEquals('filesystem://A:property', results[0].property); + assertEquals('filesystem://B:property', results[1].property); + }), callback); +} + +function testMetadataModelRequestForCachedProperty(callback) { + var model = new MetadataModel(new TestMetadataProvider()); + reportPromise(model.get([entryA, entryB], ['property']).then( + function() { + // All the result should be cached here. + return model.get([entryA, entryB], ['property']); + }).then(function(results) { + assertEquals(1, model.getProvider().requestCount); + assertEquals('filesystem://A:property', results[0].property); + assertEquals('filesystem://B:property', results[1].property); + }), callback); +} + +function testMetadataModelRequestForCachedAndNonCachedProperty(callback) { + var model = new MetadataModel(new TestMetadataProvider()); + reportPromise(model.get([entryA, entryB], ['propertyA']).then( + function() { + assertEquals(1, model.getProvider().requestCount); + // propertyB has not been cached here. + return model.get([entryA, entryB], ['propertyA', 'propertyB']); + }).then(function(results) { + assertEquals(2, model.getProvider().requestCount); + assertEquals('filesystem://A:propertyA', results[0].propertyA); + assertEquals('filesystem://A:propertyB', results[0].propertyB); + assertEquals('filesystem://B:propertyA', results[1].propertyA); + assertEquals('filesystem://B:propertyB', results[1].propertyB); + }), callback); +} + +function testMetadataModelRequestForCachedAndNonCachedEntry(callback) { + var model = new MetadataModel(new TestMetadataProvider()); + reportPromise(model.get([entryA], ['property']).then( + function() { + assertEquals(1, model.getProvider().requestCount); + // entryB has not been cached here. + return model.get([entryA, entryB], ['property']); + }).then(function(results) { + assertEquals(2, model.getProvider().requestCount); + assertEquals('filesystem://A:property', results[0].property); + assertEquals('filesystem://B:property', results[1].property); + }), callback); +} + +function testMetadataModelRequestBeforeCompletingPreviousRequest( + callback) { + var model = new MetadataModel(new TestMetadataProvider()); + model.get([entryA], ['property']); + assertEquals(1, model.getProvider().requestCount); + // The result of first call has not been fetched yet. + reportPromise(model.get([entryA], ['property']).then( + function(results) { + assertEquals(1, model.getProvider().requestCount); + assertEquals('filesystem://A:property', results[0].property); + }), callback); +} + +function testMetadataModelNotUpdateCachedResultAfterRequest( + callback) { + var model = new MetadataModel(new ManualTestMetadataProvider()); + var promise = model.get([entryA], ['propertyA']); + model.getProvider().callback[0]([{propertyA: 'valueA1'}]); + reportPromise(promise.then(function() { + // 'propertyA' is cached here. + var promise1 = model.get([entryA], ['propertyA', 'propertyB']); + var promise2 = model.get([entryA], ['propertyC']); + // Returns propertyC. + model.getProvider().callback[2]( + [{propertyA: 'valueA2', propertyC: 'valueC'}]); + model.getProvider().callback[1]([{propertyB: 'valueB'}]); + return Promise.all([promise1, promise2]); + }).then(function(results) { + // The result should be cached value at the time when get was called. + assertEquals('valueA1', results[0][0].propertyA); + assertEquals('valueB', results[0][0].propertyB); + assertEquals('valueC', results[1][0].propertyC); + }), callback); +} + +function testMetadataModelGetCache(callback) { + var model = new MetadataModel(new TestMetadataProvider()); + var promise = model.get([entryA], ['property']); + var cache = model.getCache([entryA], ['property']); + assertEquals(null, cache[0].property); + reportPromise(promise.then(function() { + var cache = model.getCache([entryA], ['property']); + assertEquals(1, model.getProvider().requestCount); + assertEquals('filesystem://A:property', cache[0].property); + }), callback); +} + +function testMetadataModelUnknownProperty() { + var model = new MetadataModel(new TestMetadataProvider()); + assertThrows(function() { + model.get([entryA], ['unknown']); + }); +} + +function testMetadataModelEmptyResult(callback) { + var model = new MetadataModel(new TestEmptyMetadataProvider()); + // getImpl returns empty result. + reportPromise(model.get([entryA], ['property']).then(function(results) { + assertEquals(undefined, results[0].property); + }), callback); +}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/mock_metadata_cache.js b/ui/file_manager/file_manager/foreground/js/metadata/mock_metadata_cache.js deleted file mode 100644 index 01f03127..0000000 --- a/ui/file_manager/file_manager/foreground/js/metadata/mock_metadata_cache.js +++ /dev/null
@@ -1,63 +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. - -/** - * Mock class for MetadataCache. - * @constructor - */ -function MockMetadataCache() { - this.metadata_ = {}; -} - -/** - * Passes metadata for callback. Metadata can be set by setForTest. - * @param {Array.<Entry>} entries The list of entries. - * @param {string} type The metadata type. - * @param {function(Object)} callback The metadata is passed to callback. - */ -MockMetadataCache.prototype.getLatest = function(entries, type, callback) { - var result = []; - for (var i = 0; i < entries.length; i++) { - result[i] = this.getOne_(entries[i], type); - } - callback(result); -}; - -/** - * @param {!Array<!Entry>} entries - * @param {string} type - * @param {function(!Array<!Object>)} callback - */ -MockMetadataCache.prototype.get = function(entries, type, callback) { - return Promise.resolve(entries.map(function(entry) { - return this.getOne_(entry, type); - }.bind(this))).then(callback); -}; - -/** - * Fetches metadata for one entry. - * @param {Entry} entry The entry. - * @param {string} type The metadata type. - * @return {Object} A metadata. When no metadata is found for the entry and - * type, null is returned. - * @private - */ -MockMetadataCache.prototype.getOne_ = function(entry, type) { - if (this.metadata_[entry.toURL()] && this.metadata_[entry.toURL()][type]) - return this.metadata_[entry.toURL()][type]; - else - return null; -}; - -/** - * Sets metadata for testing. - * @param {Entry} entry The entry. - * @param {string} type The metadata type. - * @param {Object} value The metadata for the entry and the type. - */ -MockMetadataCache.prototype.setForTest = function(entry, type, value) { - if (!this.metadata_[entry.toURL()]) - this.metadata_[entry.toURL()] = {}; - this.metadata_[entry.toURL()][type] = value; -};
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js new file mode 100644 index 0000000..a6e3289 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js
@@ -0,0 +1,173 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @param {!FileSystemMetadataProvider} fileSystemMetadataProvider + * @param {!ExternalMetadataProvider} externalMetadataProvider + * @param {!ContentMetadataProvider} contentMetadataProvider + * @param {!VolumeManagerCommon.VolumeInfoProvider} volumeManager + * @constructor + * @extends {NewMetadataProvider} + * @struct + */ +function MultiMetadataProvider( + fileSystemMetadataProvider, + externalMetadataProvider, + contentMetadataProvider, + volumeManager) { + NewMetadataProvider.call( + this, + FileSystemMetadataProvider.PROPERTY_NAMES.concat( + ExternalMetadataProvider.PROPERTY_NAMES).concat( + ContentMetadataProvider.PROPERTY_NAMES)); + + /** + * @private {!FileSystemMetadataProvider} + * @const + */ + this.fileSystemMetadataProvider_ = fileSystemMetadataProvider; + + /** + * @private {!ExternalMetadataProvider} + * @const + */ + this.externalMetadataProvider_ = externalMetadataProvider; + + /** + * @private {!ContentMetadataProvider} + * @const + */ + this.contentMetadataProvider_ = contentMetadataProvider; + + /** + * @private {!VolumeManagerCommon.VolumeInfoProvider} + * @const + */ + this.volumeManager_ = volumeManager; +} + +MultiMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype; + +/** + * Obtains metadata for entries. + * @param {!Array<!MetadataRequest>} requests + * @return {!Promise<!Array<!MetadataItem>>} + */ +MultiMetadataProvider.prototype.get = function(requests) { + var fileSystemRequests = []; + var externalRequests = []; + var contentRequests = []; + var fallbackContentRequests = []; + requests.forEach(function(request) { + // Group property names. + var fileSystemPropertyNames = []; + var externalPropertyNames = []; + var contentPropertyNames = []; + var fallbackContentPropertyNames = []; + for (var i = 0; i < request.names.length; i++) { + var name = request.names[i]; + var isFileSystemProperty = + FileSystemMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1; + var isExternalProperty = + ExternalMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1; + var isContentProperty = + ContentMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1; + assert(isFileSystemProperty || isExternalProperty || isContentProperty); + assert(!(isFileSystemProperty && isContentProperty)); + // If the property can be obtained both from ExternalProvider and from + // ContentProvider, we can obtain the property from ExternalProvider + // without fetching file content. On the other hand, the values from + // ExternalProvider may be out of sync if the file is 'dirty'. Thus we + // fallback to ContentProvider if the file is dirty. See below. + if (isExternalProperty && isContentProperty) { + externalPropertyNames.push(name); + fallbackContentPropertyNames.push(name); + continue; + } + if (isFileSystemProperty) + fileSystemPropertyNames.push(name); + if (isExternalProperty) + externalPropertyNames.push(name); + if (isContentProperty) + contentPropertyNames.push(name); + } + var volumeInfo = this.volumeManager_.getVolumeInfo(request.entry); + var addRequests = function(list, names) { + if (names.length) + list.push(new MetadataRequest(request.entry, names)); + }; + if (volumeInfo && + (volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DRIVE || + volumeInfo.volumeType === VolumeManagerCommon.VolumeType.PROVIDED)) { + // Because properties can be out of sync just after sync completion + // even if 'dirty' is false, it refers 'present' here to switch the + // content and the external providers. + if (fallbackContentPropertyNames.length && + externalPropertyNames.indexOf('present') === -1) { + externalPropertyNames.push('present'); + } + addRequests(externalRequests, externalPropertyNames); + addRequests(contentRequests, contentPropertyNames); + addRequests(fallbackContentRequests, fallbackContentPropertyNames); + } else { + addRequests(fileSystemRequests, fileSystemPropertyNames); + addRequests( + contentRequests, + contentPropertyNames.concat(fallbackContentPropertyNames)); + } + }.bind(this)); + + var get = function(provider, inRequests) { + return provider.get(inRequests).then(function(results) { + return { + requests: inRequests, + results: results + }; + }); + }; + var fileSystemPromise = get( + this.fileSystemMetadataProvider_, fileSystemRequests); + var externalPromise = get(this.externalMetadataProvider_, externalRequests); + var contentPromise = get(this.contentMetadataProvider_, contentRequests); + var fallbackContentPromise = externalPromise.then( + function(requestsAndResults) { + var requests = requestsAndResults.requests; + var results = requestsAndResults.results; + var dirtyMap = []; + for (var i = 0; i < results.length; i++) { + dirtyMap[requests[i].entry.toURL()] = results[i].present; + } + return get( + this.contentMetadataProvider_, + fallbackContentRequests.filter( + function(request) { + return dirtyMap[request.entry.toURL()]; + })); + }.bind(this)); + + // Merge results. + return Promise.all([ + fileSystemPromise, + externalPromise, + contentPromise, + fallbackContentPromise + ]).then(function(resultsList) { + var integratedResults = {}; + for (var i = 0; i < resultsList.length; i++) { + var inRequests = resultsList[i].requests; + var results = resultsList[i].results; + assert(inRequests.length === results.length); + for (var j = 0; j < results.length; j++) { + var url = inRequests[j].entry.toURL(); + integratedResults[url] = integratedResults[url] || new MetadataItem(); + for (var name in results[j]) { + integratedResults[url][name] = results[j][name]; + } + } + } + return requests.map(function(request) { + return integratedResults[request.entry.toURL()] || new MetadataItem(); + }); + }); +};
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.html new file mode 100644 index 0000000..2d2bc622 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<!-- Copyright 2015 The Chromium Authors. All rights reserved. + -- Use of this source code is governed by a BSD-style license that can be + -- found in the LICENSE file. + --> +<!-- Base classes --> +<script src="../../../../../webui/resources/js/cr.js"></script> +<script src="../../../../../webui/resources/js/cr/event_target.js"></script> +<script src="metadata_cache_set.js"></script> +<script src="new_metadata_provider.js"></script> + +<!-- Others --> +<script src="../../../../../webui/resources/js/assert.js"></script> +<script src="../../../common/js/lru_cache.js"></script> +<script src="../../../common/js/unittest_util.js"></script> +<script src="../../../common/js/volume_manager_common.js"></script> +<script src="content_metadata_provider.js"></script> +<script src="external_metadata_provider.js"></script> +<script src="file_system_metadata_provider.js"></script> +<script src="metadata_cache_item.js"></script> +<script src="metadata_item.js"></script> +<script src="multi_metadata_provider.js"></script> + +<script src="multi_metadata_provider_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.js new file mode 100644 index 0000000..691afdb4 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.js
@@ -0,0 +1,145 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var entryA = { + toURL: function() { return 'filesystem://A'; } +}; + +var entryB = { + toURL: function() { return 'filesystem://B'; } +}; + +var entryC = { + toURL: function() { return 'filesystem://C'; } +}; + +var volumeManager = { + getVolumeInfo: function(entry) { + if (entry.toURL() === 'filesystem://A') { + return { + volumeType: VolumeManagerCommon.VolumeType.DOWNLOADS + }; + } else if (entry.toURL() === 'filesystem://B') { + return { + volumeType: VolumeManagerCommon.VolumeType.DRIVE + }; + } else if (entry.toURL() === 'filesystem://C') { + return { + volumeType: VolumeManagerCommon.VolumeType.DRIVE + }; + } + assertNotReached(); + } +}; + +function testMultiMetadataProviderBasic(callback) { + var model = new MultiMetadataProvider( + // Mocking FileSystemMetadataProvider. + { + get: function(requests) { + assertEquals(1, requests.length); + assertEquals('filesystem://A', requests[0].entry.toURL()); + assertArrayEquals(['size', 'modificationTime'], requests[0].names); + return Promise.resolve( + [{modificationTime: new Date(2015, 0, 1), size: 1024}]); + } + }, + // Mocking ExternalMetadataProvider. + { + get: function(requests) { + assertEquals(1, requests.length); + assertEquals('filesystem://B', requests[0].entry.toURL()); + assertArrayEquals(['size', 'modificationTime'], requests[0].names); + return Promise.resolve( + [{modificationTime: new Date(2015, 1, 2), size: 2048}]); + } + }, + // Mocking ContentMetadataProvider. + { + get: function(requests) { + if (requests.length === 0) + return Promise.resolve([]); + assertEquals(2, requests.length); + assertEquals('filesystem://A', requests[0].entry.toURL()); + assertEquals('filesystem://B', requests[1].entry.toURL()); + assertArrayEquals(['contentThumbnailUrl'], requests[0].names); + assertArrayEquals(['contentThumbnailUrl'], requests[1].names); + return Promise.resolve([ + {contentThumbnailUrl: 'THUMBNAIL_URL_A'}, + {contentThumbnailUrl: 'THUMBNAIL_URL_B'} + ]); + } + }, + // Mocking VolumeManagerWrapper. + volumeManager); + reportPromise(model.get([ + new MetadataRequest( + entryA, ['size', 'modificationTime', 'contentThumbnailUrl']), + new MetadataRequest( + entryB, ['size', 'modificationTime', 'contentThumbnailUrl']) + ]).then(function(results) { + assertEquals(2, results.length); + assertEquals( + new Date(2015, 0, 1).toString(), + results[0].modificationTime.toString()); + assertEquals(1024, results[0].size); + assertEquals('THUMBNAIL_URL_A', results[0].contentThumbnailUrl); + assertEquals( + new Date(2015, 1, 2).toString(), + results[1].modificationTime.toString()); + assertEquals(2048, results[1].size); + assertEquals('THUMBNAIL_URL_B', results[1].contentThumbnailUrl); + }), callback); +} + +function testMultiMetadataProviderExternalAndContentProperty(callback) { + var model = new MultiMetadataProvider( + // Mocking FileSystemMetadataProvider. + { + get: function(requests) { + assertEquals(0, requests.length); + return Promise.resolve([]); + } + }, + // Mocking ExternalMetadataProvider. + { + get: function(requests) { + assertEquals(2, requests.length); + assertEquals('filesystem://B', requests[0].entry.toURL()); + assertEquals('filesystem://C', requests[1].entry.toURL()); + assertArrayEquals(['imageWidth', 'present'], requests[0].names); + assertArrayEquals(['imageWidth', 'present'], requests[1].names); + return Promise.resolve([ + {present: false, imageWidth: 200}, + {present: true, imageWidth: 400} + ]); + } + }, + // Mocking ContentMetadataProvider. + { + get: function(requests) { + assertEquals(1, requests.length); + assertTrue(requests[0].entry.toURL() in this.results_); + return Promise.resolve([ + this.results_[requests[0].entry.toURL()] + ]); + }, + results_: { + 'filesystem://A': {imageWidth: 100}, + 'filesystem://C': {imageWidth: 300} + } + }, + // Mocking VolumeManagerWrapper. + volumeManager); + reportPromise(model.get([ + new MetadataRequest(entryA, ['imageWidth']), + new MetadataRequest(entryB, ['imageWidth']), + new MetadataRequest(entryC, ['imageWidth']) + ]).then(function(results) { + assertEquals(3, results.length); + assertEquals(100, results[0].imageWidth); + assertEquals(200, results[1].imageWidth); + assertEquals(300, results[2].imageWidth); + }), callback); +}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider.js index fc088271..282bbbf 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider.js
@@ -4,18 +4,11 @@ /** * TODO(hirono): Remove 'New' from the name after removing old MetadataProvider. - * @param {!MetadataProviderCache} cache * @param {!Array<string>} validPropertyNames * @constructor * @struct */ -function NewMetadataProvider(cache, validPropertyNames) { - /** - * @private {!MetadataProviderCache} - * @const - */ - this.cache_ = cache; - +function NewMetadataProvider(validPropertyNames) { /** * Set of valid property names. Key is the name of property and value is * always true. @@ -26,14 +19,15 @@ for (var i = 0; i < validPropertyNames.length; i++) { this.validPropertyNames_[validPropertyNames[i]] = true; } - - /** - * @private {!Array<!MetadataProviderCallbackRequest<T>>} - * @const - */ - this.callbackRequests_ = []; } +NewMetadataProvider.prototype.checkPropertyNames = function(names) { + // Check if the property name is correct or not. + for (var i = 0; i < names.length; i++) { + assert(this.validPropertyNames_[names[i]]); + } +}; + /** * Obtains the metadata for the request. * @param {!Array<!MetadataRequest>} requests @@ -41,162 +35,5 @@ * should not return rejected promise. Instead it should return undefined * property for property error, and should return empty MetadataItem for * entry error. - * @protected */ -NewMetadataProvider.prototype.getImpl; - -/** - * Obtains metadata for entries. - * @param {!Array<!Entry>} entries Entries. - * @param {!Array<string>} names Metadata property names to be obtained. - * @return {!Promise<!Array<!MetadataItem>>} - */ -NewMetadataProvider.prototype.get = function(entries, names) { - // Check if the property name is correct or not. - for (var i = 0; i < names.length; i++) { - assert(this.validPropertyNames_[names[i]]); - } - - // Check if the results are cached or not. - if (this.cache_.hasFreshCache(entries, names)) - return Promise.resolve(this.getCache(entries, names)); - - // The LRU cache may be cached out when the callback is completed. - // To hold cached values, create snapshot of the cache for entries. - var requestId = this.cache_.generateRequestId(); - var snapshot = this.cache_.createSnapshot(entries); - var requests = snapshot.createRequests(entries, names); - snapshot.startRequests(requestId, requests); - this.cache_.startRequests(requestId, requests); - - // Register callback. - var promise = new Promise(function(fulfill) { - this.callbackRequests_.push(new MetadataProviderCallbackRequest( - entries, names, snapshot, fulfill)); - }.bind(this)); - - // If the requests are not empty, call the requests. - if (requests.length) { - this.getImpl(requests).then(function(list) { - // Obtain requested entries and ensure all the requested properties are - // contained in the result. - var requestedEntries = []; - for (var i = 0; i < requests.length; i++) { - requestedEntries.push(requests[i].entry); - for (var j = 0; j < requests[i].names.length; j++) { - var name = requests[i].names[j]; - if (!(name in list[i])) - list[i][name] = undefined; - } - } - - // Store cache. - this.cache_.storeProperties(requestId, requestedEntries, list); - - // Invoke callbacks. - var i = 0; - while (i < this.callbackRequests_.length) { - if (this.callbackRequests_[i].storeProperties( - requestId, requestedEntries, list)) { - // Callback was called. - this.callbackRequests_.splice(i, 1); - } else { - i++; - } - } - }.bind(this)); - } - - return promise; -}; - -/** - * Obtains metadata cache for entries. - * @param {!Array<!Entry>} entries Entries. - * @param {!Array<string>} names Metadata property names to be obtained. - * @return {!Array<!MetadataItem>} - */ -NewMetadataProvider.prototype.getCache = function(entries, names) { - // Check if the property name is correct or not. - for (var i = 0; i < names.length; i++) { - assert(this.validPropertyNames_[names[i]]); - } - return this.cache_.get(entries, names); -}; - -/** - * @param {!Array<!Entry>} entries - * @param {!Array<string>} names - * @param {!MetadataCacheSet} cache - * @param {function(!MetadataItem):undefined} fulfill - * @constructor - * @struct - */ -function MetadataProviderCallbackRequest(entries, names, cache, fulfill) { - /** - * @private {!Array<!Entry>} - * @const - */ - this.entries_ = entries; - - /** - * @private {!Array<string>} - * @const - */ - this.names_ = names; - - /** - * @private {!MetadataCacheSet} - * @const - */ - this.cache_ = cache; - - /** - * @private {function(!MetadataItem):undefined} - * @const - */ - this.fulfill_ = fulfill; -} - -/** - * Stores properties to snapshot cache of the callback request. - * If all the requested property are served, it invokes the callback. - * @param {number} requestId - * @param {!Array<!Entry>} entries - * @param {!Array<!MetadataItem>} objects - * @return {boolean} Whether the callback is invoked or not. - */ -MetadataProviderCallbackRequest.prototype.storeProperties = function( - requestId, entries, objects) { - this.cache_.storeProperties(requestId, entries, objects); - if (this.cache_.hasFreshCache(this.entries_, this.names_)) { - this.fulfill_(this.cache_.get(this.entries_, this.names_)); - return true; - } - return false; -}; - -/** - * Helper wrapper for LRUCache. - * @constructor - * @extends {MetadataCacheSet} - * @struct - */ -function MetadataProviderCache() { - MetadataCacheSet.call(this, new MetadataCacheSetStorageForObject({})); - - /** - * @private {number} - */ - this.requestIdCounter_ = 0; -} - -MetadataProviderCache.prototype.__proto__ = MetadataCacheSet.prototype; - -/** - * Generates a unique request ID every time when it is called. - * @return {number} - */ -MetadataProviderCache.prototype.generateRequestId = function() { - return this.requestIdCounter_++; -}; +NewMetadataProvider.prototype.get;
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.html deleted file mode 100644 index 476242cd..0000000 --- a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.html +++ /dev/null
@@ -1,19 +0,0 @@ -<!DOCTYPE html> -<!-- Copyright 2015 The Chromium Authors. All rights reserved. - -- Use of this source code is governed by a BSD-style license that can be - -- found in the LICENSE file. - --> -<!-- Base class --> -<script src="../../../../../webui/resources/js/cr.js"></script> -<script src="../../../../../webui/resources/js/cr/event_target.js"></script> -<script src="metadata_cache_set.js"></script> - -<!-- Others --> -<script src="../../../../../webui/resources/js/assert.js"></script> -<script src="../../../common/js/lru_cache.js"></script> -<script src="../../../common/js/unittest_util.js"></script> -<script src="metadata_cache_item.js"></script> -<script src="metadata_item.js"></script> -<script src="new_metadata_provider.js"></script> - -<script src="new_metadata_provider_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.js deleted file mode 100644 index 54cda9f8..0000000 --- a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.js +++ /dev/null
@@ -1,180 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -function TestMetadataProvider(cache) { - NewMetadataProvider.call(this, cache, ['property', 'propertyA', 'propertyB']); - this.requestCount = 0; -} - -TestMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype; - -TestMetadataProvider.prototype.getImpl = function(requests) { - this.requestCount++; - return Promise.resolve(requests.map(function(request) { - var entry = request.entry; - var names = request.names; - var result = {}; - for (var i = 0; i < names.length; i++) { - result[names[i]] = entry.toURL() + ':' + names[i]; - } - return result; - })); -}; - -function TestEmptyMetadataProvider(cache) { - NewMetadataProvider.call(this, cache, ['property']); -} - -TestEmptyMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype; - -TestEmptyMetadataProvider.prototype.getImpl = function(requests) { - return Promise.resolve(requests.map(function() { - return {}; - })); -}; - -function ManualTestMetadataProvider(cache) { - NewMetadataProvider.call( - this, cache, ['propertyA', 'propertyB', 'propertyC']); - this.callback = []; -} - -ManualTestMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype; - -ManualTestMetadataProvider.prototype.getImpl = function(requests) { - return new Promise(function(fulfill) { - this.callback.push(fulfill); - }.bind(this)); -}; - -var entryA = { - toURL: function() { return "filesystem://A"; } -}; - -var entryB = { - toURL: function() { return "filesystem://B"; } -}; - -function testNewMetadataProviderBasic(callback) { - var cache = new MetadataProviderCache(); - var provider = new TestMetadataProvider(cache); - reportPromise(provider.get([entryA, entryB], ['property']).then( - function(results) { - assertEquals(1, provider.requestCount); - assertEquals('filesystem://A:property', results[0].property); - assertEquals('filesystem://B:property', results[1].property); - }), callback); -} - -function testNewMetadataProviderRequestForCachedProperty(callback) { - var cache = new MetadataProviderCache(); - var provider = new TestMetadataProvider(cache); - reportPromise(provider.get([entryA, entryB], ['property']).then( - function() { - // All the result should be cached here. - return provider.get([entryA, entryB], ['property']); - }).then(function(results) { - assertEquals(1, provider.requestCount); - assertEquals('filesystem://A:property', results[0].property); - assertEquals('filesystem://B:property', results[1].property); - }), callback); -} - -function testNewMetadataProviderRequestForCachedAndNonCachedProperty(callback) { - var cache = new MetadataProviderCache(); - var provider = new TestMetadataProvider(cache); - reportPromise(provider.get([entryA, entryB], ['propertyA']).then( - function() { - assertEquals(1, provider.requestCount); - // propertyB has not been cached here. - return provider.get([entryA, entryB], ['propertyA', 'propertyB']); - }).then(function(results) { - assertEquals(2, provider.requestCount); - assertEquals('filesystem://A:propertyA', results[0].propertyA); - assertEquals('filesystem://A:propertyB', results[0].propertyB); - assertEquals('filesystem://B:propertyA', results[1].propertyA); - assertEquals('filesystem://B:propertyB', results[1].propertyB); - }), callback); -} - -function testNewMetadataProviderRequestForCachedAndNonCachedEntry(callback) { - var cache = new MetadataProviderCache(); - var provider = new TestMetadataProvider(cache); - reportPromise(provider.get([entryA], ['property']).then( - function() { - assertEquals(1, provider.requestCount); - // entryB has not been cached here. - return provider.get([entryA, entryB], ['property']); - }).then(function(results) { - assertEquals(2, provider.requestCount); - assertEquals('filesystem://A:property', results[0].property); - assertEquals('filesystem://B:property', results[1].property); - }), callback); -} - -function testNewMetadataProviderRequestBeforeCompletingPreviousRequest( - callback) { - var cache = new MetadataProviderCache(); - var provider = new TestMetadataProvider(cache); - provider.get([entryA], ['property']); - assertEquals(1, provider.requestCount); - // The result of first call has not been fetched yet. - reportPromise(provider.get([entryA], ['property']).then( - function(results) { - assertEquals(1, provider.requestCount); - assertEquals('filesystem://A:property', results[0].property); - }), callback); -} - -function testNewMetadataProviderNotUpdateCachedResultAfterRequest( - callback) { - var cache = new MetadataProviderCache(); - var provider = new ManualTestMetadataProvider(cache); - var promise = provider.get([entryA], ['propertyA']); - provider.callback[0]([{propertyA: 'valueA1'}]); - reportPromise(promise.then(function() { - // 'propertyA' is cached here. - var promise1 = provider.get([entryA], ['propertyA', 'propertyB']); - var promise2 = provider.get([entryA], ['propertyC']); - // Returns propertyC. - provider.callback[2]([{propertyA: 'valueA2', propertyC: 'valueC'}]); - provider.callback[1]([{propertyB: 'valueB'}]); - return Promise.all([promise1, promise2]); - }).then(function(results) { - // The result should be cached value at the time when get was called. - assertEquals('valueA1', results[0][0].propertyA); - assertEquals('valueB', results[0][0].propertyB); - assertEquals('valueC', results[1][0].propertyC); - }), callback); -} - -function testNewMetadataProviderGetCache(callback) { - var cache = new MetadataProviderCache(); - var provider = new TestMetadataProvider(cache); - var promise = provider.get([entryA], ['property']); - var cache = provider.getCache([entryA], ['property']); - assertEquals(null, cache[0].property); - reportPromise(promise.then(function() { - var cache = provider.getCache([entryA], ['property']); - assertEquals(1, provider.requestCount); - assertEquals('filesystem://A:property', cache[0].property); - }), callback); -} - -function testNewMetadataProviderUnknownProperty() { - var cache = new MetadataProviderCache(); - var provider = new TestMetadataProvider(cache); - assertThrows(function() { - provider.get([entryA], ['unknown']); - }); -} - -function testNewMetadataProviderEmptyResult(callback) { - var cache = new MetadataProviderCache(); - var provider = new TestEmptyMetadataProvider(cache); - // getImpl returns empty result. - reportPromise(provider.get([entryA], ['property']).then(function(results) { - assertEquals(undefined, results[0].property); - }), callback); -}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.js b/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.js index 16f4a5f..0aac0d92 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.js
@@ -3,25 +3,32 @@ // found in the LICENSE file. /** - * @param {!FileSystemMetadata} fileSystemMetadata + * Metadata containing thumbnail information. + * @typedef {Object} + */ +var ThumbnailMetadataItem; + +/** + * @param {!MetadataModel} metadataModel * @struct * @constructor */ -function ThumbnailModel(fileSystemMetadata) { +function ThumbnailModel(metadataModel) { /** - * @private {!FileSystemMetadata} + * @private {!MetadataModel} * @const */ - this.fileSystemMetadata_ = fileSystemMetadata; + this.metadataModel_ = metadataModel; } /** * @param {!Array<!Entry>} entries - * @return {Promise} Promise fulfilled with old format metadata list. + * @return {Promise<ThumbnailMetadataItem>} Promise fulfilled with old format + * metadata list. */ ThumbnailModel.prototype.get = function(entries) { var results = {}; - return this.fileSystemMetadata_.get( + return this.metadataModel_.get( entries, [ 'modificationTime', @@ -37,12 +44,16 @@ // using old metadata format. results[url] = { filesystem: { - modificationTime: metadataList[i].modificationTime + modificationTime: metadataList[i].modificationTime, + modificationTimeError: metadataList[i].modificationTimeError }, external: { thumbnailUrl: metadataList[i].thumbnailUrl, + thumbnailUrlError: metadataList[i].thumbnailUrlError, customIconUrl: metadataList[i].customIconUrl, - dirty: metadataList[i].dirty + customIconUrlError: metadataList[i].customIconUrlError, + dirty: metadataList[i].dirty, + dirtyError: metadataList[i].dirtyError }, thumbnail: {}, media: {} @@ -53,7 +64,7 @@ contentRequestEntries.push(entries[i]); } if (contentRequestEntries.length) { - return this.fileSystemMetadata_.get( + return this.metadataModel_.get( contentRequestEntries, [ 'contentThumbnailUrl', @@ -64,10 +75,16 @@ var url = contentRequestEntries[i].toURL(); results[url].thumbnail.url = contentMetadataList[i].contentThumbnailUrl; + results[url].thumbnail.urlError = + contentMetadataList[i].contentThumbnailUrlError; results[url].thumbnail.transform = contentMetadataList[i].contentThumbnailTransform; + results[url].thumbnail.transformError = + contentMetadataList[i].contentThumbnailTransformError; results[url].media.imageTransform = contentMetadataList[i].contentImageTransform; + results[url].media.imageTransformError = + contentMetadataList[i].contentImageTransformError; } }); }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata_update_controller.js b/ui/file_manager/file_manager/foreground/js/metadata_update_controller.js index 67a32e2f..08b3465 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata_update_controller.js +++ b/ui/file_manager/file_manager/foreground/js/metadata_update_controller.js
@@ -6,15 +6,13 @@ * Controller for list contents update. * @param {!ListContainer} listContainer * @param {!DirectoryModel} directoryModel - * @param {!MetadataProviderCache} metadataProviderCache - * @param {!FileSystemMetadata} fileSystemMetadata + * @param {!MetadataModel} metadataModel * @constructor * @struct */ function MetadataUpdateController(listContainer, directoryModel, - metadataProviderCache, - fileSystemMetadata) { + metadataModel) { /** * @private {!DirectoryModel} * @const @@ -22,10 +20,10 @@ this.directoryModel_ = directoryModel; /** - * @private {!FileSystemMetadata} + * @private {!MetadataModel} * @const */ - this.fileSystemMetadata_ = fileSystemMetadata; + this.metadataModel_ = metadataModel; /** * @private {!ListContainer} @@ -36,7 +34,7 @@ chrome.fileManagerPrivate.onPreferencesChanged.addListener( this.onPreferencesChanged_.bind(this)); this.onPreferencesChanged_(); - metadataProviderCache.addEventListener( + metadataModel.addEventListener( 'update', this.onCachedMetadataUpdate_.bind(this)); // Update metadata to change 'Today' and 'Yesterday' dates. @@ -70,11 +68,11 @@ // changed. var isFakeEntry = util.isFakeEntry(directoryEntry); var changedEntries = (isFakeEntry ? [] : [directoryEntry]).concat(entries); - this.fileSystemMetadata_.notifyEntriesChanged(changedEntries); + this.metadataModel_.notifyEntriesChanged(changedEntries); // We don't pass callback here. When new metadata arrives, we have an // observer registered to update the UI. - this.fileSystemMetadata_.get( + this.metadataModel_.get( changedEntries, this.directoryModel_.getPrefetchPropertyNames()); }; @@ -97,7 +95,7 @@ MetadataUpdateController.prototype.dailyUpdateModificationTime_ = function() { var entries = /** @type {!Array<!Entry>} */( this.directoryModel_.getFileList().slice()); - this.fileSystemMetadata_.get(entries, ['modificationTime']).then(function() { + this.metadataModel_.get(entries, ['modificationTime']).then(function() { this.listContainer_.currentView.updateListItemsMetadata( 'filesystem', entries); }.bind(this));
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.js b/ui/file_manager/file_manager/foreground/js/task_controller.js index 90da38012..4cb37d1 100644 --- a/ui/file_manager/file_manager/foreground/js/task_controller.js +++ b/ui/file_manager/file_manager/foreground/js/task_controller.js
@@ -5,7 +5,7 @@ /** * @param {DialogType} dialogType * @param {!FileManagerUI} ui - * @param {!FileSystemMetadata} fileSystemMetadata + * @param {!MetadataModel} metadataModel * @param {!FileSelectionHandler} selectionHandler * @param {!MetadataUpdateController} metadataUpdateController * @param {function():!FileTasks} createTask @@ -13,7 +13,7 @@ * @struct */ function TaskController( - dialogType, ui, fileSystemMetadata, selectionHandler, + dialogType, ui, metadataModel, selectionHandler, metadataUpdateController, createTask) { /** * @type {DialogType} @@ -30,11 +30,11 @@ this.ui_ = ui; /** - * @type {!FileSystemMetadata} + * @type {!MetadataModel} * @const * @private */ - this.fileSystemMetadata_ = fileSystemMetadata; + this.metadataModel_ = metadataModel; /** * @type {!FileSelectionHandler} @@ -263,7 +263,7 @@ * @private */ TaskController.prototype.getMimeType_ = function(entry) { - return this.fileSystemMetadata_.get([entry], ['contentMimeType']).then( + return this.metadataModel_.get([entry], ['contentMimeType']).then( function(properties) { if (properties[0].contentMimeType) return properties[0].contentMimeType; @@ -367,7 +367,7 @@ */ TaskController.prototype.doEntryAction = function(entry) { if (this.dialogType_ == DialogType.FULL_PAGE) { - this.fileSystemMetadata_.get([entry], ['contentMimeType']).then( + this.metadataModel_.get([entry], ['contentMimeType']).then( function(props) { var tasks = this.createTask_(); tasks.init([entry], [props[0].contentMimeType || '']);
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.html b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.html index c13d6bd..b2dbce7 100644 --- a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.html +++ b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.html
@@ -18,7 +18,6 @@ <script src="dialog_type.js"></script> <script src="file_selection.js"></script> <script src="file_tasks.js"></script> -<script src="metadata/mock_metadata_cache.js"></script> <script src="task_controller.js"></script> <script src="task_controller_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js index 15f3325..62e66f7 100644 --- a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js
@@ -6,11 +6,11 @@ recordEnum: function() {} }; -function MockFileSystemMetadata(properties) { +function MockMetadataModel(properties) { this.properties_ = properties; } -MockFileSystemMetadata.prototype.get = function() { +MockMetadataModel.prototype.get = function() { return Promise.resolve([this.properties_]); }; @@ -48,7 +48,7 @@ defaultActionMenuItem: document.createElement('div') } }, - new MockFileSystemMetadata({}), + new MockMetadataModel({}), new cr.EventTarget(), null, function() { @@ -61,7 +61,7 @@ isOnDrive: function() { return true; }, - getFileSystemMetadata: function() {} + getMetadataModel: function() {} }); }); @@ -98,7 +98,7 @@ } } }, - new MockFileSystemMetadata({contentMimeType: 'application/rtf'}), + new MockMetadataModel({contentMimeType: 'application/rtf'}), new cr.EventTarget(), null, null); @@ -141,7 +141,7 @@ } } }, - new MockFileSystemMetadata({}), + new MockMetadataModel({}), new cr.EventTarget(), null, null); @@ -171,7 +171,7 @@ defaultActionMenuItem: document.createElement('div') } }, - new MockFileSystemMetadata({contentMimeType: 'image/png'}), + new MockMetadataModel({contentMimeType: 'image/png'}), new cr.EventTarget(), null, null);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js index d254c49..8e6e1dea 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js +++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -396,8 +396,8 @@ */ SubDirectoryItem.prototype.updateSharedStatusIcon = function() { var icon = this.querySelector('.icon'); - this.parentTree_.fileSystemMetadata.notifyEntriesChanged([this.dirEntry_]); - this.parentTree_.fileSystemMetadata.get([this.dirEntry_], ['shared']).then( + this.parentTree_.metadataModel.notifyEntriesChanged([this.dirEntry_]); + this.parentTree_.metadataModel.get([this.dirEntry_], ['shared']).then( function(metadata) { icon.classList.toggle('shared', metadata[0] && metadata[0].shared); }); @@ -792,15 +792,14 @@ * @param {HTMLElement} el Element to be DirectoryTree. * @param {!DirectoryModel} directoryModel Current DirectoryModel. * @param {!VolumeManagerWrapper} volumeManager VolumeManager of the system. - * @param {!FileSystemMetadata} fileSystemMetadata Shared MetadataCache - * instance. + * @param {!MetadataModel} metadataModel Shared MetadataModel instance. * @param {boolean} fakeEntriesVisible True if it should show the fakeEntries. */ DirectoryTree.decorate = function( - el, directoryModel, volumeManager, fileSystemMetadata, fakeEntriesVisible) { + el, directoryModel, volumeManager, metadataModel, fakeEntriesVisible) { el.__proto__ = DirectoryTree.prototype; /** @type {DirectoryTree} */ (el).decorateDirectoryTree( - directoryModel, volumeManager, fileSystemMetadata, fakeEntriesVisible); + directoryModel, volumeManager, metadataModel, fakeEntriesVisible); }; DirectoryTree.prototype = { @@ -839,11 +838,11 @@ }, /** - * The reference to shared FileSystemMetadata instance. - * @type {!FileSystemMetadata} + * The reference to shared MetadataModel instance. + * @type {!MetadataModel} */ - get fileSystemMetadata() { - return this.fileSystemMetadata_; + get metadataModel() { + return this.metadataModel_; }, set dataModel(dataModel) { @@ -959,18 +958,17 @@ * Decorates an element. * @param {!DirectoryModel} directoryModel Current DirectoryModel. * @param {!VolumeManagerWrapper} volumeManager VolumeManager of the system. - * @param {!FileSystemMetadata} fileSystemMetadata Shared MetadataCache - * instance. + * @param {!MetadataModel} metadataModel Shared MetadataModel instance. * @param {boolean} fakeEntriesVisible True if it should show the fakeEntries. */ DirectoryTree.prototype.decorateDirectoryTree = function( - directoryModel, volumeManager, fileSystemMetadata, fakeEntriesVisible) { + directoryModel, volumeManager, metadataModel, fakeEntriesVisible) { cr.ui.Tree.prototype.decorate.call(this); this.sequence_ = 0; this.directoryModel_ = directoryModel; this.volumeManager_ = volumeManager; - this.fileSystemMetadata_ = fileSystemMetadata; + this.metadataModel_ = metadataModel; this.models_ = []; this.fileFilter_ = this.directoryModel_.getFileFilter();
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree_unittest.html b/ui/file_manager/file_manager/foreground/js/ui/directory_tree_unittest.html index ec176b4..9fdf3352 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree_unittest.html +++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree_unittest.html
@@ -20,7 +20,6 @@ <script src="../../../common/js/unittest_util.js"></script> <script src="../../../common/js/util.js"></script> <script src="../../../common/js/volume_manager_common.js"></script> - <script src="../metadata/mock_metadata_cache.js"></script> <script src="../mock_directory_model.js"></script> <script src="../mock_navigation_list_model.js"></script> <script src="../navigation_list_model.js"></script>
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 db001f07..a2eecf71 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
@@ -22,15 +22,15 @@ /** * Decorates an HTML element to be a FileGrid. * @param {!Element} self The grid to decorate. - * @param {!FileSystemMetadata} fileSystemMetadata File system metadata. + * @param {!MetadataModel} metadataModel File system metadata. * @param {VolumeManagerWrapper} volumeManager Volume manager instance. * @param {!importer.HistoryLoader} historyLoader */ FileGrid.decorate = function( - self, fileSystemMetadata, volumeManager, historyLoader) { + self, metadataModel, volumeManager, historyLoader) { cr.ui.Grid.decorate(self); self.__proto__ = FileGrid.prototype; - self.fileSystemMetadata_ = fileSystemMetadata; + self.metadataModel_ = metadataModel; self.volumeManager_ = volumeManager; self.historyLoader_ = historyLoader; @@ -107,6 +107,18 @@ FileGrid.prototype.mergeItems = function(beginIndex, endIndex) { cr.ui.Grid.prototype.mergeItems.call(this, beginIndex, endIndex); + // Make sure that grid item's selected attribute is updated just after the + // mergeItems operation is done. This prevents shadow of selected grid items + // from being animated unintentionally by redraw. + for (var i = beginIndex; i < endIndex; i++) { + var item = this.getListItemByIndex(i); + if (!item) + continue; + var isSelected = this.selectionModel.getIndexSelected(i); + if (item.selected != isSelected) + item.selected = isSelected; + } + // Keep these values to set range when a new list thumbnail loader is set. this.beginIndex_ = beginIndex; this.endIndex_ = endIndex; @@ -138,7 +150,7 @@ FileGrid.decorateThumbnailBox_(assertInstanceof(box, HTMLDivElement), entry, - this.fileSystemMetadata_, + this.metadataModel_, this.volumeManager_, this.historyLoader_, this.listThumbnailLoader_); @@ -168,7 +180,7 @@ * Decorates thumbnail. * @param {cr.ui.ListItem} li List item. * @param {!Entry} entry Entry to render a thumbnail for. - * @param {!FileSystemMetadata} fileSystemMetadata To retrieve metadata. + * @param {!MetadataModel} metadataModel To retrieve metadata. * @param {VolumeManagerWrapper} volumeManager Volume manager instance. * @param {!importer.HistoryLoader} historyLoader * @private @@ -176,13 +188,13 @@ FileGrid.decorateThumbnail_ = function( li, entry, - fileSystemMetadata, + metadataModel, volumeManager, historyLoader, listThumbnailLoader) { li.className = 'thumbnail-item'; if (entry) - filelist.decorateListItem(li, entry, fileSystemMetadata); + filelist.decorateListItem(li, entry, metadataModel); var frame = li.ownerDocument.createElement('div'); frame.className = 'thumbnail-frame'; @@ -193,7 +205,7 @@ FileGrid.decorateThumbnailBox_( assertInstanceof(box, HTMLDivElement), entry, - fileSystemMetadata, + metadataModel, volumeManager, historyLoader, listThumbnailLoader); @@ -219,7 +231,7 @@ * * @param {!HTMLDivElement} box Box to decorate. * @param {Entry} entry Entry which thumbnail is generating for. - * @param {!FileSystemMetadata} fileSystemMetadata To retrieve metadata. + * @param {!MetadataModel} metadataModel To retrieve metadata. * @param {VolumeManagerWrapper} volumeManager Volume manager instance. * @param {!importer.HistoryLoader} historyLoader * @param {function(HTMLImageElement)=} opt_imageLoadCallback Callback called @@ -227,7 +239,7 @@ * @private */ FileGrid.decorateThumbnailBox_ = function( - box, entry, fileSystemMetadata, volumeManager, historyLoader, + box, entry, metadataModel, volumeManager, historyLoader, listThumbnailLoader, opt_imageLoadCallback) { box.className = 'img-container'; @@ -242,7 +254,7 @@ if (entry.isDirectory) { box.setAttribute('generic-thumbnail', 'folder'); - var shared = !!fileSystemMetadata.getCache([entry], ['shared'])[0].shared; + var shared = !!metadataModel.getCache([entry], ['shared'])[0].shared; box.classList.toggle('shared', shared); if (opt_imageLoadCallback) @@ -279,7 +291,7 @@ thumbnail.style.backgroundImage = 'url(' + dataUrl + ')'; thumbnail.addEventListener('webkitAnimationEnd', function() { // Remove animation css once animation is completed in order not to animate - // agein when an item is attached to the dom again. + // again when an item is attached to the dom again. thumbnail.classList.remove('animate'); for (var i = 0; i < oldThumbnails.length; i++) { @@ -366,7 +378,7 @@ FileGrid.decorateThumbnail_( li, entry, - grid.fileSystemMetadata_, + grid.metadataModel_, grid.volumeManager_, grid.historyLoader_, grid.listThumbnailLoader_);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js index 7d62b53..4949743 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js +++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -224,7 +224,7 @@ /** * Decorates the element. * @param {!Element} self Table to decorate. - * @param {!FileSystemMetadata} fileSystemMetadata To retrieve + * @param {!MetadataModel} metadataModel To retrieve * metadata. * @param {VolumeManagerWrapper} volumeManager To retrieve volume info. * @param {!importer.HistoryLoader} historyLoader @@ -232,11 +232,11 @@ * False if a file open/save dialog. */ FileTable.decorate = function( - self, fileSystemMetadata, volumeManager, historyLoader, fullPage) { + self, metadataModel, volumeManager, historyLoader, fullPage) { cr.ui.Table.decorate(self); FileTableList.decorate(self.list); self.__proto__ = FileTable.prototype; - self.fileSystemMetadata_ = fileSystemMetadata; + self.metadataModel_ = metadataModel; self.volumeManager_ = volumeManager; self.historyLoader_ = historyLoader; @@ -394,7 +394,8 @@ var box = listItem.querySelector('.detail-thumbnail'); if (box) { this.setThumbnailImage_( - assertInstanceof(box, HTMLDivElement), event.dataUrl); + assertInstanceof(box, HTMLDivElement), event.dataUrl, + true /* with animation */); } } }; @@ -494,9 +495,12 @@ return true; // Check if the point is on the column contents or not. - var item = this.list.getListItemByIndex(itemIndex); switch (this.columnModel.columns_[hitColumn.index].id) { case 'name': + var item = this.list.getListItemByIndex(itemIndex); + if (!item) + return false; + var spanElement = item.querySelector('.filename-label span'); var spanRect = spanElement.getBoundingClientRect(); // The this.list.cachedBounds_ object is set by @@ -564,7 +568,7 @@ * @private */ FileTable.prototype.updateSize_ = function(div, entry) { - var metadata = this.fileSystemMetadata_.getCache( + var metadata = this.metadataModel_.getCache( [entry], ['size', 'hosted'])[0]; var size = metadata.size; if (size === null || size === undefined) { @@ -694,7 +698,7 @@ * @private */ FileTable.prototype.updateDate_ = function(div, entry) { - var modTime = this.fileSystemMetadata_.getCache( + var modTime = this.metadataModel_.getCache( [entry], ['modificationTime'])[0].modificationTime; if (!modTime) { @@ -776,7 +780,7 @@ forEachCell('.table-row-cell > .date', function(item, entry, listItem) { filelist.updateListItemExternalProps( listItem, - this.fileSystemMetadata_.getCache( + this.metadataModel_.getCache( [entry], ['availableOffline', 'customIconUrl', 'shared'])[0]); }); } else if (type === 'import-history') { @@ -795,7 +799,7 @@ */ FileTable.prototype.renderTableRow_ = function(baseRenderFunction, entry) { var item = baseRenderFunction(entry, this); - filelist.decorateListItem(item, entry, this.fileSystemMetadata_); + filelist.decorateListItem(item, entry, this.metadataModel_); return item; }; @@ -814,7 +818,8 @@ if (this.listThumbnailLoader_ && this.listThumbnailLoader_.getThumbnailFromCache(entry)) { this.setThumbnailImage_( - box, this.listThumbnailLoader_.getThumbnailFromCache(entry).dataUrl); + box, this.listThumbnailLoader_.getThumbnailFromCache(entry).dataUrl, + false /* without animation */); } return box; @@ -824,12 +829,31 @@ * Sets thumbnail image to the box. * @param {!HTMLDivElement} box Detail thumbnail div element. * @param {string} dataUrl Data url of thumbnail. + * @param {boolean} shouldAnimate Whether the thumbnail is shown with animation + * or not. * @private */ -FileTable.prototype.setThumbnailImage_ = function(box, dataUrl) { - // TODO(yawano): Add transition animation for thumbnail update. - box.style.backgroundImage = 'url(' + dataUrl + ')'; - box.classList.add('loaded'); +FileTable.prototype.setThumbnailImage_ = function(box, dataUrl, shouldAnimate) { + var oldThumbnails = box.querySelectorAll('.thumbnail'); + + var thumbnail = box.ownerDocument.createElement('div'); + thumbnail.classList.add('thumbnail'); + thumbnail.style.backgroundImage = 'url(' + dataUrl + ')'; + thumbnail.addEventListener('webkitAnimationEnd', function() { + // Remove animation css once animation is completed in order not to animate + // again when an item is attached to the dom again. + thumbnail.classList.remove('animate'); + + for (var i = 0; i < oldThumbnails.length; i++) { + if (box.contains(oldThumbnails[i])) + box.removeChild(oldThumbnails[i]); + } + }); + + if (shouldAnimate) + thumbnail.classList.add('animate'); + + box.appendChild(thumbnail); }; /** @@ -866,15 +890,15 @@ * Common item decoration for table's and grid's items. * @param {cr.ui.ListItem} li List item. * @param {Entry} entry The entry. - * @param {!FileSystemMetadata} fileSystemMetadata Cache to + * @param {!MetadataModel} metadataModel Cache to * retrieve metadada. */ -filelist.decorateListItem = function(li, entry, fileSystemMetadata) { +filelist.decorateListItem = function(li, entry, metadataModel) { li.classList.add(entry.isDirectory ? 'directory' : 'file'); // The metadata may not yet be ready. In that case, the list item will be // updated when the metadata is ready via updateListItemsMetadata. For files // not on an external backend, externalProps is not available. - var externalProps = fileSystemMetadata.getCache( + var externalProps = metadataModel.getCache( [entry], ['hosted', 'availableOffline', 'customIconUrl', 'shared'])[0]; filelist.updateListItemExternalProps(li, externalProps); @@ -1103,6 +1127,13 @@ return; } + // Esc + if (e.keyCode === 27 && !e.ctrlKey && !e.shiftKey) { + sm.unselectAll(); + e.preventDefault(); + return; + } + // Space if (e.keyCode == SPACE_KEY_CODE) { if (leadIndex != -1) {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js b/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js index 207c848..3476fd8 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js +++ b/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
@@ -27,7 +27,7 @@ // Make sure that list item's selected attribute is updated just after the // mergeItems operation is done. This prevents checkmarks on selected items - // from being animated unintentinally by redraw. + // from being animated unintentionally by redraw. for (var i = beginIndex; i < endIndex; i++) { var item = this.getListItemByIndex(i); if (!item)
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 4a4a9188..a65ee0c 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
@@ -136,6 +136,7 @@ this.webViewWrapper_.className = 'share-dialog-webview-wrapper'; this.cancelButton_.hidden = true; this.okButton_.hidden = true; + this.closeButton_.hidden = true; this.frame_.insertBefore(this.webViewWrapper_, this.frame_.querySelector('.cr-dialog-buttons')); };
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html index 5600fccc92..6991fdf 100644 --- a/ui/file_manager/file_manager/main.html +++ b/ui/file_manager/file_manager/main.html
@@ -131,11 +131,11 @@ <script src="foreground/js/launch_param.js"></script> <script src="foreground/js/metadata/content_metadata_provider.js"></script> <script src="foreground/js/metadata/external_metadata_provider.js"></script> - <script src="foreground/js/metadata/file_system_metadata.js"></script> <script src="foreground/js/metadata/file_system_metadata_provider.js"></script> - <script src="foreground/js/metadata/metadata_cache.js"></script> <script src="foreground/js/metadata/metadata_cache_item.js"></script> <script src="foreground/js/metadata/metadata_item.js"></script> + <script src="foreground/js/metadata/metadata_model.js"></script> + <script src="foreground/js/metadata/multi_metadata_provider.js"></script> <script src="foreground/js/metadata_update_controller.js"></script> <script src="foreground/js/naming_controller.js"></script> <script src="foreground/js/navigation_list_model.js"></script>
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json index 36a9aa9..78b23ff 100644 --- a/ui/file_manager/file_manager/manifest.json +++ b/ui/file_manager/file_manager/manifest.json
@@ -157,7 +157,6 @@ "foreground/js/metadata/function_sequence.js", "foreground/js/metadata/id3_parser.js", "foreground/js/metadata/image_parsers.js", - "foreground/js/metadata/metadata_cache.js", "foreground/js/metadata/metadata_dispatcher.js", "foreground/js/metadata/metadata_parser.js", "foreground/js/metadata/mpeg_parser.js"
diff --git a/ui/file_manager/gallery/gallery.html b/ui/file_manager/gallery/gallery.html index 00f049b..0fce458 100644 --- a/ui/file_manager/gallery/gallery.html +++ b/ui/file_manager/gallery/gallery.html
@@ -54,14 +54,14 @@ <script src="../file_manager/common/js/volume_manager_common.js"></script> <script src="../file_manager/foreground/js/metadata/content_metadata_provider.js"></script> + <script src="../file_manager/foreground/js/metadata/exif_constants.js"></script> <script src="../file_manager/foreground/js/metadata/external_metadata_provider.js"></script> - <script src="../file_manager/foreground/js/metadata/file_system_metadata.js"></script> <script src="../file_manager/foreground/js/metadata/file_system_metadata_provider.js"></script> - <script src="../file_manager/foreground/js/metadata/metadata_cache.js"></script> <script src="../file_manager/foreground/js/metadata/metadata_cache_item.js"></script> <script src="../file_manager/foreground/js/metadata/metadata_item.js"></script> + <script src="../file_manager/foreground/js/metadata/metadata_model.js"></script> + <script src="../file_manager/foreground/js/metadata/multi_metadata_provider.js"></script> <script src="../file_manager/foreground/js/metadata/thumbnail_model.js"></script> - <script src="../file_manager/foreground/js/metadata/exif_constants.js"></script> <script src="../file_manager/foreground/js/mouse_inactivity_watcher.js"></script> <script src="../file_manager/foreground/js/share_client.js"></script> <script src="../file_manager/foreground/js/thumbnail_loader.js"></script>
diff --git a/ui/file_manager/gallery/js/compiled_resources.gyp b/ui/file_manager/gallery/js/compiled_resources.gyp index ad5166f4..2152717b 100644 --- a/ui/file_manager/gallery/js/compiled_resources.gyp +++ b/ui/file_manager/gallery/js/compiled_resources.gyp
@@ -69,13 +69,14 @@ '../../file_manager/foreground/js/metadata/content_metadata_provider.js', '../../file_manager/foreground/js/metadata/exif_constants.js', '../../file_manager/foreground/js/metadata/external_metadata_provider.js', - '../../file_manager/foreground/js/metadata/file_system_metadata.js', '../../file_manager/foreground/js/metadata/file_system_metadata_provider.js', - '../../file_manager/foreground/js/metadata/metadata_cache.js', '../../file_manager/foreground/js/metadata/metadata_cache_item.js', '../../file_manager/foreground/js/metadata/metadata_cache_set.js', '../../file_manager/foreground/js/metadata/metadata_item.js', + '../../file_manager/foreground/js/metadata/metadata_model.js', + '../../file_manager/foreground/js/metadata/multi_metadata_provider.js', '../../file_manager/foreground/js/metadata/new_metadata_provider.js', + '../../file_manager/foreground/js/metadata/thumbnail_model.js', '../../file_manager/foreground/js/mouse_inactivity_watcher.js', '../../file_manager/foreground/js/share_client.js', '../../file_manager/foreground/js/thumbnail_loader.js',
diff --git a/ui/file_manager/gallery/js/gallery.js b/ui/file_manager/gallery/js/gallery.js index a835bfa3..663dd15 100644 --- a/ui/file_manager/gallery/js/gallery.js +++ b/ui/file_manager/gallery/js/gallery.js
@@ -6,7 +6,6 @@ * Overrided metadata worker's path. * @type {string} */ -ContentProvider.WORKER_SCRIPT = '/js/metadata_worker.js'; ContentMetadataProvider.WORKER_SCRIPT = '/js/metadata_worker.js'; /** @@ -21,9 +20,9 @@ /** * @type {{appWindow: chrome.app.window.AppWindow, onClose: function(), * onMaximize: function(), onMinimize: function(), - * onAppRegionChanged: function(), metadataCache: MetadataCache, - * readonlyDirName: string, displayStringFunction: function(), - * loadTimeData: Object, curDirEntry: Entry, searchResults: *}} + * onAppRegionChanged: function(), readonlyDirName: string, + * displayStringFunction: function(), loadTimeData: Object, + * curDirEntry: Entry, searchResults: *}} * @private * * TODO(yawano): curDirEntry and searchResults seem not to be used. @@ -41,7 +40,6 @@ }, onMinimize: function() { chrome.app.window.current().minimize(); }, onAppRegionChanged: function() {}, - metadataCache: MetadataCache.createFull(volumeManager), readonlyDirName: '', displayStringFunction: function() { return ''; }, loadTimeData: {}, @@ -50,22 +48,22 @@ }; this.container_ = queryRequiredElement(document, '.gallery'); this.document_ = document; - this.metadataCache_ = this.context_.metadataCache; this.volumeManager_ = volumeManager; /** - * @private {!FileSystemMetadata} + * @private {!MetadataModel} * @const */ - this.fileSystemMetadata_ = FileSystemMetadata.create( - new MetadataProviderCache(), volumeManager); + this.metadataModel_ = MetadataModel.create(volumeManager); + /** + * @private {!ThumbnailModel} + * @const + */ + this.thumbnailModel_ = new ThumbnailModel(this.metadataModel_); this.selectedEntry_ = null; - this.metadataCacheObserverId_ = null; this.onExternallyUnmountedBound_ = this.onExternallyUnmounted_.bind(this); this.initialized_ = false; - this.dataModel_ = new GalleryDataModel( - this.context_.metadataCache, - this.fileSystemMetadata_); + this.dataModel_ = new GalleryDataModel(this.metadataModel_); var downloadVolumeInfo = this.volumeManager_.getCurrentProfileVolumeInfo( VolumeManagerCommon.VolumeType.DOWNLOADS); downloadVolumeInfo.resolveDisplayRoot().then(function(entry) { @@ -164,6 +162,8 @@ this.errorBanner_, this.dataModel_, this.selectionModel_, + this.metadataModel_, + this.thumbnailModel_, this.context_, this.volumeManager_, this.toggleMode_.bind(this), @@ -200,15 +200,7 @@ this.inactivityWatcher_ = new MouseInactivityWatcher( this.container_, Gallery.FADE_TIMEOUT, this.hasActiveTool.bind(this)); - // Search results may contain files from different subdirectories so - // the observer is not going to work. - if (!this.context_.searchResults && this.context_.curDirEntry) { - this.metadataCacheObserverId_ = this.metadataCache_.addObserver( - this.context_.curDirEntry, - MetadataCache.CHILDREN, - 'thumbnail', - this.updateThumbnails_.bind(this)); - } + // TODO(hirono): Add observer to handle thumbnail update. this.volumeManager_.addEventListener( 'externally-unmounted', this.onExternallyUnmountedBound_); // The 'pagehide' event is called when the app window is closed. @@ -245,9 +237,10 @@ /** * Types of metadata Gallery uses (to query the metadata cache). * @const - * @type {string} + * @type {!Array<string>} */ -Gallery.METADATA_TYPE = 'thumbnail|filesystem|media|external'; +Gallery.PREFETCH_PROPERTY_NAMES = + ['imageWidth', 'imageHeight', 'size', 'present']; /** * Closes gallery when a volume containing the selected item is unmounted. @@ -269,8 +262,6 @@ * @private */ Gallery.prototype.onPageHide_ = function() { - if (this.metadataCacheObserverId_ !== null) - this.metadataCache_.removeObserver(this.metadataCacheObserverId_); this.volumeManager_.removeEventListener( 'externally-unmounted', this.onExternallyUnmountedBound_); }; @@ -311,12 +302,12 @@ // Obtains max chank size. var maxChunkSize = 20; var volumeInfo = this.volumeManager_.getVolumeInfo(entries[0]); - if (volumeInfo && - volumeInfo.volumeType === VolumeManagerCommon.VolumeType.MTP) { - maxChunkSize = 1; + if (volumeInfo) { + if (volumeInfo.volumeType === VolumeManagerCommon.VolumeType.MTP) + maxChunkSize = 1; + if (volumeInfo.isReadOnly) + this.context_.readonlyDirName = volumeInfo.label; } - if (volumeInfo.isReadOnly) - this.context_.readonlyDirName = volumeInfo.label; // Make loading list. var entrySet = {}; @@ -357,22 +348,20 @@ // Load entries. // Use the self variable capture-by-closure because it is faster than bind. var self = this; + var thumbnailModel = new ThumbnailModel(this.metadataModel_); var loadChunk = function(firstChunk) { // Extract chunk. var chunk = loadingList.splice(0, maxChunkSize); if (!chunk.length) return; - - return new Promise(function(fulfill) { - // Obtains metadata for chunk. - var entries = chunk.map(function(chunkItem) { - return chunkItem.entry; - }); - self.metadataCache_.get(entries, Gallery.METADATA_TYPE, fulfill); - }).then(function(metadataList) { - if (chunk.length !== metadataList.length) - return Promise.reject('Failed to load metadata.'); - + var entries = chunk.map(function(chunkItem) { + return chunkItem.entry; + }); + var metadataPromise = self.metadataModel_.get( + entries, Gallery.PREFETCH_PROPERTY_NAMES); + var thumbnailPromise = thumbnailModel.get(entries); + return Promise.all([metadataPromise, thumbnailPromise]).then( + function(metadataLists) { // Remove all the previous items if it's the first chunk. // Do it here because prevent a flicker between removing all the items // and adding new ones. @@ -387,13 +376,11 @@ var locationInfo = self.volumeManager_.getLocationInfo(chunkItem.entry); if (!locationInfo) // Skip the item, since gone. return; - var clonedMetadata = MetadataCache.cloneMetadata(metadataList[index]); items.push(new Gallery.Item( chunkItem.entry, locationInfo, - clonedMetadata, - self.metadataCache_, - self.fileSystemMetadata_, + metadataLists[0][index], + metadataLists[1][index], /* original */ true)); }); self.dataModel_.push.apply(self.dataModel_, items); @@ -822,7 +809,7 @@ var event = new Event('content'); event.item = item; event.oldEntry = oldEntry; - event.metadata = null; // Metadata unchanged. + event.thumbnailChanged = false; this.dataModel_.dispatchEvent(event); }.bind(this), function(error) { if (error === 'NOT_CHANGED')
diff --git a/ui/file_manager/gallery/js/gallery_data_model.js b/ui/file_manager/gallery/js/gallery_data_model.js index 5b80f77..cac6d65 100644 --- a/ui/file_manager/gallery/js/gallery_data_model.js +++ b/ui/file_manager/gallery/js/gallery_data_model.js
@@ -5,28 +5,20 @@ /** * Data model for gallery. * - * @param {!MetadataCache} metadataCache Metadata cache. - * @param {!FileSystemMetadata} fileSystemMetadata + * @param {!MetadataModel} metadataModel * @param {!EntryListWatcher=} opt_watcher Entry list watcher. * @constructor * @extends {cr.ui.ArrayDataModel} */ -function GalleryDataModel(metadataCache, fileSystemMetadata, opt_watcher) { +function GalleryDataModel(metadataModel, opt_watcher) { cr.ui.ArrayDataModel.call(this, []); /** - * Metadata cache. - * @private {!MetadataCache} - * @const - */ - this.metadataCache_ = metadataCache; - - /** * File system metadata. - * @private {!FileSystemMetadata} + * @private {!MetadataModel} * @const */ - this.fileSystemMetadata_ = fileSystemMetadata; + this.metadataModel_ = metadataModel; /** * Directory where the image is saved if the image is located in a read-only @@ -72,11 +64,13 @@ GalleryDataModel.prototype.saveItem = function( volumeManager, item, canvas, overwrite) { var oldEntry = item.getEntry(); - var oldMetadata = item.getMetadata(); + var oldMetadataItem = item.getMetadataItem(); + var oldThumbnailMetadataItem = item.getThumbnailMetadataItem(); var oldLocationInfo = item.getLocationInfo(); return new Promise(function(fulfill, reject) { item.saveToFile( volumeManager, + this.metadataModel_, this.fallbackSaveDirectory, overwrite, canvas, @@ -91,7 +85,7 @@ var event = new Event('content'); event.item = item; event.oldEntry = oldEntry; - event.metadata = item.getMetadata(); + event.thumbnailChanged = true; this.dispatchEvent(event); if (!util.isSameEntry(oldEntry, item.getEntry())) { @@ -100,9 +94,8 @@ var anotherItem = new Gallery.Item( oldEntry, oldLocationInfo, - oldMetadata, - this.metadataCache_, - this.fileSystemMetadata_, + oldMetadataItem, + oldThumbnailMetadataItem, item.isOriginal()); // The item must be added behind the existing item so that it does // not change the index of the existing item.
diff --git a/ui/file_manager/gallery/js/gallery_data_model_unittest.html b/ui/file_manager/gallery/js/gallery_data_model_unittest.html index d4565ca..34f2a9e5 100644 --- a/ui/file_manager/gallery/js/gallery_data_model_unittest.html +++ b/ui/file_manager/gallery/js/gallery_data_model_unittest.html
@@ -15,10 +15,6 @@ <script src="../../file_manager/common/js/mock_entry.js"></script> <script src="../../file_manager/common/js/unittest_util.js"></script> <script src="../../file_manager/common/js/util.js"></script> -<script src="../../file_manager/foreground/js/metadata/metadata_cache.js"> -</script> -<script src="../../file_manager/foreground/js/metadata/mock_metadata_cache.js"> -</script> <script src="entry_list_watcher.js"></script> <script src="gallery_data_model.js"></script> <script src="gallery_item.js"></script>
diff --git a/ui/file_manager/gallery/js/gallery_data_model_unittest.js b/ui/file_manager/gallery/js/gallery_data_model_unittest.js index bad20791..c54ce2d0 100644 --- a/ui/file_manager/gallery/js/gallery_data_model_unittest.js +++ b/ui/file_manager/gallery/js/gallery_data_model_unittest.js
@@ -8,17 +8,15 @@ var item; function setUp() { - var metadataCache = new MockMetadataCache(); model = new GalleryDataModel( - metadataCache, - /* Mock FileSystemMetadata */{}, + /* Mock MetadataModel */{}, /* Mock EntryListWatcher */{}); fileSystem = new MockFileSystem('volumeId'); item = new Gallery.Item( new MockEntry(fileSystem, '/test.jpg'), null, - {media: {mimeType: 'image/jpeg'}}, - metadataCache, + /* metadataItem */ {}, + /* thumbnailMetadataItem */ {}, /* original */ true); } @@ -26,6 +24,7 @@ // Mocking the saveToFile method. item.saveToFile = function( volumeManager, + metadataModel, fallbackDir, overwrite, canvas, @@ -44,6 +43,7 @@ // Mocking the saveToFile method. item.saveToFile = function( volumeManager, + metadataModel, fallbackDir, overwrite, canvas,
diff --git a/ui/file_manager/gallery/js/gallery_item.js b/ui/file_manager/gallery/js/gallery_item.js index 2db056dc..54c6ef1 100644 --- a/ui/file_manager/gallery/js/gallery_item.js +++ b/ui/file_manager/gallery/js/gallery_item.js
@@ -7,47 +7,33 @@ * * @param {!FileEntry} entry Image entry. * @param {!EntryLocation} locationInfo Entry location information. - * @param {!Object} metadata Metadata for the entry. - * @param {!MetadataCache} metadataCache Metadata cache instance. - * @param {!FileSystemMetadata} fileSystemMetadata File system metadata. + * @param {!MetadataItem} metadataItem + * @param {!ThumbnailMetadataItem} thumbnailMetadataItem * @param {boolean} original Whether the entry is original or edited. * @constructor * @struct */ Gallery.Item = function( - entry, locationInfo, metadata, metadataCache, fileSystemMetadata, - original) { + entry, locationInfo, metadataItem, thumbnailMetadataItem, original) { /** - * @type {!FileEntry} - * @private + * @private {!FileEntry} */ this.entry_ = entry; /** - * @type {!EntryLocation} - * @private + * @private {!EntryLocation} */ this.locationInfo_ = locationInfo; /** - * @type {!Object} - * @private + * @private {!MetadataItem} */ - this.metadata_ = Object.preventExtensions(metadata); + this.metadataItem_ = metadataItem; /** - * @type {!MetadataCache} - * @private - * @const + * @private {!ThumbnailMetadataItem} */ - this.metadataCache_ = metadataCache; - - /** - * @type {!FileSystemMetadata} - * @private - * @const - */ - this.fileSystemMetadata_ = fileSystemMetadata; + this.thumbnailMetadataItem_ = metadataItem; // TODO(yawano): Change this.contentImage and this.screenImage to private // fields and provide utility methods for them (e.g. revokeFullImageCache). @@ -95,29 +81,24 @@ }; /** - * @return {!Object} Metadata. + * @return {!MetadataItem} Metadata. */ -Gallery.Item.prototype.getMetadata = function() { return this.metadata_; }; +Gallery.Item.prototype.getMetadataItem = function() { + return this.metadataItem_; +}; /** - * Obtains the latest media metadata. - * - * This is a heavy operation since it forces to load the image data to obtain - * the metadata. - * @return {!Promise} Promise to be fulfilled with fetched metadata. + * @return {!MetadataItem} Metadata. */ -Gallery.Item.prototype.getFetchedMedia = function() { - return new Promise(function(fulfill, reject) { - this.metadataCache_.getLatest( - [this.entry_], - 'fetchedMedia', - function(metadata) { - if (metadata[0]) - fulfill(metadata[0]); - else - reject('Failed to load metadata.'); - }); - }.bind(this)); +Gallery.Item.prototype.getMetadataItem = function() { + return this.metadataItem_; +}; + +/** + * @return {!ThumbnailMetadataItem} Thumbnail metadata item. + */ +Gallery.Item.prototype.getThumbnailMetadataItem = function() { + return this.thumbnailMetadataItem_; }; /** @@ -232,14 +213,15 @@ * Writes the new item content to either the existing or a new file. * * @param {!VolumeManager} volumeManager Volume manager instance. + * @param {!MetadataModel} metadataModel * @param {DirectoryEntry} fallbackDir Fallback directory in case the current * directory is read only. * @param {boolean} overwrite Whether to overwrite the image to the item or not. * @param {!HTMLCanvasElement} canvas Source canvas. - * @param {function(boolean)=} opt_callback Callback accepting true for success. + * @param {function(boolean)} callback Callback accepting true for success. */ Gallery.Item.prototype.saveToFile = function( - volumeManager, fallbackDir, overwrite, canvas, opt_callback) { + volumeManager, metadataModel, fallbackDir, overwrite, canvas, callback) { ImageUtil.metrics.startInterval(ImageUtil.getMetricName('SaveTime')); var name = this.getFileName(); @@ -257,32 +239,28 @@ this.locationInfo_ = locationInfo; // Updates the metadata. - this.metadataCache_.clear([this.entry_], '*'); - this.metadataCache_.getLatest( - [this.entry_], - Gallery.METADATA_TYPE, - function(metadataList) { - if (metadataList.length === 1) { - this.metadata_ = metadataList[0]; - if (opt_callback) - opt_callback(true); - } else { - if (opt_callback) - opt_callback(false); - } - }.bind(this)); - this.fileSystemMetadata_.notifyEntriesChanged([this.entry_]); + metadataModel.notifyEntriesChanged([this.entry_]); + Promise.all([ + metadataModel.get([entry], Gallery.PREFETCH_PROPERTY_NAMES), + new ThumbnailModel(metadataModel).get([entry]) + ]).then(function(metadataLists) { + this.metadataItem_ = metadataLists[0][0]; + this.thumbnailMetadataItem_ = metadataLists[1][0]; + callback(true); + }.bind(this), function() { + callback(false); + }); }.bind(this); var onError = function(error) { console.error('Error saving from gallery', name, error); ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 0, 2); - if (opt_callback) - opt_callback(false); + if (callback) + callback(false); }; var doSave = function(newFile, fileEntry) { - var metadataPromise = this.fileSystemMetadata_.get( + var metadataPromise = metadataModel.get( [fileEntry], ['mediaMimeType', 'contentMimeType', 'ifd', 'exifLittleEndian']); metadataPromise.then(function(metadataItems) {
diff --git a/ui/file_manager/gallery/js/gallery_item_unittest.html b/ui/file_manager/gallery/js/gallery_item_unittest.html index 70ef7d0..9245154 100644 --- a/ui/file_manager/gallery/js/gallery_item_unittest.html +++ b/ui/file_manager/gallery/js/gallery_item_unittest.html
@@ -18,6 +18,7 @@ <script src="../../file_manager/common/js/mock_entry.js"></script> <script src="../../file_manager/common/js/unittest_util.js"></script> <script src="../../file_manager/common/js/util.js"></script> +<script src="../../file_manager/foreground/js/metadata/thumbnail_model.js"></script> <script src="gallery_item.js"></script> <script src="gallery_item_unittest.js"></script>
diff --git a/ui/file_manager/gallery/js/gallery_item_unittest.js b/ui/file_manager/gallery/js/gallery_item_unittest.js index 8a7b25df..613bbb2b 100644 --- a/ui/file_manager/gallery/js/gallery_item_unittest.js +++ b/ui/file_manager/gallery/js/gallery_item_unittest.js
@@ -49,38 +49,34 @@ } }); }; - var fetchedMediaCleared = false; - var metadataCache = { - getLatest: function(entries, type, callback) { - callback([{name: 'newMetadata'}]); + var entryChanged = false; + var metadataModel = { + get: function(entries, names) { + return Promise.resolve([ + {size: 200} + ]); }, - clear: function(entries, type) { - fetchedMediaCleared = true; + notifyEntriesChanged: function() { + entryChanged = true; } }; var item = new Gallery.Item( entry, {isReadOnly: false}, - {name: 'oldMetadata'}, - metadataCache, - // Mock of FileSystemMetadata. - { - get: function() { - return Promise.resolve([{}]); - }, - notifyEntriesChanged: function() {} - }, + {size: 100}, + {}, /* original */ true); - assertEquals('oldMetadata', item.getMetadata().name); - assertFalse(fetchedMediaCleared); + assertEquals(100, item.getMetadataItem().size); + assertFalse(entryChanged); reportPromise( new Promise(item.saveToFile.bind( item, {getLocationInfo: function() { return {}; }}, - null, - true, + metadataModel, + /* fallbackDir */ null, + /* overwrite */ true, document.createElement('canvas'))).then(function() { - assertEquals('newMetadata', item.getMetadata().name); - assertTrue(fetchedMediaCleared); + assertEquals(200, item.getMetadataItem().size); + assertTrue(entryChanged); }), callback); }
diff --git a/ui/file_manager/gallery/js/gallery_scripts.js b/ui/file_manager/gallery/js/gallery_scripts.js index df653f5..a8de954 100644 --- a/ui/file_manager/gallery/js/gallery_scripts.js +++ b/ui/file_manager/gallery/js/gallery_scripts.js
@@ -46,14 +46,14 @@ //<include src="../../file_manager/common/js/util.js"> //<include src="../../file_manager/common/js/volume_manager_common.js"> //<include src="../../file_manager/foreground/js/metadata/content_metadata_provider.js"> +//<include src="../../file_manager/foreground/js/metadata/exif_constants.js"> //<include src="../../file_manager/foreground/js/metadata/external_metadata_provider.js"> -//<include src="../../file_manager/foreground/js/metadata/file_system_metadata.js"> //<include src="../../file_manager/foreground/js/metadata/file_system_metadata_provider.js"> -//<include src="../../file_manager/foreground/js/metadata/metadata_cache.js"> //<include src="../../file_manager/foreground/js/metadata/metadata_cache_item.js"> //<include src="../../file_manager/foreground/js/metadata/metadata_item.js"> +//<include src="../../file_manager/foreground/js/metadata/metadata_model.js"> +//<include src="../../file_manager/foreground/js/metadata/multi_metadata_provider.js"> //<include src="../../file_manager/foreground/js/metadata/thumbnail_model.js"> -//<include src="../../file_manager/foreground/js/metadata/exif_constants.js"> //<include src="../../file_manager/foreground/js/mouse_inactivity_watcher.js"> //<include src="../../file_manager/foreground/js/share_client.js"> //<include src="../../file_manager/foreground/js/thumbnail_loader.js">
diff --git a/ui/file_manager/gallery/js/image_editor/exif_encoder_unittest.html b/ui/file_manager/gallery/js/image_editor/exif_encoder_unittest.html index e84dffe..3016f41 100644 --- a/ui/file_manager/gallery/js/image_editor/exif_encoder_unittest.html +++ b/ui/file_manager/gallery/js/image_editor/exif_encoder_unittest.html
@@ -12,7 +12,6 @@ </script> <script src="../../../../webui/resources/js/assert.js"></script> -<script src="../../../file_manager/foreground/js/metadata/metadata_cache.js"></script> <script src="../../../file_manager/foreground/js/metadata/byte_reader.js"></script> <script src="../../../file_manager/foreground/js/metadata/metadata_parser.js"></script> <script src="../../../file_manager/foreground/js/metadata/metadata_dispatcher.js"></script>
diff --git a/ui/file_manager/gallery/js/image_editor/image_encoder_unittest.html b/ui/file_manager/gallery/js/image_editor/image_encoder_unittest.html index ea6cede..0a527331 100644 --- a/ui/file_manager/gallery/js/image_editor/image_encoder_unittest.html +++ b/ui/file_manager/gallery/js/image_editor/image_encoder_unittest.html
@@ -8,7 +8,6 @@ <script src="../../../../webui/resources/js/assert.js"></script> -<script src="../../../file_manager/foreground/js/metadata/metadata_cache.js"></script> <script src="../../../file_manager/common/js/unittest_util.js"></script> <script src="image_util.js"></script>
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 83f4d63..76481b5 100644 --- a/ui/file_manager/gallery/js/image_editor/image_util.js +++ b/ui/file_manager/gallery/js/image_editor/image_util.js
@@ -427,11 +427,19 @@ * account. * * @param {!HTMLDocument} document Owner document. + * @param {!MetadataModel} metadataModel * @constructor * @struct */ -ImageUtil.ImageLoader = function(document) { +ImageUtil.ImageLoader = function(document, metadataModel) { this.document_ = document; + + /** + * @private {!MetadataModel} + * @const + */ + this.metadataModel_ = metadataModel; + this.image_ = new Image(); this.generation_ = 0; @@ -510,14 +518,10 @@ this.image_.onload = function() { this.image_.onerror = null; this.image_.onload = null; - item.getFetchedMedia().then(function(fetchedMediaMetadata) { - if (fetchedMediaMetadata.imageTransform) - onTransform(this.image_, fetchedMediaMetadata.imageTransform); - else - onTransform(this.image_); - }.bind(this)).catch(function(error) { - console.error(error.stack || error); - }); + this.metadataModel_.get([entry], ['contentImageTransform']).then( + function(metadataItems) { + onTransform(this.image_, metadataItems[0].contentImageTransform); + }.bind(this)); }.bind(this); // The error callback has an optional error argument, which in case of a
diff --git a/ui/file_manager/gallery/js/image_editor/image_view.js b/ui/file_manager/gallery/js/image_editor/image_view.js index 6bea3ef..05fa32d6 100644 --- a/ui/file_manager/gallery/js/image_editor/image_view.js +++ b/ui/file_manager/gallery/js/image_editor/image_view.js
@@ -7,11 +7,12 @@ * * @param {!HTMLElement} container The container element. * @param {!Viewport} viewport The viewport. + * @param {!MetadataModel} metadataModel * @constructor * @extends {ImageBuffer.Overlay} * @struct */ -function ImageView(container, viewport) { +function ImageView(container, viewport, metadataModel) { ImageBuffer.Overlay.call(this); this.container_ = container; @@ -27,10 +28,12 @@ this.contentGeneration_ = 0; this.displayedContentGeneration_ = 0; - this.imageLoader_ = new ImageUtil.ImageLoader(this.document_); + this.imageLoader_ = + new ImageUtil.ImageLoader(this.document_, metadataModel); // We have a separate image loader for prefetch which does not get cancelled // when the selection changes. - this.prefetchLoader_ = new ImageUtil.ImageLoader(this.document_); + this.prefetchLoader_ = + new ImageUtil.ImageLoader(this.document_, metadataModel); this.contentCallbacks_ = []; @@ -149,9 +152,10 @@ return ImageView.LoadTarget.CACHED_THUMBNAIL; // Only show thumbnails if there is no effect or the effect is Slide. - var metadata = item.getMetadata(); var thumbnailLoader = new ThumbnailLoader( - item.getEntry(), ThumbnailLoader.LoaderType.CANVAS, item.getMetadata()); + item.getEntry(), + ThumbnailLoader.LoaderType.CANVAS, + item.getThumbnailMetadataItem()); if ((effect instanceof ImageView.Effect.None || effect instanceof ImageView.Effect.Slide) && thumbnailLoader.getLoadTarget() !== @@ -347,7 +351,6 @@ ImageView.prototype.load = function(item, effect, displayCallback, loadCallback) { var entry = item.getEntry(); - var metadata = item.getMetadata() || {}; if (!(effect instanceof ImageView.Effect.None)) { // Skip effects when reloading repeatedly very quickly. @@ -386,7 +389,7 @@ var thumbnailLoader = new ThumbnailLoader( entry, ThumbnailLoader.LoaderType.CANVAS, - metadata); + item.getThumbnailMetadataItem()); thumbnailLoader.loadDetachedImage(function(success) { displayThumbnail( ImageView.LoadType.IMAGE_FILE, @@ -412,26 +415,16 @@ */ function displayThumbnail(loadType, canvas) { if (canvas) { - var width = null; - var height = null; - if (metadata.media) { - width = metadata.media.width; - height = metadata.media.height; - } - // If metadata.external.present is true, the image data is loaded directly - // from local cache, whose size may be out of sync with the drive - // metadata. - if (metadata.external && !metadata.external.present) { - width = metadata.external.imageWidth; - height = metadata.external.imageHeight; - } + var width = item.getMetadataItem().imageWidth; + var height = item.getMetadataItem().imageHeight; self.replace( canvas, effect, width, height, true /* preview */); - if (displayCallback) displayCallback(); + if (displayCallback) + displayCallback(); } loadMainImage(loadType, entry, !!canvas, (effect && canvas) ? effect.getSafeInterval() : 0); @@ -492,7 +485,7 @@ loadType, Object.keys(ImageView.LoadType).length); if (loadType === ImageView.LoadType.ERROR && - !navigator.onLine && !metadata.external.present) { + !navigator.onLine && !item.getMetadataItem().present) { loadType = ImageView.LoadType.OFFLINE; } if (loadCallback) loadCallback(loadType, animationDuration, opt_error);
diff --git a/ui/file_manager/gallery/js/mosaic_mode.js b/ui/file_manager/gallery/js/mosaic_mode.js index 1b419b6c..360b27d 100644 --- a/ui/file_manager/gallery/js/mosaic_mode.js +++ b/ui/file_manager/gallery/js/mosaic_mode.js
@@ -547,7 +547,7 @@ if (!this.tiles_) return; - if (!event.metadata) + if (!event.thumbnailChanged) return; // Thumbnail unchanged, nothing to do. var index = this.dataModel_.indexOf(event.item); @@ -2054,7 +2054,6 @@ * target dimensions using metadata. */ Mosaic.Tile.prototype.init = function() { - var metadata = this.getItem().getMetadata(); this.markUnloaded(); this.left_ = null; // Mark as not laid out. @@ -2065,7 +2064,7 @@ this.thumbnailLoader_ = new ThumbnailLoader( this.getItem().getEntry(), ThumbnailLoader.LoaderType.CANVAS, - metadata, + this.getItem().getThumbnailMetadataItem(), undefined, // Media type. [ ThumbnailLoader.LoadTarget.EXTERNAL_METADATA, @@ -2079,7 +2078,7 @@ this.thumbnailPreloader_ = new ThumbnailLoader( this.getItem().getEntry(), ThumbnailLoader.LoaderType.CANVAS, - metadata, + this.getItem().getThumbnailMetadataItem(), undefined, // Media type. [ ThumbnailLoader.LoadTarget.CONTENT_METADATA @@ -2095,15 +2094,12 @@ // extracted from headers. For Drive files, it is received via the Drive API. // If the dimensions are not available, then the fallback dimensions will be // used (same as for the generic icon). + var metadataItem = this.getItem().getMetadataItem(); var width; var height; - if (metadata.media && metadata.media.width) { - width = metadata.media.width; - height = metadata.media.height; - } else if (metadata.external && metadata.external.imageWidth && - metadata.external.imageHeight) { - width = metadata.external.imageWidth; - height = metadata.external.imageHeight; + if (metadataItem.imageWidth && metadataItem.imageHeight) { + width = metadataItem.imageWidth; + height = metadataItem.imageHeight; } else { // No dimensions in metadata, then use the generic dimensions. width = Mosaic.Tile.GENERIC_ICON_SIZE;
diff --git a/ui/file_manager/gallery/js/ribbon.js b/ui/file_manager/gallery/js/ribbon.js index 5926a32f..e84dc0d 100644 --- a/ui/file_manager/gallery/js/ribbon.js +++ b/ui/file_manager/gallery/js/ribbon.js
@@ -8,33 +8,40 @@ * @param {!Document} document Document. * @param {!cr.ui.ArrayDataModel} dataModel Data model. * @param {!cr.ui.ListSelectionModel} selectionModel Selection model. + * @param {!ThumbnailModel} thumbnailModel * @extends {HTMLDivElement} * @constructor * @suppress {checkStructDictInheritance} * @struct */ -function Ribbon(document, dataModel, selectionModel) { +function Ribbon(document, dataModel, selectionModel, thumbnailModel) { if (this instanceof Ribbon) { return Ribbon.call(/** @type {Ribbon} */ (document.createElement('div')), - document, dataModel, selectionModel); + document, dataModel, selectionModel, thumbnailModel); } this.__proto__ = Ribbon.prototype; this.className = 'ribbon'; /** - * @type {!cr.ui.ArrayDataModel} - * @private + * @private {!cr.ui.ArrayDataModel} + * @const */ this.dataModel_ = dataModel; /** - * @type {!cr.ui.ListSelectionModel} - * @private + * @private {!cr.ui.ListSelectionModel} + * @const */ this.selectionModel_ = selectionModel; /** + * @private {!ThumbnailModel} + * @const + */ + this.thumbnailModel_ = thumbnailModel; + + /** * @type {!Object} * @private */ @@ -389,14 +396,16 @@ * @private */ Ribbon.prototype.setThumbnailImage_ = function(thumbnail, item) { - var loader = new ThumbnailLoader( - item.getEntry(), - ThumbnailLoader.LoaderType.IMAGE, - item.getMetadata()); - loader.load( - thumbnail.querySelector('.image-wrapper'), - ThumbnailLoader.FillMode.FILL /* fill */, - ThumbnailLoader.OptimizationMode.NEVER_DISCARD); + this.thumbnailModel_.get([item.getEntry()]).then(function(metadataList) { + var loader = new ThumbnailLoader( + item.getEntry(), + ThumbnailLoader.LoaderType.IMAGE, + metadataList[0]); + loader.load( + thumbnail.querySelector('.image-wrapper'), + ThumbnailLoader.FillMode.FILL /* fill */, + ThumbnailLoader.OptimizationMode.NEVER_DISCARD); + }); }; /**
diff --git a/ui/file_manager/gallery/js/slide_mode.js b/ui/file_manager/gallery/js/slide_mode.js index fb91ef2..e5efc167 100644 --- a/ui/file_manager/gallery/js/slide_mode.js +++ b/ui/file_manager/gallery/js/slide_mode.js
@@ -13,18 +13,22 @@ * @param {!ErrorBanner} errorBanner Error banner. * @param {!cr.ui.ArrayDataModel} dataModel Data model. * @param {!cr.ui.ListSelectionModel} selectionModel Selection model. + * @param {!MetadataModel} metadataModel + * @param {!ThumbnailModel} thumbnailModel * @param {!Object} context Context. * @param {!VolumeManager} volumeManager Volume manager. * @param {function(function())} toggleMode Function to toggle the Gallery mode. * @param {function(string):string} displayStringFunction String formatting * function. + * @constructor * @struct * @suppress {checkStructDictInheritance} * @extends {cr.EventTarget} */ function SlideMode(container, content, toolbar, prompt, errorBanner, dataModel, - selectionModel, context, volumeManager, toggleMode, displayStringFunction) { + selectionModel, metadataModel, thumbnailModel, context, volumeManager, + toggleMode, displayStringFunction) { /** * @type {!HTMLElement} * @private @@ -95,13 +99,6 @@ this.volumeManager_ = volumeManager; /** - * @type {!MetadataCache} - * @private - * @const - */ - this.metadataCache_ = context.metadataCache; - - /** * @type {function(function())} * @private * @const @@ -337,7 +334,7 @@ * @const */ this.ribbon_ = new Ribbon( - this.document_, this.dataModel_, this.selectionModel_); + this.document_, this.dataModel_, this.selectionModel_, thumbnailModel); this.ribbonSpacer_.appendChild(this.ribbon_); util.createChild(this.container_, 'spinner'); @@ -428,7 +425,8 @@ */ this.imageView_ = new ImageView( this.imageContainer_, - this.viewport_); + this.viewport_, + metadataModel); /** * @type {!ImageEditor} @@ -993,7 +991,6 @@ SlideMode.prototype.itemLoaded_ = function( item, loadCallback, loadType, delay, opt_error) { var entry = item.getEntry(); - var metadata = item.getMetadata(); this.showSpinner_(false); if (loadType === ImageView.LoadType.ERROR) { @@ -1015,7 +1012,7 @@ }; ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MB'), - toMillions(metadata.filesystem.size)); + toMillions(item.getMetadataItem().size)); var canvas = this.imageView_.getCanvas(); ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MPix'),
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn index 88a3647e..07915fae 100644 --- a/ui/gfx/BUILD.gn +++ b/ui/gfx/BUILD.gn
@@ -85,7 +85,7 @@ "font.h", "font_fallback.h", "font_fallback_linux.cc", - "font_fallback_mac.cc", + "font_fallback_mac.mm", "font_fallback_win.cc", "font_fallback_win.h", "font_list.cc", @@ -420,6 +420,7 @@ "color_utils_unittest.cc", "display_change_notifier_unittest.cc", "display_unittest.cc", + "font_fallback_mac_unittest.cc", "font_list_unittest.cc", "geometry/box_unittest.cc", "geometry/cubic_bezier_unittest.cc",
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h index c8fd284..88882fa 100644 --- a/ui/gfx/canvas.h +++ b/ui/gfx/canvas.h
@@ -40,48 +40,35 @@ // of kSrcOver_Mode. class GFX_EXPORT Canvas { public: - // Specifies the alignment for text rendered with the DrawStringRect method. enum { + // Specifies the alignment for text rendered with the DrawStringRect method. TEXT_ALIGN_LEFT = 1 << 0, TEXT_ALIGN_CENTER = 1 << 1, TEXT_ALIGN_RIGHT = 1 << 2, + TEXT_ALIGN_TO_HEAD = 1 << 3, // Specifies the text consists of multiple lines. - MULTI_LINE = 1 << 3, + MULTI_LINE = 1 << 4, // By default DrawStringRect does not process the prefix ('&') character // specially. That is, the string "&foo" is rendered as "&foo". When // rendering text from a resource that uses the prefix character for // mnemonics, the prefix should be processed and can be rendered as an // underline (SHOW_PREFIX), or not rendered at all (HIDE_PREFIX). - SHOW_PREFIX = 1 << 4, - HIDE_PREFIX = 1 << 5, + SHOW_PREFIX = 1 << 5, + HIDE_PREFIX = 1 << 6, // Prevent ellipsizing - NO_ELLIPSIS = 1 << 6, + NO_ELLIPSIS = 1 << 7, // Specifies if words can be split by new lines. // This only works with MULTI_LINE. - CHARACTER_BREAK = 1 << 7, - - // Instructs DrawStringRect() to render the text using RTL directionality. - // In most cases, passing this flag is not necessary because information - // about the text directionality is going to be embedded within the string - // in the form of special Unicode characters. However, we don't insert - // directionality characters into strings if the locale is LTR because some - // platforms (for example, an English Windows XP with no RTL fonts - // installed) don't support these characters. Thus, this flag should be - // used to render text using RTL directionality when the locale is LTR. - FORCE_RTL_DIRECTIONALITY = 1 << 8, - - // Similar to FORCE_RTL_DIRECTIONALITY, but left-to-right. - // See FORCE_RTL_DIRECTIONALITY for details. - FORCE_LTR_DIRECTIONALITY = 1 << 9, + CHARACTER_BREAK = 1 << 8, // Instructs DrawStringRect() to not use subpixel rendering. This is useful // when rendering text onto a fully- or partially-transparent background // that will later be blended with another image. - NO_SUBPIXEL_RENDERING = 1 << 10, + NO_SUBPIXEL_RENDERING = 1 << 9, }; // Creates an empty canvas with image_scale of 1x.
diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc index 3de9b93..428c32a8 100644 --- a/ui/gfx/canvas_skia.cc +++ b/ui/gfx/canvas_skia.cc
@@ -21,41 +21,6 @@ namespace { -#if defined(OS_WIN) -// If necessary, wraps |text| with RTL/LTR directionality characters based on -// |flags| and |text| content. -// Returns true if the text will be rendered right-to-left. -// TODO(msw): Nix this, now that RenderTextWin supports directionality directly. -bool AdjustStringDirection(int flags, base::string16* text) { - // TODO(msw): FORCE_LTR_DIRECTIONALITY does not work for RTL text now. - - // If the string is empty or LTR was forced, simply return false since the - // default RenderText directionality is already LTR. - if (text->empty() || (flags & Canvas::FORCE_LTR_DIRECTIONALITY)) - return false; - - // If RTL is forced, apply it to the string. - if (flags & Canvas::FORCE_RTL_DIRECTIONALITY) { - base::i18n::WrapStringWithRTLFormatting(text); - return true; - } - - // If a direction wasn't forced but the UI language is RTL and there were - // strong RTL characters, ensure RTL is applied. - if (base::i18n::IsRTL() && base::i18n::StringContainsStrongRTLChars(*text)) { - base::i18n::WrapStringWithRTLFormatting(text); - return true; - } - - // In the default case, the string should be rendered as LTR. RenderText's - // default directionality is LTR, so the text doesn't need to be wrapped. - // Note that individual runs within the string may still be rendered RTL - // (which will be the case for RTL text under non-RTL locales, since under RTL - // locales it will be handled by the if statement above). - return false; -} -#endif // defined(OS_WIN) - // Checks each pixel immediately adjacent to the given pixel in the bitmap. If // any of them are not the halo color, returns true. This defines the halo of // pixels that will appear around the text. Note that we have to check each @@ -131,11 +96,14 @@ // if not specified. if (!(flags & (Canvas::TEXT_ALIGN_CENTER | Canvas::TEXT_ALIGN_RIGHT | - Canvas::TEXT_ALIGN_LEFT))) { + Canvas::TEXT_ALIGN_LEFT | + Canvas::TEXT_ALIGN_TO_HEAD))) { flags |= Canvas::DefaultCanvasTextAlignment(); } - if (flags & Canvas::TEXT_ALIGN_RIGHT) + if (flags & Canvas::TEXT_ALIGN_TO_HEAD) + render_text->SetHorizontalAlignment(ALIGN_TO_HEAD); + else if (flags & Canvas::TEXT_ALIGN_RIGHT) render_text->SetHorizontalAlignment(ALIGN_RIGHT); else if (flags & Canvas::TEXT_ALIGN_CENTER) render_text->SetHorizontalAlignment(ALIGN_CENTER); @@ -163,11 +131,6 @@ DCHECK_GE(*width, 0); DCHECK_GE(*height, 0); - base::string16 adjusted_text = text; -#if defined(OS_WIN) - AdjustStringDirection(flags, &adjusted_text); -#endif - if ((flags & MULTI_LINE) && *width != 0) { WordWrapBehavior wrap_behavior = TRUNCATE_LONG_WORDS; if (flags & CHARACTER_BREAK) @@ -176,9 +139,8 @@ wrap_behavior = ELIDE_LONG_WORDS; std::vector<base::string16> strings; - ElideRectangleText(adjusted_text, font_list, - *width, INT_MAX, - wrap_behavior, &strings); + ElideRectangleText(text, font_list, *width, INT_MAX, wrap_behavior, + &strings); Rect rect(ClampToInt(*width), INT_MAX); scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); UpdateRenderText(rect, base::string16(), font_list, flags, 0, @@ -198,23 +160,15 @@ *width = w; *height = h; } else { - // If the string is too long, the call by |RenderTextWin| to |ScriptShape()| - // will inexplicably fail with result E_INVALIDARG. Guard against this. - const size_t kMaxRenderTextLength = 5000; - if (adjusted_text.length() >= kMaxRenderTextLength) { - *width = static_cast<float>( - font_list.GetExpectedTextWidth(adjusted_text.length())); - *height = static_cast<float>(font_list.GetHeight()); - } else { - scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); - Rect rect(ClampToInt(*width), ClampToInt(*height)); - StripAcceleratorChars(flags, &adjusted_text); - UpdateRenderText(rect, adjusted_text, font_list, flags, 0, - render_text.get()); - const SizeF& string_size = render_text->GetStringSizeF(); - *width = string_size.width(); - *height = string_size.height(); - } + scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); + Rect rect(ClampToInt(*width), ClampToInt(*height)); + base::string16 adjusted_text = text; + StripAcceleratorChars(flags, &adjusted_text); + UpdateRenderText(rect, adjusted_text, font_list, flags, 0, + render_text.get()); + const SizeF& string_size = render_text->GetStringSizeF(); + *width = string_size.width(); + *height = string_size.height(); } } @@ -235,11 +189,6 @@ ClipRect(clip_rect); Rect rect(text_bounds); - base::string16 adjusted_text = text; - -#if defined(OS_WIN) - AdjustStringDirection(flags, &adjusted_text); -#endif scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); render_text->set_shadows(shadows); @@ -252,7 +201,7 @@ wrap_behavior = ELIDE_LONG_WORDS; std::vector<base::string16> strings; - ElideRectangleText(adjusted_text, font_list, + ElideRectangleText(text, font_list, static_cast<float>(text_bounds.width()), text_bounds.height(), wrap_behavior, &strings); @@ -284,6 +233,7 @@ rect += Vector2d(0, line_height); } } else { + base::string16 adjusted_text = text; Range range = StripAcceleratorChars(flags, &adjusted_text); bool elide_text = ((flags & NO_ELLIPSIS) == 0); @@ -373,21 +323,10 @@ DrawStringRectWithFlags(text, font_list, color, display_rect, flags); return; } - - // Align with forced content directionality, overriding alignment flags. - if (flags & FORCE_RTL_DIRECTIONALITY) { - flags &= ~(TEXT_ALIGN_CENTER | TEXT_ALIGN_LEFT); - flags |= TEXT_ALIGN_RIGHT; - } else if (flags & FORCE_LTR_DIRECTIONALITY) { - flags &= ~(TEXT_ALIGN_CENTER | TEXT_ALIGN_RIGHT); - flags |= TEXT_ALIGN_LEFT; - } else if (!(flags & TEXT_ALIGN_LEFT) && !(flags & TEXT_ALIGN_RIGHT)) { - // Also align with content directionality instead of fading both ends. - flags &= ~TEXT_ALIGN_CENTER; - const bool is_rtl = base::i18n::GetFirstStrongCharacterDirection(text) == - base::i18n::RIGHT_TO_LEFT; - flags |= is_rtl ? TEXT_ALIGN_RIGHT : TEXT_ALIGN_LEFT; - } + // Align with content directionality instead of fading both ends. + flags &= ~TEXT_ALIGN_CENTER; + if (!(flags & (TEXT_ALIGN_LEFT | TEXT_ALIGN_RIGHT))) + flags |= TEXT_ALIGN_TO_HEAD; flags |= NO_ELLIPSIS; scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
diff --git a/ui/gfx/font_fallback.h b/ui/gfx/font_fallback.h index 78f3937..05d21cad 100644 --- a/ui/gfx/font_fallback.h +++ b/ui/gfx/font_fallback.h
@@ -8,11 +8,13 @@ #include <string> #include <vector> +#include "ui/gfx/gfx_export.h" + namespace gfx { // Given a font family name, returns the names of font families that are // suitable for fallback. -std::vector<std::string> GetFallbackFontFamilies( +GFX_EXPORT std::vector<std::string> GetFallbackFontFamilies( const std::string& font_family); } // namespace gfx
diff --git a/ui/gfx/font_fallback_mac.cc b/ui/gfx/font_fallback_mac.cc deleted file mode 100644 index 3d96d11..0000000 --- a/ui/gfx/font_fallback_mac.cc +++ /dev/null
@@ -1,20 +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 "ui/gfx/font_fallback.h" - -#include <string> -#include <vector> - -#include "base/logging.h" - -namespace gfx { - -std::vector<std::string> GetFallbackFontFamilies( - const std::string& font_family) { - // TODO(jiangj): Not implemented, see crbug.com/439039. - return std::vector<std::string>(1, font_family); -} - -} // namespace gfx
diff --git a/ui/gfx/font_fallback_mac.mm b/ui/gfx/font_fallback_mac.mm new file mode 100644 index 0000000..25df09a --- /dev/null +++ b/ui/gfx/font_fallback_mac.mm
@@ -0,0 +1,102 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/font_fallback.h" + +#import <Foundation/Foundation.h> +#include <dlfcn.h> +#include <string> +#include <vector> + +#import "base/strings/sys_string_conversions.h" +#include "base/mac/foundation_util.h" +#import "base/mac/mac_util.h" + +// CTFontCopyDefaultCascadeListForLanguages() doesn't exist in the 10.6 SDK. +// There is only the following. It doesn't exist in the public header files, +// but is an exported symbol so should always link. +extern "C" CFArrayRef CTFontCopyDefaultCascadeList(CTFontRef font_ref); + +namespace { + +// Wrapper for CTFontCopyDefaultCascadeListForLanguages() which should appear in +// CoreText.h from 10.8 onwards. +// TODO(tapted): Delete this wrapper when only 10.8+ is supported. +CFArrayRef CTFontCopyDefaultCascadeListForLanguagesWrapper( + CTFontRef font_ref, + CFArrayRef language_pref_list) { + typedef CFArrayRef (*MountainLionPrototype)(CTFontRef, CFArrayRef); + static const MountainLionPrototype cascade_with_languages_function = + reinterpret_cast<MountainLionPrototype>( + dlsym(RTLD_DEFAULT, "CTFontCopyDefaultCascadeListForLanguages")); + if (cascade_with_languages_function) + return cascade_with_languages_function(font_ref, language_pref_list); + + // Fallback to the 10.6 Private API. + DCHECK(base::mac::IsOSLionOrEarlier()); + return CTFontCopyDefaultCascadeList(font_ref); +} + +} // namespace + +namespace gfx { + +std::vector<std::string> GetFallbackFontFamilies( + const std::string& font_family) { + // On Mac "There is a system default cascade list (which is polymorphic, based + // on the user's language setting and current font)" - CoreText Programming + // Guide. + // The CoreText APIs provide CTFontCreateForString(font, string, range), but + // it requires a text string "hint", and the returned font can't be + // represented by name for easy retrieval later. + // In 10.8, CTFontCopyDefaultCascadeListForLanguages(font, language_list) + // showed up which is a good fit GetFallbackFontFamilies(). + + // Size doesn't matter for querying the cascade list. + const CGFloat font_size = 10.0; + base::ScopedCFTypeRef<CFStringRef> cfname( + base::SysUTF8ToCFStringRef(font_family)); + + // Using CTFontCreateWithName here works, but CoreText emits stderr spam along + // the lines of `CTFontCreateWithName() using name "Arial" and got font with + // PostScript name "ArialMT".` Instead, create a descriptor. + const void* attribute_keys[] = {kCTFontFamilyNameAttribute}; + const void* attribute_values[] = {cfname.get()}; + base::ScopedCFTypeRef<CFDictionaryRef> attributes(CFDictionaryCreate( + kCFAllocatorDefault, attribute_keys, attribute_values, 1, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + base::ScopedCFTypeRef<CTFontDescriptorRef> descriptor( + CTFontDescriptorCreateWithAttributes(attributes)); + base::ScopedCFTypeRef<CTFontRef> base_font( + CTFontCreateWithFontDescriptor(descriptor, font_size, nullptr)); + + if (!base_font) + return std::vector<std::string>(1, font_family); + + NSArray* languages = [[NSUserDefaults standardUserDefaults] + stringArrayForKey:@"AppleLanguages"]; + CFArrayRef languages_cf = base::mac::NSToCFCast(languages); + base::ScopedCFTypeRef<CFArrayRef> cascade_list( + CTFontCopyDefaultCascadeListForLanguagesWrapper(base_font, languages_cf)); + + std::vector<std::string> fallback_fonts; + + const CFIndex fallback_count = CFArrayGetCount(cascade_list); + for (CFIndex i = 0; i < fallback_count; ++i) { + CTFontDescriptorRef descriptor = + base::mac::CFCastStrict<CTFontDescriptorRef>( + CFArrayGetValueAtIndex(cascade_list, i)); + base::ScopedCFTypeRef<CFStringRef> font_name( + base::mac::CFCastStrict<CFStringRef>(CTFontDescriptorCopyAttribute( + descriptor, kCTFontFamilyNameAttribute))); + fallback_fonts.push_back(base::SysCFStringRefToUTF8(font_name)); + } + + if (fallback_fonts.empty()) + return std::vector<std::string>(1, font_family); + + return fallback_fonts; +} + +} // namespace gfx
diff --git a/ui/gfx/font_fallback_mac_unittest.cc b/ui/gfx/font_fallback_mac_unittest.cc new file mode 100644 index 0000000..689ec6d --- /dev/null +++ b/ui/gfx/font_fallback_mac_unittest.cc
@@ -0,0 +1,21 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/font_fallback.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace gfx { + +// A targeted test for GetFallbackFontFamilies on Mac. It uses a system API that +// only became publicly available in the 10.8 SDK. This test is to ensure it +// behaves sensibly on all supported OS versions. +GTEST_TEST(FontFallbackMacTest, GetFallbackFontFamilies) { + std::vector<std::string> fallback_families = GetFallbackFontFamilies("Arial"); + // If there is only one fallback, it means the only fallback is the font + // itself. + EXPECT_LT(1u, fallback_families.size()); +} + +} // namespace gfx
diff --git a/ui/gfx/gfx.gyp b/ui/gfx/gfx.gyp index d8da3fed..a7de96e 100644 --- a/ui/gfx/gfx.gyp +++ b/ui/gfx/gfx.gyp
@@ -163,7 +163,7 @@ 'font.h', 'font_fallback.h', 'font_fallback_linux.cc', - 'font_fallback_mac.cc', + 'font_fallback_mac.mm', 'font_fallback_win.cc', 'font_fallback_win.h', 'font_list.cc',
diff --git a/ui/gfx/gfx_tests.gyp b/ui/gfx/gfx_tests.gyp index f4d30e2..a6f2f81 100644 --- a/ui/gfx/gfx_tests.gyp +++ b/ui/gfx/gfx_tests.gyp
@@ -41,6 +41,7 @@ 'color_utils_unittest.cc', 'display_change_notifier_unittest.cc', 'display_unittest.cc', + 'font_fallback_mac_unittest.cc', 'font_list_unittest.cc', 'font_render_params_linux_unittest.cc', 'geometry/box_unittest.cc',
diff --git a/ui/gfx/render_text_harfbuzz.h b/ui/gfx/render_text_harfbuzz.h index 2c9e20fe..eabf798 100644 --- a/ui/gfx/render_text_harfbuzz.h +++ b/ui/gfx/render_text_harfbuzz.h
@@ -174,6 +174,7 @@ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_SubglyphGraphemePartition); FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_NonExistentFont); FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_UniscribeFallback); + FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_UnicodeFallback); // Specify the width of a glyph for test. The width of glyphs is very // platform-dependent and environment-dependent. Otherwise multiline test
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc index 542939ea..e274a266 100644 --- a/ui/gfx/render_text_unittest.cc +++ b/ui/gfx/render_text_unittest.cc
@@ -2569,6 +2569,24 @@ } #endif // defined(OS_WIN) +// Ensure that the fallback fonts offered by gfx::GetFallbackFontFamilies() are +// tried. Note this test assumes the font "Arial" doesn't provide a unicode +// glyph for a particular character, and that there exists a system fallback +// font which does. +#if defined(OS_WIN) || defined(OS_MACOSX) +TEST_F(RenderTextTest, HarfBuzz_UnicodeFallback) { + RenderTextHarfBuzz render_text; + render_text.SetFontList(FontList("Arial, 12px")); + + // Korean character "han". + render_text.SetText(WideToUTF16(L"\xd55c")); + render_text.EnsureLayout(); + internal::TextRunList* run_list = render_text.GetRunList(); + ASSERT_EQ(1U, run_list->size()); + EXPECT_EQ(0U, run_list->runs()[0]->CountMissingGlyphs()); +} +#endif // defined(OS_WIN) || defined(OS_MACOSX) + // 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) {
diff --git a/ui/gfx/x/x11_error_tracker.cc b/ui/gfx/x/x11_error_tracker.cc index 110f79c..859e718 100644 --- a/ui/gfx/x/x11_error_tracker.cc +++ b/ui/gfx/x/x11_error_tracker.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/logging.h" #include "ui/gfx/x/x11_error_tracker.h" +#include "base/logging.h" #include "ui/gfx/x/x11_types.h" namespace { @@ -16,7 +16,8 @@ g_x11_error_code = error->error_code; return 0; } -} + +} // namespace namespace gfx {
diff --git a/ui/gl/android/surface_texture.cc b/ui/gl/android/surface_texture.cc index bf9012a..a9f52dc5 100644 --- a/ui/gl/android/surface_texture.cc +++ b/ui/gl/android/surface_texture.cc
@@ -87,19 +87,6 @@ env->ReleaseFloatArrayElements(jmatrix.obj(), elements, JNI_ABORT); } -void SurfaceTexture::SetDefaultBufferSize(int width, int height) { - JNIEnv* env = base::android::AttachCurrentThread(); - - if (width > 0 && height > 0) { - Java_SurfaceTexturePlatformWrapper_setDefaultBufferSize( - env, j_surface_texture_.obj(), static_cast<jint>(width), - static_cast<jint>(height)); - } else { - LOG(WARNING) << "Not setting surface texture buffer size - " - "width or height is 0"; - } -} - void SurfaceTexture::AttachToGLContext() { if (GlContextMethodsAvailable()) { int texture_id;
diff --git a/ui/gl/android/surface_texture.h b/ui/gl/android/surface_texture.h index 05bc5a3..b22e5c4 100644 --- a/ui/gl/android/surface_texture.h +++ b/ui/gl/android/surface_texture.h
@@ -46,9 +46,6 @@ // texture image set by the most recent call to updateTexImage. void GetTransformMatrix(float mtx[16]); - // Set the default size of the image buffers. - void SetDefaultBufferSize(int width, int height); - // Attach the SurfaceTexture to the texture currently bound to // GL_TEXTURE_EXTERNAL_OES. void AttachToGLContext();
diff --git a/ui/gl/gl_image_memory.cc b/ui/gl/gl_image_memory.cc index 6b9a519..ca106b7 100644 --- a/ui/gl/gl_image_memory.cc +++ b/ui/gl/gl_image_memory.cc
@@ -183,30 +183,6 @@ return false; } -// static -bool GLImageMemory::ValidSize(const gfx::Size& size, - gfx::GpuMemoryBuffer::Format format) { - switch (format) { - case gfx::GpuMemoryBuffer::ATC: - case gfx::GpuMemoryBuffer::ATCIA: - case gfx::GpuMemoryBuffer::DXT1: - case gfx::GpuMemoryBuffer::DXT5: - case gfx::GpuMemoryBuffer::ETC1: - // Compressed images must have a width and height that's evenly divisible - // by the block size. - return size.width() % 4 == 0 && size.height() % 4 == 0; - case gfx::GpuMemoryBuffer::RGBA_8888: - case gfx::GpuMemoryBuffer::BGRA_8888: - return true; - case gfx::GpuMemoryBuffer::RGBX_8888: - NOTREACHED(); - return false; - } - - NOTREACHED(); - return false; -} - bool GLImageMemory::Initialize(const unsigned char* memory, gfx::GpuMemoryBuffer::Format format) { if (!ValidInternalFormat(internalformat_)) { @@ -221,6 +197,8 @@ DCHECK(memory); DCHECK(!memory_); + DCHECK_IMPLIES(IsCompressedFormat(format), size_.width() % 4 == 0); + DCHECK_IMPLIES(IsCompressedFormat(format), size_.height() % 4 == 0); memory_ = memory; format_ = format; return true;
diff --git a/ui/gl/gl_image_memory.h b/ui/gl/gl_image_memory.h index befc3a8e..a50a3806 100644 --- a/ui/gl/gl_image_memory.h +++ b/ui/gl/gl_image_memory.h
@@ -26,9 +26,6 @@ gfx::GpuMemoryBuffer::Format format, size_t* stride_in_bytes); - static bool ValidSize(const gfx::Size& size, - gfx::GpuMemoryBuffer::Format format); - bool Initialize(const unsigned char* memory, gfx::GpuMemoryBuffer::Format format);
diff --git a/ui/gl/gl_image_shared_memory.cc b/ui/gl/gl_image_shared_memory.cc index 363ebf5b..d9e31a7 100644 --- a/ui/gl/gl_image_shared_memory.cc +++ b/ui/gl/gl_image_shared_memory.cc
@@ -18,9 +18,6 @@ if (size.IsEmpty()) return false; - if (!GLImageMemory::ValidSize(size, format)) - return false; - size_t stride_in_bytes = 0; if (!GLImageMemory::StrideInBytes(size.width(), format, &stride_in_bytes)) return false;
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h index a6e6ff1d..b67ca69 100644 --- a/ui/gl/gl_surface.h +++ b/ui/gl/gl_surface.h
@@ -156,6 +156,15 @@ static scoped_refptr<GLSurface> CreateViewGLSurface( gfx::AcceleratedWidget window); +#if defined(USE_OZONE) + // Create a GL surface that renders directly into a window with surfaceless + // semantics - there is no default framebuffer and the primary surface must + // be presented as an overlay. If surfaceless mode is not supported or + // enabled it will return a null pointer. + static scoped_refptr<GLSurface> CreateSurfacelessViewGLSurface( + gfx::AcceleratedWidget window); +#endif // defined(USE_OZONE) + // Create a GL surface used for offscreen rendering. static scoped_refptr<GLSurface> CreateOffscreenGLSurface( const gfx::Size& size);
diff --git a/ui/gl/gl_surface_ozone.cc b/ui/gl/gl_surface_ozone.cc index f79b6d0..47ea8d6 100644 --- a/ui/gl/gl_surface_ozone.cc +++ b/ui/gl/gl_surface_ozone.cc
@@ -4,16 +4,20 @@ #include "ui/gl/gl_surface.h" +#include "base/bind.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "ui/gfx/native_widget_types.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_image.h" +#include "ui/gl/gl_image_linux_dma_buffer.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_surface_egl.h" #include "ui/gl/gl_surface_osmesa.h" #include "ui/gl/gl_surface_stub.h" +#include "ui/gl/scoped_binders.h" #include "ui/gl/scoped_make_current.h" +#include "ui/ozone/public/native_pixmap.h" #include "ui/ozone/public/surface_factory_ozone.h" #include "ui/ozone/public/surface_ozone_egl.h" @@ -157,7 +161,7 @@ return SwapBuffersAsync(callback); } - private: + protected: ~GLSurfaceOzoneSurfaceless() override { Destroy(); // EGL surface must be destroyed before SurfaceOzone } @@ -196,6 +200,157 @@ DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfaceless); }; +// This provides surface-like semantics implemented through surfaceless. +// A framebuffer is bound automatically. +class GL_EXPORT GLSurfaceOzoneSurfacelessSurfaceImpl + : public GLSurfaceOzoneSurfaceless { + public: + GLSurfaceOzoneSurfacelessSurfaceImpl( + scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, + AcceleratedWidget widget) + : GLSurfaceOzoneSurfaceless(ozone_surface.Pass(), widget), + fbo_(0), + current_surface_(0) { + for (auto& texture : textures_) + texture = 0; + } + + unsigned int GetBackingFrameBufferObject() override { return fbo_; } + + bool OnMakeCurrent(GLContext* context) override { + if (!fbo_) { + glGenFramebuffersEXT(1, &fbo_); + if (!fbo_) + return false; + glGenTextures(arraysize(textures_), textures_); + if (!CreatePixmaps()) + return false; + } + BindFramebuffer(); + glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_); + return SurfacelessEGL::OnMakeCurrent(context); + } + + bool Resize(const gfx::Size& size) override { + if (size == GetSize()) + return true; + return GLSurfaceOzoneSurfaceless::Resize(size) && CreatePixmaps(); + } + + bool SupportsPostSubBuffer() override { return false; } + + bool SwapBuffers() override { + if (!images_[current_surface_]->ScheduleOverlayPlane( + widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE, + gfx::Rect(GetSize()), gfx::RectF(1, 1))) + return false; + if (!GLSurfaceOzoneSurfaceless::SwapBuffers()) + return false; + current_surface_ ^= 1; + BindFramebuffer(); + return true; + } + + bool SwapBuffersAsync(const SwapCompletionCallback& callback) override { + if (!images_[current_surface_]->ScheduleOverlayPlane( + widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE, + gfx::Rect(GetSize()), gfx::RectF(1, 1))) + return false; + if (!GLSurfaceOzoneSurfaceless::SwapBuffersAsync(callback)) + return false; + current_surface_ ^= 1; + BindFramebuffer(); + return true; + } + + void Destroy() override { + GLContext* current_context = GLContext::GetCurrent(); + DCHECK(current_context && current_context->IsCurrent(this)); + glBindFramebufferEXT(GL_FRAMEBUFFER, 0); + if (fbo_) { + glDeleteTextures(arraysize(textures_), textures_); + for (auto& texture : textures_) + texture = 0; + glDeleteFramebuffersEXT(1, &fbo_); + fbo_ = 0; + } + for (auto image : images_) { + if (image) + image->Destroy(true); + } + } + + private: + class SurfaceImage : public GLImageLinuxDMABuffer { + public: + SurfaceImage(const gfx::Size& size, unsigned internalformat) + : GLImageLinuxDMABuffer(size, internalformat) {} + + bool Initialize(scoped_refptr<ui::NativePixmap> pixmap, + gfx::GpuMemoryBuffer::Format format) { + base::FileDescriptor handle(pixmap->GetDmaBufFd(), false); + if (!GLImageLinuxDMABuffer::Initialize(handle, format, + pixmap->GetDmaBufPitch())) + return false; + pixmap_ = pixmap; + return true; + } + bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget, + int z_order, + gfx::OverlayTransform transform, + const gfx::Rect& bounds_rect, + const gfx::RectF& crop_rect) override { + return ui::SurfaceFactoryOzone::GetInstance()->ScheduleOverlayPlane( + widget, z_order, transform, pixmap_, bounds_rect, crop_rect); + } + + private: + ~SurfaceImage() override {} + + scoped_refptr<ui::NativePixmap> pixmap_; + }; + + ~GLSurfaceOzoneSurfacelessSurfaceImpl() override { + DCHECK(!fbo_); + for (size_t i = 0; i < arraysize(textures_); i++) + DCHECK(!textures_[i]) << "texture " << i << " not released"; + } + + void BindFramebuffer() { + ScopedFrameBufferBinder fb(fbo_); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, textures_[current_surface_], 0); + } + + bool CreatePixmaps() { + if (!fbo_) + return true; + for (size_t i = 0; i < arraysize(textures_); i++) { + scoped_refptr<ui::NativePixmap> pixmap = + ui::SurfaceFactoryOzone::GetInstance()->CreateNativePixmap( + widget_, GetSize(), ui::SurfaceFactoryOzone::RGBA_8888, + ui::SurfaceFactoryOzone::SCANOUT); + if (!pixmap) + return false; + scoped_refptr<SurfaceImage> image = new SurfaceImage(GetSize(), GL_RGBA); + if (!image->Initialize(pixmap, gfx::GpuMemoryBuffer::Format::BGRA_8888)) + return false; + images_[i] = image; + // Bind image to texture. + ScopedTextureBinder binder(GL_TEXTURE_2D, textures_[i]); + if (!images_[i]->BindTexImage(GL_TEXTURE_2D)) + return false; + } + return true; + } + + GLuint fbo_; + GLuint textures_[2]; + scoped_refptr<GLImage> images_[2]; + int current_surface_; + DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfacelessSurfaceImpl); +}; + } // namespace // static @@ -217,6 +372,27 @@ } // static +scoped_refptr<GLSurface> GLSurface::CreateSurfacelessViewGLSurface( + gfx::AcceleratedWidget window) { + if (GetGLImplementation() == kGLImplementationEGLGLES2 && + window != kNullAcceleratedWidget && + GLSurfaceEGL::IsEGLSurfacelessContextSupported() && + ui::SurfaceFactoryOzone::GetInstance()->CanShowPrimaryPlaneAsOverlay()) { + scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone = + ui::SurfaceFactoryOzone::GetInstance() + ->CreateSurfacelessEGLSurfaceForWidget(window); + if (!surface_ozone) + return nullptr; + scoped_refptr<GLSurface> surface; + surface = new GLSurfaceOzoneSurfaceless(surface_ozone.Pass(), window); + if (surface->Initialize()) + return surface; + } + + return nullptr; +} + +// static scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface( gfx::AcceleratedWidget window) { if (GetGLImplementation() == kGLImplementationOSMesaGL) { @@ -236,7 +412,8 @@ ->CreateSurfacelessEGLSurfaceForWidget(window); if (!surface_ozone) return NULL; - surface = new GLSurfaceOzoneSurfaceless(surface_ozone.Pass(), window); + surface = new GLSurfaceOzoneSurfacelessSurfaceImpl(surface_ozone.Pass(), + window); } else { scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone = ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
diff --git a/ui/keyboard/BUILD.gn b/ui/keyboard/BUILD.gn index b504ba2..66a98a4 100644 --- a/ui/keyboard/BUILD.gn +++ b/ui/keyboard/BUILD.gn
@@ -93,33 +93,31 @@ path = rebase_path("//third_party/google_input_tools") } -if (!is_win || link_chrome_on_windows) { - test("keyboard_unittests") { - sources = [ - "keyboard_controller_unittest.cc", - "test/run_all_unittests.cc", - ] +test("keyboard_unittests") { + sources = [ + "keyboard_controller_unittest.cc", + "test/run_all_unittests.cc", + ] - deps = [ - ":keyboard", - "//base", - "//base/allocator", - "//base/test:test_support", - "//content", - "//skia", - "//testing/gtest", - "//ui/aura:test_support", - "//ui/base", - "//ui/base/ime", - "//ui/base:test_support", - "//ui/compositor:test_support", - "//ui/events:test_support", - "//ui/gfx", - "//ui/gfx/geometry", - "//ui/gl", - "//ui/resources:ui_test_pak", - "//ui/wm", - "//url", - ] - } + deps = [ + ":keyboard", + "//base", + "//base/allocator", + "//base/test:test_support", + "//content", + "//skia", + "//testing/gtest", + "//ui/aura:test_support", + "//ui/base", + "//ui/base/ime", + "//ui/base:test_support", + "//ui/compositor:test_support", + "//ui/events:test_support", + "//ui/gfx", + "//ui/gfx/geometry", + "//ui/gl", + "//ui/resources:ui_test_pak", + "//ui/wm", + "//url", + ] }
diff --git a/ui/message_center/BUILD.gn b/ui/message_center/BUILD.gn index b295019..cedc5b9 100644 --- a/ui/message_center/BUILD.gn +++ b/ui/message_center/BUILD.gn
@@ -176,65 +176,63 @@ ] } -if (!is_win || link_chrome_on_windows) { - test("message_center_unittests") { - sources = [ - "test/run_all_unittests.cc", +test("message_center_unittests") { + sources = [ + "test/run_all_unittests.cc", + ] + + deps = [ + ":message_center", + ":test_support", + "//base", + "//base/allocator", + "//base/test:test_support", + "//skia", + "//testing/gtest", + "//ui/base", + "//ui/events", + "//ui/gfx", + "//ui/gfx/geometry", + "//ui/gl", + "//ui/resources", + "//ui/resources:ui_test_pak", + "//url", + ] + + if (enable_notifications && !is_android) { + sources += [ + "cocoa/notification_controller_unittest.mm", + "cocoa/popup_collection_unittest.mm", + "cocoa/popup_controller_unittest.mm", + "cocoa/settings_controller_unittest.mm", + "cocoa/status_item_view_unittest.mm", + "cocoa/tray_controller_unittest.mm", + "cocoa/tray_view_controller_unittest.mm", + "message_center_impl_unittest.cc", + "message_center_tray_unittest.cc", + "notification_delegate_unittest.cc", + "notification_list_unittest.cc", ] - deps = [ - ":message_center", - ":test_support", - "//base", - "//base/allocator", - "//base/test:test_support", - "//skia", - "//testing/gtest", - "//ui/base", - "//ui/events", - "//ui/gfx", - "//ui/gfx/geometry", - "//ui/gl", - "//ui/resources", - "//ui/resources:ui_test_pak", - "//url", - ] + if (is_mac) { + deps += [ "//ui/gfx:test_support" ] + } - if (enable_notifications && !is_android) { + if (toolkit_views && !is_mac) { sources += [ - "cocoa/notification_controller_unittest.mm", - "cocoa/popup_collection_unittest.mm", - "cocoa/popup_controller_unittest.mm", - "cocoa/settings_controller_unittest.mm", - "cocoa/status_item_view_unittest.mm", - "cocoa/tray_controller_unittest.mm", - "cocoa/tray_view_controller_unittest.mm", - "message_center_impl_unittest.cc", - "message_center_tray_unittest.cc", - "notification_delegate_unittest.cc", - "notification_list_unittest.cc", + "views/bounded_label_unittest.cc", + "views/message_center_view_unittest.cc", + "views/message_popup_collection_unittest.cc", + "views/notification_view_unittest.cc", + "views/notifier_settings_view_unittest.cc", ] - - if (is_mac) { - deps += [ "//ui/gfx:test_support" ] - } - - if (toolkit_views && !is_mac) { - sources += [ - "views/bounded_label_unittest.cc", - "views/message_center_view_unittest.cc", - "views/message_popup_collection_unittest.cc", - "views/notification_view_unittest.cc", - "views/notifier_settings_view_unittest.cc", - ] - deps += [ - # Compositor is needed by message_center_view_unittest.cc and for the - # fonts used by bounded_label_unittest.cc. - "//ui/compositor", - "//ui/views", - "//ui/views:test_support", - ] - } - } # enable_notifications && !is_android - } + deps += [ + # Compositor is needed by message_center_view_unittest.cc and for the + # fonts used by bounded_label_unittest.cc. + "//ui/compositor", + "//ui/views", + "//ui/views:test_support", + ] + } + } # enable_notifications && !is_android }
diff --git a/ui/message_center/views/bounded_label.cc b/ui/message_center/views/bounded_label.cc index a634a29d..ca9f0f9 100644 --- a/ui/message_center/views/bounded_label.cc +++ b/ui/message_center/views/bounded_label.cc
@@ -199,11 +199,7 @@ if (SkColorGetA(background_color()) != 0xFF) flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING; - const base::i18n::TextDirection direction = - base::i18n::GetFirstStrongCharacterDirection(text()); - if (direction == base::i18n::RIGHT_TO_LEFT) - return flags | gfx::Canvas::FORCE_RTL_DIRECTIONALITY; - return flags | gfx::Canvas::FORCE_LTR_DIRECTIONALITY; + return flags | gfx::Canvas::TEXT_ALIGN_TO_HEAD; } void InnerBoundedLabel::ClearCaches() {
diff --git a/ui/oobe/BUILD.gn b/ui/oobe/BUILD.gn new file mode 100644 index 0000000..fb6def9 --- /dev/null +++ b/ui/oobe/BUILD.gn
@@ -0,0 +1,48 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//components/webui_generator/generator/wug.gni") +import("//tools/grit/grit_rule.gni") + +wug("oobe_wug_generated") { + source = "declarations/oobe.json" +} + +grit("resources") { + source = "oobe_resources.grd" + outputs = [ + "grit/oobe_resources.h", + "grit/oobe_resources_map.cc", + "grit/oobe_resources_map.h", + "oobe_resources.pak", + "oobe_resources.rc", + ] +} + +group("oobe_gen") { + public_deps = [ + ":oobe_wug_generated", + "//components/webui_generator", + ] +} + +component("oobe") { + sources = [ + "oobe_export.h", + "oobe_md_ui.cc", + "oobe_md_ui.h", + ] + + defines = [ "OOBE_IMPLEMENTATION" ] + + deps = [ + "//base", + ":resources", + ":oobe_gen", + ] + + public_deps = [ + "//content/public/browser", + ] +}
diff --git a/ui/oobe/DEPS b/ui/oobe/DEPS new file mode 100644 index 0000000..7e735e1 --- /dev/null +++ b/ui/oobe/DEPS
@@ -0,0 +1,6 @@ +include_rules = [ + "+base/strings", + "+content/public/browser", + "+grit/oobe_resources.h", + "+grit/oobe_resources_map.h", +]
diff --git a/ui/oobe/OWNERS b/ui/oobe/OWNERS new file mode 100644 index 0000000..11c1de2 --- /dev/null +++ b/ui/oobe/OWNERS
@@ -0,0 +1,5 @@ +antrim@chromium.org +dpolukhin@chromium.org +dzhioev@chromium.org +merkulova@chromium.org +nkostylev@chromium.org
diff --git a/ui/oobe/declarations/oobe.json b/ui/oobe/declarations/oobe.json new file mode 100644 index 0000000..9163e9e --- /dev/null +++ b/ui/oobe/declarations/oobe.json
@@ -0,0 +1,7 @@ +{ + "comment": "Root OOBE element.", + "type": "oobe", + "events": [ + { "name": "button_clicked" } + ] +}
diff --git a/ui/oobe/oobe.gyp b/ui/oobe/oobe.gyp new file mode 100644 index 0000000..8b98764 --- /dev/null +++ b/ui/oobe/oobe.gyp
@@ -0,0 +1,64 @@ +# Copyright (c) 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'targets': [ + { + # GN version: //ui/oobe:resources + 'target_name': 'oobe_resources', + 'type': 'none', + 'variables': { + 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/ui/oobe', + }, + 'actions': [ + { + 'action_name': 'oobe_resources', + 'variables': { + 'grit_grd_file': 'oobe_resources.grd', + }, + 'includes': [ '../../build/grit_action.gypi' ], + }, + ], + 'includes': [ '../../build/grit_target.gypi' ], + 'copies': [ + { + 'destination': '<(PRODUCT_DIR)', + 'files': [ + '<(grit_out_dir)/oobe_resources.pak', + ], + }, + ], + }, + { + 'variables': { + 'declaration_file': 'declarations/oobe.json', + }, + 'includes': ['../../components/webui_generator/generator/wug.gypi'], + }, + { + # GN version: //ui/oobe + 'target_name': 'oobe', + 'type': '<(component)', + 'defines': [ + 'OOBE_IMPLEMENTATION' + ], + 'dependencies': [ + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/content/content.gyp:content_browser', + '<(DEPTH)/components/components.gyp:webui_generator', + 'oobe_resources', + 'oobe_wug_generated', + ], + 'sources': [ + '<(SHARED_INTERMEDIATE_DIR)/ui/oobe/grit/oobe_resources_map.cc', + 'oobe_md_ui.cc', + 'oobe_md_ui.h', + 'oobe_export.h', + ], + 'export_dependent_settings': [ + '<(DEPTH)/content/content.gyp:content_browser', + ] + }, + ] +}
diff --git a/ui/oobe/oobe_export.h b/ui/oobe/oobe_export.h new file mode 100644 index 0000000..3024b9d1 --- /dev/null +++ b/ui/oobe/oobe_export.h
@@ -0,0 +1,32 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_OOBE_OOBE_EXPORT_H_ +#define UI_OOBE_OOBE_EXPORT_H_ + +// Defines OOBE_UI_EXPORT so that functionality implemented by the +// keyboard module can be exported to consumers. + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(OOBE_IMPLEMENTATION) +#define OOBE_EXPORT __declspec(dllexport) +#else +#define OOBE_EXPORT __declspec(dllimport) +#endif // defined(OOBE_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(OOBE_IMPLEMENTATION) +#define OOBE_EXPORT __attribute__((visibility("default"))) +#else +#define OOBE_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) +#define OOBE_EXPORT +#endif + +#endif // UI_OOBE_OOBE_EXPORT_H_
diff --git a/ui/oobe/oobe_md_ui.cc b/ui/oobe/oobe_md_ui.cc new file mode 100644 index 0000000..07e91b5 --- /dev/null +++ b/ui/oobe/oobe_md_ui.cc
@@ -0,0 +1,45 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/string_util.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_ui_data_source.h" +#include "grit/oobe_resources.h" +#include "grit/oobe_resources_map.h" +#include "ui/oobe/declarations/oobe_web_ui_view.h" +#include "ui/oobe/oobe_md_ui.h" + +namespace { + +void SetUpDataSource(content::WebUIDataSource* source) { + source->SetJsonPath("strings.js"); + source->AddResourcePath("", IDR_OOBE_UI_HTML); + + // Add all resources defined in "oobe_resources.grd" file at once. + const char prefix[] = "resources/"; + const size_t prefix_length = arraysize(prefix) - 1; + for (size_t i = 0; i < kOobeResourcesSize; ++i) { + std::string name = kOobeResources[i].name; + DCHECK(StartsWithASCII(name, prefix, true)); + source->AddResourcePath(name.substr(prefix_length), + kOobeResources[i].value); + } +} + +} // namespace + +OobeMdUI::OobeMdUI(content::WebUI* web_ui, const std::string& host) + : WebUIController(web_ui) { + content::WebUIDataSource* source = content::WebUIDataSource::Create(host); + SetUpDataSource(source); + + view_.reset(new gen::OobeWebUIView(web_ui)); + view_->Init(); + view_->SetUpDataSource(source); + + content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(), + source); +} + +OobeMdUI::~OobeMdUI() {}
diff --git a/ui/oobe/oobe_md_ui.h b/ui/oobe/oobe_md_ui.h new file mode 100644 index 0000000..7ff3aefb --- /dev/null +++ b/ui/oobe/oobe_md_ui.h
@@ -0,0 +1,32 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_OOBE_OOBE_MD_UI_H_ +#define UI_OOBE_OOBE_MD_UI_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "content/public/browser/web_ui_controller.h" +#include "ui/oobe/oobe_export.h" + +namespace content { +class WebUI; +} + +namespace gen { +class OobeWebUIView; +} + +class OOBE_EXPORT OobeMdUI : public content::WebUIController { + public: + OobeMdUI(content::WebUI* web_ui, const std::string& host); + ~OobeMdUI() override; + + private: + scoped_ptr<gen::OobeWebUIView> view_; + + DISALLOW_COPY_AND_ASSIGN(OobeMdUI); +}; + +#endif // UI_OOBE_OOBE_MD_UI_H_
diff --git a/ui/oobe/oobe_resources.grd b/ui/oobe/oobe_resources.grd new file mode 100644 index 0000000..590c618 --- /dev/null +++ b/ui/oobe/oobe_resources.grd
@@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<grit latest_public_release="0" current_release="1"> + <outputs> + <output filename="grit/oobe_resources.h" type="rc_header"> + <emit emit_type='prepend'></emit> + </output> + <output filename="grit/oobe_resources_map.cc" type="resource_file_map_source" /> + <output filename="grit/oobe_resources_map.h" type="resource_map_header" /> + <output filename="oobe_resources.pak" type="data_package" /> + <output filename="oobe_resources.rc" type="rc_all" /> + </outputs> + <release seq="1"> + <includes> + <if expr="chromeos"> + <include name="IDR_OOBE_UI_HTML" file="resources/oobe_ui.html" type="chrome_html" /> + <include name="IDR_OOBE_UI_JS" file="resources/oobe_ui.js" type="chrome_html" /> + <include name="IDR_OOBE_ELEMENT_HTML" file="resources/oobe-element.html" type="chrome_html" /> + <include name="IDR_OOBE_ELEMENT_JS" file="resources/oobe-element.js" type="chrome_html" /> + </if> + </includes> + </release> +</grit>
diff --git a/ui/oobe/resources/oobe-element.html b/ui/oobe/resources/oobe-element.html new file mode 100644 index 0000000..f6c342a --- /dev/null +++ b/ui/oobe/resources/oobe-element.html
@@ -0,0 +1,25 @@ +<!-- Copyright 2015 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<link rel="import" href="chrome://resources/polymer/paper-button/paper-button.html"> +<link rel="import" href="ui/oobe/declarations/oobe-view.html"> + +<polymer-element name="oobe-element" extends="oobe-view"> + <template> + <style> + paper-button { + background-color: #00bcd4; + color: #fff; + box-shadow: 0px 3px 2px rgba(0, 0, 0, 0.2); + text-transform: none; + font-weight: bold; + } + </style> + <paper-button on-tap="{{fireEvent}}" event="buttonClicked"> + Old OOBE + </paper-button> + </template> +</polymer-element> + +<script src="oobe-element.js"></script>
diff --git a/ui/oobe/resources/oobe-element.js b/ui/oobe/resources/oobe-element.js new file mode 100644 index 0000000..aeadaf3 --- /dev/null +++ b/ui/oobe/resources/oobe-element.js
@@ -0,0 +1,12 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +Polymer('oobe-element', { + initialize: function() { + this.contextChanged(); + }, + + contextChanged: function(changedKeys) { + } +});
diff --git a/ui/oobe/resources/oobe_ui.html b/ui/oobe/resources/oobe_ui.html new file mode 100644 index 0000000..7dfc91c4 --- /dev/null +++ b/ui/oobe/resources/oobe_ui.html
@@ -0,0 +1,11 @@ +<!doctype html> +<html> +<head> + <script src="chrome://resources/js/load_time_data.js"></script> + <script src="chrome://oobe-md/strings.js"></script> + <link rel="import" href="oobe-element.html"> +</head> +<body> + <oobe-element wugid="WUG_ROOT"></oobe-element> +</body> +</html>
diff --git a/tools/telemetry/telemetry/core/heap/__init__.py b/ui/oobe/resources/oobe_ui.js similarity index 100% rename from tools/telemetry/telemetry/core/heap/__init__.py rename to ui/oobe/resources/oobe_ui.js
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn index 6868897..f3618a1 100644 --- a/ui/ozone/BUILD.gn +++ b/ui/ozone/BUILD.gn
@@ -94,8 +94,8 @@ "platform_selection.h", "public/input_controller.cc", "public/input_controller.h", - "public/ozone_gpu_thread_helper.cc", - "public/ozone_gpu_thread_helper.h", + "public/ozone_gpu_test_helper.cc", + "public/ozone_gpu_test_helper.h", "public/ozone_platform.cc", "public/ozone_platform.h", "public/ozone_switches.cc",
diff --git a/ui/ozone/demo/gl_renderer.cc b/ui/ozone/demo/gl_renderer.cc index 8e0fcfe..191d343c 100644 --- a/ui/ozone/demo/gl_renderer.cc +++ b/ui/ozone/demo/gl_renderer.cc
@@ -18,7 +18,7 @@ } bool GlRenderer::Initialize() { - surface_ = gfx::GLSurface::CreateViewGLSurface(widget_); + surface_ = CreateSurface(); if (!surface_.get()) { LOG(ERROR) << "Failed to create GL surface"; return false; @@ -54,4 +54,8 @@ LOG(FATAL) << "Failed to swap buffers"; } +scoped_refptr<gfx::GLSurface> GlRenderer::CreateSurface() { + return gfx::GLSurface::CreateViewGLSurface(widget_); +} + } // namespace ui
diff --git a/ui/ozone/demo/gl_renderer.h b/ui/ozone/demo/gl_renderer.h index 727801ce..c7cf520 100644 --- a/ui/ozone/demo/gl_renderer.h +++ b/ui/ozone/demo/gl_renderer.h
@@ -26,6 +26,8 @@ void RenderFrame() override; protected: + virtual scoped_refptr<gfx::GLSurface> CreateSurface(); + scoped_refptr<gfx::GLSurface> surface_; scoped_refptr<gfx::GLContext> context_;
diff --git a/ui/ozone/demo/surfaceless_gl_renderer.cc b/ui/ozone/demo/surfaceless_gl_renderer.cc index 791615d..296700d 100644 --- a/ui/ozone/demo/surfaceless_gl_renderer.cc +++ b/ui/ozone/demo/surfaceless_gl_renderer.cc
@@ -133,4 +133,8 @@ back_buffer_ ^= 1; } +scoped_refptr<gfx::GLSurface> SurfacelessGlRenderer::CreateSurface() { + return gfx::GLSurface::CreateSurfacelessViewGLSurface(widget_); +} + } // namespace ui
diff --git a/ui/ozone/demo/surfaceless_gl_renderer.h b/ui/ozone/demo/surfaceless_gl_renderer.h index 9356ab1..b6bc877 100644 --- a/ui/ozone/demo/surfaceless_gl_renderer.h +++ b/ui/ozone/demo/surfaceless_gl_renderer.h
@@ -32,6 +32,9 @@ // Called by swap buffers when the actual swap finished. void OnSwapBuffersAck(); + // GlRenderer: + scoped_refptr<gfx::GLSurface> CreateSurface() override; + class BufferWrapper { public: BufferWrapper();
diff --git a/ui/ozone/platform/dri/BUILD.gn b/ui/ozone/platform/dri/BUILD.gn index d796a60..03112a32 100644 --- a/ui/ozone/platform/dri/BUILD.gn +++ b/ui/ozone/platform/dri/BUILD.gn
@@ -45,15 +45,14 @@ "dri_vsync_provider.h", "dri_window.cc", "dri_window.h", + "dri_window_delegate.cc", "dri_window_delegate.h", - "dri_window_delegate_impl.cc", - "dri_window_delegate_impl.h", "dri_window_delegate_manager.cc", "dri_window_delegate_manager.h", "dri_window_manager.cc", "dri_window_manager.h", - "dri_wrapper.cc", - "dri_wrapper.h", + "drm_device.cc", + "drm_device.h", "drm_device_generator.cc", "drm_device_generator.h", "drm_device_manager.cc", @@ -120,7 +119,7 @@ testonly = true sources = [ "dri_surface_unittest.cc", - "dri_window_delegate_impl_unittest.cc", + "dri_window_delegate_unittest.cc", "hardware_display_controller_unittest.cc", "hardware_display_plane_manager_unittest.cc", "screen_manager_unittest.cc", @@ -149,14 +148,14 @@ "gbm_buffer.h", "gbm_buffer_base.cc", "gbm_buffer_base.h", + "gbm_device.cc", + "gbm_device.h", "gbm_surface.cc", "gbm_surface.h", "gbm_surface_factory.cc", "gbm_surface_factory.h", "gbm_surfaceless.cc", "gbm_surfaceless.h", - "gbm_wrapper.cc", - "gbm_wrapper.h", "ozone_platform_gbm.cc", "ozone_platform_gbm.h", ]
diff --git a/ui/ozone/platform/dri/crtc_controller.cc b/ui/ozone/platform/dri/crtc_controller.cc index b5dcb14..d9e86f23 100644 --- a/ui/ozone/platform/dri/crtc_controller.cc +++ b/ui/ozone/platform/dri/crtc_controller.cc
@@ -6,13 +6,13 @@ #include "base/logging.h" #include "base/time/time.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/platform/dri/page_flip_observer.h" #include "ui/ozone/platform/dri/scanout_buffer.h" namespace ui { -CrtcController::CrtcController(const scoped_refptr<DriWrapper>& drm, +CrtcController::CrtcController(const scoped_refptr<DrmDevice>& drm, uint32_t crtc, uint32_t connector) : drm_(drm),
diff --git a/ui/ozone/platform/dri/crtc_controller.h b/ui/ozone/platform/dri/crtc_controller.h index 01dc9a6..827515ce 100644 --- a/ui/ozone/platform/dri/crtc_controller.h +++ b/ui/ozone/platform/dri/crtc_controller.h
@@ -18,7 +18,7 @@ namespace ui { -class DriWrapper; +class DrmDevice; class PageFlipObserver; // Wrapper around a CRTC. @@ -29,14 +29,14 @@ class OZONE_EXPORT CrtcController : public base::SupportsWeakPtr<CrtcController> { public: - CrtcController(const scoped_refptr<DriWrapper>& drm, + CrtcController(const scoped_refptr<DrmDevice>& drm, uint32_t crtc, uint32_t connector); ~CrtcController(); uint32_t crtc() const { return crtc_; } uint32_t connector() const { return connector_; } - const scoped_refptr<DriWrapper>& drm() const { return drm_; } + const scoped_refptr<DrmDevice>& drm() const { return drm_; } bool is_disabled() const { return is_disabled_; } bool page_flip_pending() const { return page_flip_pending_; } uint64_t time_of_last_flip() const { return time_of_last_flip_; } @@ -75,7 +75,7 @@ void RemoveObserver(PageFlipObserver* observer); private: - scoped_refptr<DriWrapper> drm_; + scoped_refptr<DrmDevice> drm_; HardwareDisplayPlaneManager* overlay_plane_manager_; // Not owned.
diff --git a/ui/ozone/platform/dri/display_snapshot_dri.cc b/ui/ozone/platform/dri/display_snapshot_dri.cc index 1ad9fb2c..164d5ee 100644 --- a/ui/ozone/platform/dri/display_snapshot_dri.cc +++ b/ui/ozone/platform/dri/display_snapshot_dri.cc
@@ -14,7 +14,7 @@ #include "ui/display/util/edid_parser.h" #include "ui/ozone/platform/dri/display_mode_dri.h" #include "ui/ozone/platform/dri/dri_util.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" #if !defined(DRM_MODE_CONNECTOR_DSI) #define DRM_MODE_CONNECTOR_DSI 16 @@ -46,7 +46,7 @@ } } -bool IsAspectPreserving(DriWrapper* drm, drmModeConnector* connector) { +bool IsAspectPreserving(DrmDevice* drm, drmModeConnector* connector) { ScopedDrmPropertyPtr property(drm->GetProperty(connector, "scaling mode")); if (!property) return false; @@ -67,7 +67,7 @@ } // namespace -DisplaySnapshotDri::DisplaySnapshotDri(const scoped_refptr<DriWrapper>& drm, +DisplaySnapshotDri::DisplaySnapshotDri(const scoped_refptr<DrmDevice>& drm, drmModeConnector* connector, drmModeCrtc* crtc, uint32_t index)
diff --git a/ui/ozone/platform/dri/display_snapshot_dri.h b/ui/ozone/platform/dri/display_snapshot_dri.h index 0a7052b..2ba799034 100644 --- a/ui/ozone/platform/dri/display_snapshot_dri.h +++ b/ui/ozone/platform/dri/display_snapshot_dri.h
@@ -11,17 +11,17 @@ namespace ui { -class DriWrapper; +class DrmDevice; class DisplaySnapshotDri : public DisplaySnapshot { public: - DisplaySnapshotDri(const scoped_refptr<DriWrapper>& drm, + DisplaySnapshotDri(const scoped_refptr<DrmDevice>& drm, drmModeConnector* connector, drmModeCrtc* crtc, uint32_t index); ~DisplaySnapshotDri() override; - scoped_refptr<DriWrapper> drm() const { return drm_; } + scoped_refptr<DrmDevice> drm() const { return drm_; } // Native properties of a display used by the DRI implementation in // configuring this display. uint32_t connector() const { return connector_; } @@ -32,7 +32,7 @@ std::string ToString() const override; private: - scoped_refptr<DriWrapper> drm_; + scoped_refptr<DrmDevice> drm_; uint32_t connector_; uint32_t crtc_; ScopedDrmPropertyPtr dpms_property_;
diff --git a/ui/ozone/platform/dri/dri.gypi b/ui/ozone/platform/dri/dri.gypi index 77795af..63faee7f 100644 --- a/ui/ozone/platform/dri/dri.gypi +++ b/ui/ozone/platform/dri/dri.gypi
@@ -67,15 +67,14 @@ 'dri_vsync_provider.h', 'dri_window.cc', 'dri_window.h', + 'dri_window_delegate.cc', 'dri_window_delegate.h', - 'dri_window_delegate_impl.cc', - 'dri_window_delegate_impl.h', 'dri_window_delegate_manager.cc', 'dri_window_delegate_manager.h', 'dri_window_manager.cc', 'dri_window_manager.h', - 'dri_wrapper.cc', - 'dri_wrapper.h', + 'drm_device.cc', + 'drm_device.h', 'drm_device_generator.cc', 'drm_device_generator.h', 'drm_device_manager.cc', @@ -120,12 +119,12 @@ 'direct_dependent_settings': { 'sources': [ 'dri_surface_unittest.cc', - 'dri_window_delegate_impl_unittest.cc', + 'dri_window_delegate_unittest.cc', 'hardware_display_controller_unittest.cc', 'hardware_display_plane_manager_unittest.cc', 'screen_manager_unittest.cc', - 'test/mock_dri_wrapper.cc', - 'test/mock_dri_wrapper.h', + 'test/mock_drm_device.cc', + 'test/mock_drm_device.h', ], }, },
diff --git a/ui/ozone/platform/dri/dri_buffer.cc b/ui/ozone/platform/dri/dri_buffer.cc index 9fa284f..bd2c2c2 100644 --- a/ui/ozone/platform/dri/dri_buffer.cc +++ b/ui/ozone/platform/dri/dri_buffer.cc
@@ -5,7 +5,7 @@ #include "ui/ozone/platform/dri/dri_buffer.h" #include "base/logging.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" namespace ui { @@ -34,8 +34,8 @@ } // namespace -DriBuffer::DriBuffer(const scoped_refptr<DriWrapper>& dri) - : dri_(dri), handle_(0), framebuffer_(0) { +DriBuffer::DriBuffer(const scoped_refptr<DrmDevice>& drm) + : drm_(drm), handle_(0), framebuffer_(0) { } DriBuffer::~DriBuffer() { @@ -43,26 +43,26 @@ return; if (framebuffer_) - dri_->RemoveFramebuffer(framebuffer_); + drm_->RemoveFramebuffer(framebuffer_); SkImageInfo info; void* pixels = const_cast<void*>(surface_->peekPixels(&info, NULL)); if (!pixels) return; - dri_->DestroyDumbBuffer(info, handle_, stride_, pixels); + drm_->DestroyDumbBuffer(info, handle_, stride_, pixels); } bool DriBuffer::Initialize(const SkImageInfo& info, bool should_register_framebuffer) { void* pixels = NULL; - if (!dri_->CreateDumbBuffer(info, &handle_, &stride_, &pixels)) { + if (!drm_->CreateDumbBuffer(info, &handle_, &stride_, &pixels)) { VLOG(2) << "Cannot create drm dumb buffer"; return false; } if (should_register_framebuffer && - !dri_->AddFramebuffer( + !drm_->AddFramebuffer( info.width(), info.height(), GetColorDepth(info.colorType()), info.bytesPerPixel() << 3, stride_, handle_, &framebuffer_)) { VLOG(2) << "Failed to register framebuffer: " << strerror(errno); @@ -100,7 +100,7 @@ DriBufferGenerator::~DriBufferGenerator() {} scoped_refptr<ScanoutBuffer> DriBufferGenerator::Create( - const scoped_refptr<DriWrapper>& drm, + const scoped_refptr<DrmDevice>& drm, const gfx::Size& size) { scoped_refptr<DriBuffer> buffer(new DriBuffer(drm)); SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
diff --git a/ui/ozone/platform/dri/dri_buffer.h b/ui/ozone/platform/dri/dri_buffer.h index 7bcca1b..0b9f8e68 100644 --- a/ui/ozone/platform/dri/dri_buffer.h +++ b/ui/ozone/platform/dri/dri_buffer.h
@@ -13,14 +13,14 @@ namespace ui { -class DriWrapper; +class DrmDevice; // Wrapper for a DRM allocated buffer. Keeps track of the native properties of // the buffer and wraps the pixel memory into a SkSurface which can be used to // draw into using Skia. class OZONE_EXPORT DriBuffer : public ScanoutBuffer { public: - DriBuffer(const scoped_refptr<DriWrapper>& dri); + DriBuffer(const scoped_refptr<DrmDevice>& drm); // Allocates the backing pixels and wraps them in |surface_|. |info| is used // to describe the buffer characteristics (size, color format). @@ -38,7 +38,7 @@ protected: ~DriBuffer() override; - scoped_refptr<DriWrapper> dri_; + scoped_refptr<DrmDevice> drm_; // Wrapper around the native pixel memory. skia::RefPtr<SkSurface> surface_; @@ -62,7 +62,7 @@ ~DriBufferGenerator() override; // ScanoutBufferGenerator: - scoped_refptr<ScanoutBuffer> Create(const scoped_refptr<DriWrapper>& drm, + scoped_refptr<ScanoutBuffer> Create(const scoped_refptr<DrmDevice>& drm, const gfx::Size& size) override; private:
diff --git a/ui/ozone/platform/dri/dri_console_buffer.cc b/ui/ozone/platform/dri/dri_console_buffer.cc index 204590f..91aba48 100644 --- a/ui/ozone/platform/dri/dri_console_buffer.cc +++ b/ui/ozone/platform/dri/dri_console_buffer.cc
@@ -9,14 +9,14 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "ui/ozone/platform/dri/dri_util.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/platform/dri/scoped_drm_types.h" namespace ui { -DriConsoleBuffer::DriConsoleBuffer(const scoped_refptr<DriWrapper>& dri, +DriConsoleBuffer::DriConsoleBuffer(const scoped_refptr<DrmDevice>& drm, uint32_t framebuffer) - : dri_(dri), + : drm_(drm), handle_(0), framebuffer_(framebuffer), mmap_base_(NULL), @@ -30,7 +30,7 @@ } bool DriConsoleBuffer::Initialize() { - ScopedDrmFramebufferPtr fb(dri_->GetFramebuffer(framebuffer_)); + ScopedDrmFramebufferPtr fb(drm_->GetFramebuffer(framebuffer_)); if (!fb) return false; @@ -41,7 +41,7 @@ mmap_size_ = info.getSafeSize(stride_); - if (!MapDumbBuffer(dri_->get_fd(), fb->handle, mmap_size_, &mmap_base_)) { + if (!MapDumbBuffer(drm_->get_fd(), fb->handle, mmap_size_, &mmap_base_)) { mmap_base_ = NULL; return false; }
diff --git a/ui/ozone/platform/dri/dri_console_buffer.h b/ui/ozone/platform/dri/dri_console_buffer.h index 6a9c3cca..e174955 100644 --- a/ui/ozone/platform/dri/dri_console_buffer.h +++ b/ui/ozone/platform/dri/dri_console_buffer.h
@@ -14,7 +14,7 @@ namespace ui { -class DriWrapper; +class DrmDevice; // Wrapper for the console buffer. This is the buffer that is allocated by // default by the system and is used when no application is controlling the @@ -22,7 +22,7 @@ // memory into a SkSurface which can be used to draw into using Skia. class DriConsoleBuffer { public: - DriConsoleBuffer(const scoped_refptr<DriWrapper>& dri, uint32_t framebuffer); + DriConsoleBuffer(const scoped_refptr<DrmDevice>& drm, uint32_t framebuffer); ~DriConsoleBuffer(); SkCanvas* canvas() { return surface_->getCanvas(); } @@ -34,7 +34,7 @@ bool Initialize(); protected: - scoped_refptr<DriWrapper> dri_; + scoped_refptr<DrmDevice> drm_; // Wrapper around the native pixel memory. skia::RefPtr<SkSurface> surface_;
diff --git a/ui/ozone/platform/dri/dri_gpu_platform_support.cc b/ui/ozone/platform/dri/dri_gpu_platform_support.cc index d4116bf..a67d42a 100644 --- a/ui/ozone/platform/dri/dri_gpu_platform_support.cc +++ b/ui/ozone/platform/dri/dri_gpu_platform_support.cc
@@ -9,9 +9,9 @@ #include "ipc/ipc_message_macros.h" #include "ui/ozone/common/gpu/ozone_gpu_message_params.h" #include "ui/ozone/common/gpu/ozone_gpu_messages.h" -#include "ui/ozone/platform/dri/dri_window_delegate_impl.h" +#include "ui/ozone/platform/dri/dri_window_delegate.h" #include "ui/ozone/platform/dri/dri_window_delegate_manager.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/platform/dri/native_display_delegate_dri.h" namespace ui { @@ -229,7 +229,7 @@ void DriGpuPlatformSupport::OnCreateWindowDelegate( gfx::AcceleratedWidget widget) { scoped_ptr<DriWindowDelegate> delegate( - new DriWindowDelegateImpl(widget, drm_device_manager_, screen_manager_)); + new DriWindowDelegate(widget, drm_device_manager_, screen_manager_)); delegate->Initialize(); window_manager_->AddWindowDelegate(widget, delegate.Pass()); }
diff --git a/ui/ozone/platform/dri/dri_surface.cc b/ui/ozone/platform/dri/dri_surface.cc index 89107f2b..2bc85a3f 100644 --- a/ui/ozone/platform/dri/dri_surface.cc +++ b/ui/ozone/platform/dri/dri_surface.cc
@@ -13,17 +13,17 @@ #include "ui/gfx/skia_util.h" #include "ui/ozone/platform/dri/dri_buffer.h" #include "ui/ozone/platform/dri/dri_vsync_provider.h" -#include "ui/ozone/platform/dri/dri_window_delegate_impl.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/dri_window_delegate.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/platform/dri/hardware_display_controller.h" namespace ui { namespace { -scoped_refptr<DriBuffer> AllocateBuffer(const scoped_refptr<DriWrapper>& dri, +scoped_refptr<DriBuffer> AllocateBuffer(const scoped_refptr<DrmDevice>& drm, const gfx::Size& size) { - scoped_refptr<DriBuffer> buffer(new DriBuffer(dri)); + scoped_refptr<DriBuffer> buffer(new DriBuffer(drm)); SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height()); bool initialized = @@ -58,7 +58,7 @@ // For the display buffers use the mode size since a |viewport_size| smaller // than the display size will not scanout. for (size_t i = 0; i < arraysize(buffers_); ++i) - buffers_[i] = AllocateBuffer(controller->GetAllocationDriWrapper(), + buffers_[i] = AllocateBuffer(controller->GetAllocationDrmDevice(), controller->GetModeSize()); }
diff --git a/ui/ozone/platform/dri/dri_surface_factory.cc b/ui/ozone/platform/dri/dri_surface_factory.cc index c3713702..a721daf4 100644 --- a/ui/ozone/platform/dri/dri_surface_factory.cc +++ b/ui/ozone/platform/dri/dri_surface_factory.cc
@@ -9,7 +9,7 @@ #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/dri/dri_surface.h" #include "ui/ozone/platform/dri/dri_util.h" -#include "ui/ozone/platform/dri/dri_window_delegate_impl.h" +#include "ui/ozone/platform/dri/dri_window_delegate.h" #include "ui/ozone/platform/dri/dri_window_delegate_manager.h" #include "ui/ozone/platform/dri/hardware_display_controller.h" #include "ui/ozone/public/surface_ozone_canvas.h"
diff --git a/ui/ozone/platform/dri/dri_surface_unittest.cc b/ui/ozone/platform/dri/dri_surface_unittest.cc index 53d155a..7a5b8c5 100644 --- a/ui/ozone/platform/dri/dri_surface_unittest.cc +++ b/ui/ozone/platform/dri/dri_surface_unittest.cc
@@ -11,8 +11,10 @@ #include "ui/ozone/platform/dri/dri_buffer.h" #include "ui/ozone/platform/dri/dri_surface.h" #include "ui/ozone/platform/dri/dri_window_delegate.h" +#include "ui/ozone/platform/dri/drm_device_manager.h" #include "ui/ozone/platform/dri/hardware_display_controller.h" -#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h" +#include "ui/ozone/platform/dri/screen_manager.h" +#include "ui/ozone/platform/dri/test/mock_drm_device.h" namespace { @@ -20,43 +22,11 @@ const drmModeModeInfo kDefaultMode = {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}}; +const gfx::AcceleratedWidget kDefaultWidgetHandle = 1; const uint32_t kDefaultCrtc = 1; const uint32_t kDefaultConnector = 2; const size_t kPlanesPerCrtc = 1; - -class MockDriWindowDelegate : public ui::DriWindowDelegate { - public: - MockDriWindowDelegate(ui::DriWrapper* drm) { - controller_.reset(new ui::HardwareDisplayController(make_scoped_ptr( - new ui::CrtcController(drm, kDefaultCrtc, kDefaultConnector)))); - scoped_refptr<ui::DriBuffer> buffer(new ui::DriBuffer(drm)); - SkImageInfo info = SkImageInfo::MakeN32Premul(kDefaultMode.hdisplay, - kDefaultMode.vdisplay); - EXPECT_TRUE(buffer->Initialize(info, true)); - EXPECT_TRUE(controller_->Modeset(ui::OverlayPlane(buffer), kDefaultMode)); - } - ~MockDriWindowDelegate() override {} - - // DriWindowDelegate: - void Initialize() override {} - void Shutdown() override {} - gfx::AcceleratedWidget GetAcceleratedWidget() override { return 1; } - ui::HardwareDisplayController* GetController() override { - return controller_.get(); - } - void OnBoundsChanged(const gfx::Rect& bounds) override {} - void SetCursor(const std::vector<SkBitmap>& bitmaps, - const gfx::Point& location, - int frame_delay_ms) override {} - void SetCursorWithoutAnimations(const std::vector<SkBitmap>& bitmaps, - const gfx::Point& location) override {} - void MoveCursor(const gfx::Point& location) override {} - - private: - scoped_ptr<ui::HardwareDisplayController> controller_; - - DISALLOW_COPY_AND_ASSIGN(MockDriWindowDelegate); -}; +const uint32_t kDefaultCursorSize = 64; } // namespace @@ -69,8 +39,11 @@ protected: scoped_ptr<base::MessageLoop> message_loop_; - scoped_refptr<ui::MockDriWrapper> drm_; - scoped_ptr<MockDriWindowDelegate> window_delegate_; + scoped_refptr<ui::MockDrmDevice> drm_; + scoped_ptr<ui::DriBufferGenerator> buffer_generator_; + scoped_ptr<ui::ScreenManager> screen_manager_; + scoped_ptr<ui::DrmDeviceManager> drm_device_manager_; + scoped_ptr<ui::DriWindowDelegate> window_delegate_; scoped_ptr<ui::DriSurface> surface_; private: @@ -81,8 +54,20 @@ message_loop_.reset(new base::MessageLoopForUI); std::vector<uint32_t> crtcs; crtcs.push_back(kDefaultCrtc); - drm_ = new ui::MockDriWrapper(true, crtcs, kPlanesPerCrtc); - window_delegate_.reset(new MockDriWindowDelegate(drm_.get())); + drm_ = new ui::MockDrmDevice(true, crtcs, kPlanesPerCrtc); + buffer_generator_.reset(new ui::DriBufferGenerator()); + screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get())); + screen_manager_->AddDisplayController(drm_, kDefaultCrtc, kDefaultConnector); + screen_manager_->ConfigureDisplayController( + drm_, kDefaultCrtc, kDefaultConnector, gfx::Point(), kDefaultMode); + + drm_device_manager_.reset(new ui::DrmDeviceManager(drm_)); + window_delegate_.reset(new ui::DriWindowDelegate( + kDefaultWidgetHandle, drm_device_manager_.get(), screen_manager_.get())); + window_delegate_->Initialize(); + window_delegate_->OnBoundsChanged( + gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay))); + surface_.reset(new ui::DriSurface(window_delegate_.get())); surface_->ResizeCanvas(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay)); @@ -90,7 +75,7 @@ void DriSurfaceTest::TearDown() { surface_.reset(); - window_delegate_.reset(); + window_delegate_->Shutdown(); drm_ = nullptr; message_loop_.reset(); } @@ -113,12 +98,22 @@ gfx::Rect(0, 0, kDefaultMode.hdisplay / 2, kDefaultMode.vdisplay / 2)); SkBitmap image; - // Buffer 0 is the buffer used in SetUp for modesetting and buffer 1 is the - // frontbuffer. - // Buffer 2 is the backbuffer we just painted in, so we want to make sure its - // contents are correct. - image.setInfo(drm_->buffers()[2]->getCanvas()->imageInfo()); - EXPECT_TRUE(drm_->buffers()[2]->getCanvas()->readPixels(&image, 0, 0)); + std::vector<skia::RefPtr<SkSurface>> framebuffers; + for (const auto& buffer : drm_->buffers()) { + // Skip cursor buffers. + if (buffer->width() == kDefaultCursorSize && + buffer->height() == kDefaultCursorSize) + continue; + + framebuffers.push_back(buffer); + } + + // Buffer 0 is the modesetting buffer, buffer 1 is the frontbuffer and buffer + // 2 is the backbuffer. + EXPECT_EQ(3u, framebuffers.size()); + + image.setInfo(framebuffers[2]->getCanvas()->imageInfo()); + EXPECT_TRUE(framebuffers[2]->getCanvas()->readPixels(&image, 0, 0)); EXPECT_EQ(kDefaultMode.hdisplay, image.width()); EXPECT_EQ(kDefaultMode.vdisplay, image.height());
diff --git a/ui/ozone/platform/dri/dri_util.cc b/ui/ozone/platform/dri/dri_util.cc index 7849efdc..338c411 100644 --- a/ui/ozone/platform/dri/dri_util.cc +++ b/ui/ozone/platform/dri/dri_util.cc
@@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/strings/stringprintf.h" #include "ui/ozone/platform/dri/dri_util.h" #include <errno.h> @@ -13,7 +12,8 @@ #include <xf86drm.h> #include <xf86drmMode.h> -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "base/strings/stringprintf.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/platform/dri/screen_manager.h" namespace ui { @@ -142,7 +142,7 @@ return true; } -void ForceInitializationOfPrimaryDisplay(const scoped_refptr<DriWrapper>& drm, +void ForceInitializationOfPrimaryDisplay(const scoped_refptr<DrmDevice>& drm, ScreenManager* screen_manager) { LOG(WARNING) << "Forcing initialization of primary display."; ScopedVector<HardwareDisplayControllerInfo> displays =
diff --git a/ui/ozone/platform/dri/dri_util.h b/ui/ozone/platform/dri/dri_util.h index 742f512f..eb83939 100644 --- a/ui/ozone/platform/dri/dri_util.h +++ b/ui/ozone/platform/dri/dri_util.h
@@ -15,7 +15,7 @@ namespace ui { -class DriWrapper; +class DrmDevice; class ScreenManager; // Representation of the information required to initialize and configure a @@ -49,7 +49,7 @@ uint32_t size, void** pixels); -void ForceInitializationOfPrimaryDisplay(const scoped_refptr<DriWrapper>& drm, +void ForceInitializationOfPrimaryDisplay(const scoped_refptr<DrmDevice>& drm, ScreenManager* screen_manager); base::FilePath GetPrimaryDisplayCardPath();
diff --git a/ui/ozone/platform/dri/dri_window_delegate.cc b/ui/ozone/platform/dri/dri_window_delegate.cc new file mode 100644 index 0000000..ddc1e18 --- /dev/null +++ b/ui/ozone/platform/dri/dri_window_delegate.cc
@@ -0,0 +1,218 @@ +// 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/dri/dri_window_delegate.h" + +#include "base/trace_event/trace_event.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkDevice.h" +#include "third_party/skia/include/core/SkSurface.h" +#include "ui/ozone/platform/dri/dri_buffer.h" +#include "ui/ozone/platform/dri/drm_device.h" +#include "ui/ozone/platform/dri/drm_device_manager.h" +#include "ui/ozone/platform/dri/screen_manager.h" + +namespace ui { + +namespace { + +#ifndef DRM_CAP_CURSOR_WIDTH +#define DRM_CAP_CURSOR_WIDTH 0x8 +#endif + +#ifndef DRM_CAP_CURSOR_HEIGHT +#define DRM_CAP_CURSOR_HEIGHT 0x9 +#endif + +void UpdateCursorImage(DriBuffer* cursor, const SkBitmap& image) { + SkRect damage; + image.getBounds(&damage); + + // Clear to transparent in case |image| is smaller than the canvas. + SkCanvas* canvas = cursor->GetCanvas(); + canvas->clear(SK_ColorTRANSPARENT); + + SkRect clip; + clip.set(0, 0, canvas->getDeviceSize().width(), + canvas->getDeviceSize().height()); + canvas->clipRect(clip, SkRegion::kReplace_Op); + canvas->drawBitmapRectToRect(image, &damage, damage); +} + +} // namespace + +DriWindowDelegate::DriWindowDelegate(gfx::AcceleratedWidget widget, + DrmDeviceManager* device_manager, + ScreenManager* screen_manager) + : widget_(widget), + device_manager_(device_manager), + screen_manager_(screen_manager), + controller_(NULL), + cursor_frontbuffer_(0), + cursor_frame_(0), + cursor_frame_delay_ms_(0) { +} + +DriWindowDelegate::~DriWindowDelegate() { +} + +void DriWindowDelegate::Initialize() { + TRACE_EVENT1("dri", "DriWindowDelegate::Initialize", "widget", widget_); + + device_manager_->UpdateDrmDevice(widget_, nullptr); + screen_manager_->AddObserver(this); +} + +void DriWindowDelegate::Shutdown() { + TRACE_EVENT1("dri", "DriWindowDelegate::Shutdown", "widget", widget_); + screen_manager_->RemoveObserver(this); + device_manager_->RemoveDrmDevice(widget_); +} + +gfx::AcceleratedWidget DriWindowDelegate::GetAcceleratedWidget() { + return widget_; +} + +HardwareDisplayController* DriWindowDelegate::GetController() { + return controller_; +} + +void DriWindowDelegate::OnBoundsChanged(const gfx::Rect& bounds) { + TRACE_EVENT2("dri", "DriWindowDelegate::OnBoundsChanged", "widget", widget_, + "bounds", bounds.ToString()); + bounds_ = bounds; + controller_ = screen_manager_->GetDisplayController(bounds); + UpdateWidgetToDrmDeviceMapping(); + UpdateCursorBuffers(); +} + +void DriWindowDelegate::SetCursor(const std::vector<SkBitmap>& bitmaps, + const gfx::Point& location, + int frame_delay_ms) { + cursor_bitmaps_ = bitmaps; + cursor_location_ = location; + cursor_frame_ = 0; + cursor_frame_delay_ms_ = frame_delay_ms; + cursor_timer_.Stop(); + + if (cursor_frame_delay_ms_) + cursor_timer_.Start( + FROM_HERE, base::TimeDelta::FromMilliseconds(cursor_frame_delay_ms_), + this, &DriWindowDelegate::OnCursorAnimationTimeout); + + ResetCursor(false); +} + +void DriWindowDelegate::SetCursorWithoutAnimations( + const std::vector<SkBitmap>& bitmaps, + const gfx::Point& location) { + cursor_bitmaps_ = bitmaps; + cursor_location_ = location; + cursor_frame_ = 0; + cursor_frame_delay_ms_ = 0; + ResetCursor(false); +} + +void DriWindowDelegate::MoveCursor(const gfx::Point& location) { + cursor_location_ = location; + + if (controller_) + controller_->MoveCursor(location); +} + +void DriWindowDelegate::OnDisplayChanged( + HardwareDisplayController* controller) { + DCHECK(controller); + + // If we have a new controller we need to re-allocate the buffers. + bool should_allocate_cursor_buffers = controller_ != controller; + + gfx::Rect controller_bounds = + gfx::Rect(controller->origin(), controller->GetModeSize()); + if (controller_) { + if (controller_ != controller) + return; + + if (controller->IsDisabled() || bounds_ != controller_bounds) + controller_ = nullptr; + } else { + if (bounds_ == controller_bounds && !controller->IsDisabled()) + controller_ = controller; + } + + UpdateWidgetToDrmDeviceMapping(); + if (should_allocate_cursor_buffers) + UpdateCursorBuffers(); +} + +void DriWindowDelegate::OnDisplayRemoved( + HardwareDisplayController* controller) { + if (controller_ == controller) + controller_ = nullptr; +} + +void DriWindowDelegate::ResetCursor(bool bitmap_only) { + if (!controller_) + return; + + if (cursor_bitmaps_.size()) { + // Draw new cursor into backbuffer. + UpdateCursorImage(cursor_buffers_[cursor_frontbuffer_ ^ 1].get(), + cursor_bitmaps_[cursor_frame_]); + + // Reset location & buffer. + if (!bitmap_only) + controller_->MoveCursor(cursor_location_); + controller_->SetCursor(cursor_buffers_[cursor_frontbuffer_ ^ 1]); + cursor_frontbuffer_ ^= 1; + } else { + // No cursor set. + controller_->UnsetCursor(); + } +} + +void DriWindowDelegate::OnCursorAnimationTimeout() { + cursor_frame_++; + cursor_frame_ %= cursor_bitmaps_.size(); + + ResetCursor(true); +} + +void DriWindowDelegate::UpdateWidgetToDrmDeviceMapping() { + scoped_refptr<DrmDevice> drm = nullptr; + if (controller_) + drm = controller_->GetAllocationDrmDevice(); + + device_manager_->UpdateDrmDevice(widget_, drm); +} + +void DriWindowDelegate::UpdateCursorBuffers() { + if (!controller_) { + for (size_t i = 0; i < arraysize(cursor_buffers_); ++i) { + cursor_buffers_[i] = nullptr; + } + } else { + scoped_refptr<DrmDevice> drm = controller_->GetAllocationDrmDevice(); + + uint64_t cursor_width = 64; + uint64_t cursor_height = 64; + drm->GetCapability(DRM_CAP_CURSOR_WIDTH, &cursor_width); + drm->GetCapability(DRM_CAP_CURSOR_HEIGHT, &cursor_height); + + SkImageInfo info = SkImageInfo::MakeN32Premul(cursor_width, cursor_height); + for (size_t i = 0; i < arraysize(cursor_buffers_); ++i) { + cursor_buffers_[i] = new DriBuffer(drm); + // Don't register a framebuffer for cursors since they are special (they + // aren't modesetting buffers and drivers may fail to register them due to + // their small sizes). + if (!cursor_buffers_[i]->Initialize( + info, false /* should_register_framebuffer */)) { + LOG(FATAL) << "Failed to initialize cursor buffer"; + return; + } + } + } +} + +} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_window_delegate.h b/ui/ozone/platform/dri/dri_window_delegate.h index 75f9d95..9868068 100644 --- a/ui/ozone/platform/dri/dri_window_delegate.h +++ b/ui/ozone/platform/dri/dri_window_delegate.h
@@ -7,7 +7,12 @@ #include <vector> +#include "base/timer/timer.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" +#include "ui/ozone/ozone_export.h" +#include "ui/ozone/platform/dri/display_change_observer.h" class SkBitmap; @@ -18,52 +23,93 @@ namespace ui { +class DriBuffer; +class DrmDeviceManager; class HardwareDisplayController; +class ScreenManager; -// Interface for the display-server half of a DriWindow. -// -// The main implementation of this lives in the process that owns the display -// connection (usually the GPU process) and associates a platform window -// (DriWindow) with a display. A window is associated with the display whose -// bounds contains the window bounds. If there's no suitable display, the window -// is disconnected and its contents will not be visible. -// -// In software mode, this is owned directly on DriWindow because the display -// controller object is in the same process. -// -// In accelerated mode, there's a proxy implementation and calls are forwarded -// to the real object in the GPU process via IPC. -class DriWindowDelegate { +// A delegate of the platform window (DriWindow) on the GPU process. This is +// used to keep track of window state changes such that each platform window is +// correctly associated with a display. +// A window is associated with the display whose bounds contains the window +// bounds. If there's no suitable display, the window is disconnected and its +// contents will not be visible. +class OZONE_EXPORT DriWindowDelegate : public DisplayChangeObserver { public: - virtual ~DriWindowDelegate() {} + DriWindowDelegate(gfx::AcceleratedWidget widget, + DrmDeviceManager* device_manager, + ScreenManager* screen_manager); - virtual void Initialize() = 0; + ~DriWindowDelegate() override; - virtual void Shutdown() = 0; + void Initialize(); + + void Shutdown(); // Returns the accelerated widget associated with the delegate. - virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0; + gfx::AcceleratedWidget GetAcceleratedWidget(); // Returns the current controller the window is displaying on. Callers should // not cache the result as the controller may change as the window is moved. - virtual HardwareDisplayController* GetController() = 0; + HardwareDisplayController* GetController(); // Called when the window is resized/moved. - virtual void OnBoundsChanged(const gfx::Rect& bounds) = 0; + void OnBoundsChanged(const gfx::Rect& bounds); // Update the HW cursor bitmap & move to specified location. If // the bitmap is empty, the cursor is hidden. - virtual void SetCursor(const std::vector<SkBitmap>& bitmaps, - const gfx::Point& location, - int frame_delay_ms) = 0; + void SetCursor(const std::vector<SkBitmap>& bitmaps, + const gfx::Point& location, + int frame_delay_ms); // Update the HW cursor bitmap & move to specified location. If // the bitmap is empty, the cursor is hidden. - virtual void SetCursorWithoutAnimations(const std::vector<SkBitmap>& bitmaps, - const gfx::Point& location) = 0; + void SetCursorWithoutAnimations(const std::vector<SkBitmap>& bitmaps, + const gfx::Point& location); // Move the HW cursor to the specified location. - virtual void MoveCursor(const gfx::Point& location) = 0; + void MoveCursor(const gfx::Point& location); + + // DisplayChangeObserver: + void OnDisplayChanged(HardwareDisplayController* controller) override; + void OnDisplayRemoved(HardwareDisplayController* controller) override; + + private: + // Draw the last set cursor & update the cursor plane. + void ResetCursor(bool bitmap_only); + + // Draw next frame in an animated cursor. + void OnCursorAnimationTimeout(); + + void UpdateWidgetToDrmDeviceMapping(); + + // When |controller_| changes this is called to reallocate the cursor buffers + // since the allocation DRM device may have changed. + void UpdateCursorBuffers(); + + gfx::AcceleratedWidget widget_; + + DrmDeviceManager* device_manager_; // Not owned. + ScreenManager* screen_manager_; // Not owned. + + // The current bounds of the window. + gfx::Rect bounds_; + + // The controller associated with the current window. This may be nullptr if + // the window isn't over an active display. + HardwareDisplayController* controller_; + + base::RepeatingTimer<DriWindowDelegate> cursor_timer_; + + scoped_refptr<DriBuffer> cursor_buffers_[2]; + int cursor_frontbuffer_; + + std::vector<SkBitmap> cursor_bitmaps_; + gfx::Point cursor_location_; + int cursor_frame_; + int cursor_frame_delay_ms_; + + DISALLOW_COPY_AND_ASSIGN(DriWindowDelegate); }; } // namespace ui
diff --git a/ui/ozone/platform/dri/dri_window_delegate_impl.cc b/ui/ozone/platform/dri/dri_window_delegate_impl.cc deleted file mode 100644 index af81012d..0000000 --- a/ui/ozone/platform/dri/dri_window_delegate_impl.cc +++ /dev/null
@@ -1,219 +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 "ui/ozone/platform/dri/dri_window_delegate_impl.h" - -#include "base/trace_event/trace_event.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkDevice.h" -#include "third_party/skia/include/core/SkSurface.h" -#include "ui/ozone/platform/dri/dri_buffer.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" -#include "ui/ozone/platform/dri/drm_device_manager.h" -#include "ui/ozone/platform/dri/screen_manager.h" - -namespace ui { - -namespace { - -#ifndef DRM_CAP_CURSOR_WIDTH -#define DRM_CAP_CURSOR_WIDTH 0x8 -#endif - -#ifndef DRM_CAP_CURSOR_HEIGHT -#define DRM_CAP_CURSOR_HEIGHT 0x9 -#endif - -void UpdateCursorImage(DriBuffer* cursor, const SkBitmap& image) { - SkRect damage; - image.getBounds(&damage); - - // Clear to transparent in case |image| is smaller than the canvas. - SkCanvas* canvas = cursor->GetCanvas(); - canvas->clear(SK_ColorTRANSPARENT); - - SkRect clip; - clip.set(0, 0, canvas->getDeviceSize().width(), - canvas->getDeviceSize().height()); - canvas->clipRect(clip, SkRegion::kReplace_Op); - canvas->drawBitmapRectToRect(image, &damage, damage); -} - -} // namespace - -DriWindowDelegateImpl::DriWindowDelegateImpl( - gfx::AcceleratedWidget widget, - DrmDeviceManager* device_manager, - ScreenManager* screen_manager) - : widget_(widget), - device_manager_(device_manager), - screen_manager_(screen_manager), - controller_(NULL), - cursor_frontbuffer_(0), - cursor_frame_(0), - cursor_frame_delay_ms_(0) { -} - -DriWindowDelegateImpl::~DriWindowDelegateImpl() { -} - -void DriWindowDelegateImpl::Initialize() { - TRACE_EVENT1("dri", "DriWindowDelegateImpl::Initialize", "widget", widget_); - - device_manager_->UpdateDrmDevice(widget_, nullptr); - screen_manager_->AddObserver(this); -} - -void DriWindowDelegateImpl::Shutdown() { - TRACE_EVENT1("dri", "DriWindowDelegateImpl::Shutdown", "widget", widget_); - screen_manager_->RemoveObserver(this); - device_manager_->RemoveDrmDevice(widget_); -} - -gfx::AcceleratedWidget DriWindowDelegateImpl::GetAcceleratedWidget() { - return widget_; -} - -HardwareDisplayController* DriWindowDelegateImpl::GetController() { - return controller_; -} - -void DriWindowDelegateImpl::OnBoundsChanged(const gfx::Rect& bounds) { - TRACE_EVENT2("dri", "DriWindowDelegateImpl::OnBoundsChanged", "widget", - widget_, "bounds", bounds.ToString()); - bounds_ = bounds; - controller_ = screen_manager_->GetDisplayController(bounds); - UpdateWidgetToDrmDeviceMapping(); - UpdateCursorBuffers(); -} - -void DriWindowDelegateImpl::SetCursor(const std::vector<SkBitmap>& bitmaps, - const gfx::Point& location, - int frame_delay_ms) { - cursor_bitmaps_ = bitmaps; - cursor_location_ = location; - cursor_frame_ = 0; - cursor_frame_delay_ms_ = frame_delay_ms; - cursor_timer_.Stop(); - - if (cursor_frame_delay_ms_) - cursor_timer_.Start( - FROM_HERE, base::TimeDelta::FromMilliseconds(cursor_frame_delay_ms_), - this, &DriWindowDelegateImpl::OnCursorAnimationTimeout); - - ResetCursor(false); -} - -void DriWindowDelegateImpl::SetCursorWithoutAnimations( - const std::vector<SkBitmap>& bitmaps, - const gfx::Point& location) { - cursor_bitmaps_ = bitmaps; - cursor_location_ = location; - cursor_frame_ = 0; - cursor_frame_delay_ms_ = 0; - ResetCursor(false); -} - -void DriWindowDelegateImpl::MoveCursor(const gfx::Point& location) { - cursor_location_ = location; - - if (controller_) - controller_->MoveCursor(location); -} - -void DriWindowDelegateImpl::OnDisplayChanged( - HardwareDisplayController* controller) { - DCHECK(controller); - - // If we have a new controller we need to re-allocate the buffers. - bool should_allocate_cursor_buffers = controller_ != controller; - - gfx::Rect controller_bounds = - gfx::Rect(controller->origin(), controller->GetModeSize()); - if (controller_) { - if (controller_ != controller) - return; - - if (controller->IsDisabled() || bounds_ != controller_bounds) - controller_ = nullptr; - } else { - if (bounds_ == controller_bounds && !controller->IsDisabled()) - controller_ = controller; - } - - UpdateWidgetToDrmDeviceMapping(); - if (should_allocate_cursor_buffers) - UpdateCursorBuffers(); -} - -void DriWindowDelegateImpl::OnDisplayRemoved( - HardwareDisplayController* controller) { - if (controller_ == controller) - controller_ = nullptr; -} - -void DriWindowDelegateImpl::ResetCursor(bool bitmap_only) { - if (!controller_) - return; - - if (cursor_bitmaps_.size()) { - // Draw new cursor into backbuffer. - UpdateCursorImage(cursor_buffers_[cursor_frontbuffer_ ^ 1].get(), - cursor_bitmaps_[cursor_frame_]); - - // Reset location & buffer. - if (!bitmap_only) - controller_->MoveCursor(cursor_location_); - controller_->SetCursor(cursor_buffers_[cursor_frontbuffer_ ^ 1]); - cursor_frontbuffer_ ^= 1; - } else { - // No cursor set. - controller_->UnsetCursor(); - } -} - -void DriWindowDelegateImpl::OnCursorAnimationTimeout() { - cursor_frame_++; - cursor_frame_ %= cursor_bitmaps_.size(); - - ResetCursor(true); -} - -void DriWindowDelegateImpl::UpdateWidgetToDrmDeviceMapping() { - scoped_refptr<DriWrapper> drm = nullptr; - if (controller_) - drm = controller_->GetAllocationDriWrapper(); - - device_manager_->UpdateDrmDevice(widget_, drm); -} - -void DriWindowDelegateImpl::UpdateCursorBuffers() { - if (!controller_) { - for (size_t i = 0; i < arraysize(cursor_buffers_); ++i) { - cursor_buffers_[i] = nullptr; - } - } else { - scoped_refptr<DriWrapper> drm = controller_->GetAllocationDriWrapper(); - - uint64_t cursor_width = 64; - uint64_t cursor_height = 64; - drm->GetCapability(DRM_CAP_CURSOR_WIDTH, &cursor_width); - drm->GetCapability(DRM_CAP_CURSOR_HEIGHT, &cursor_height); - - SkImageInfo info = SkImageInfo::MakeN32Premul(cursor_width, cursor_height); - for (size_t i = 0; i < arraysize(cursor_buffers_); ++i) { - cursor_buffers_[i] = new DriBuffer(drm); - // Don't register a framebuffer for cursors since they are special (they - // aren't modesetting buffers and drivers may fail to register them due to - // their small sizes). - if (!cursor_buffers_[i]->Initialize( - info, false /* should_register_framebuffer */)) { - LOG(FATAL) << "Failed to initialize cursor buffer"; - return; - } - } - } -} - -} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_window_delegate_impl.h b/ui/ozone/platform/dri/dri_window_delegate_impl.h deleted file mode 100644 index 317a00ad..0000000 --- a/ui/ozone/platform/dri/dri_window_delegate_impl.h +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_OZONE_PLATFORM_DRI_DRI_WINDOW_DELEGATE_IMPL_H_ -#define UI_OZONE_PLATFORM_DRI_DRI_WINDOW_DELEGATE_IMPL_H_ - -#include "base/timer/timer.h" -#include "ui/gfx/geometry/point.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/ozone/ozone_export.h" -#include "ui/ozone/platform/dri/display_change_observer.h" -#include "ui/ozone/platform/dri/dri_window_delegate.h" - -namespace ui { - -class DriBuffer; -class DrmDeviceManager; -class HardwareDisplayController; -class ScreenManager; - -class OZONE_EXPORT DriWindowDelegateImpl : public DriWindowDelegate, - public DisplayChangeObserver { - public: - DriWindowDelegateImpl(gfx::AcceleratedWidget widget, - DrmDeviceManager* device_manager, - ScreenManager* screen_manager); - ~DriWindowDelegateImpl() override; - - // DriWindowDelegate: - void Initialize() override; - void Shutdown() override; - gfx::AcceleratedWidget GetAcceleratedWidget() override; - HardwareDisplayController* GetController() override; - void OnBoundsChanged(const gfx::Rect& bounds) override; - void SetCursor(const std::vector<SkBitmap>& bitmaps, - const gfx::Point& location, - int frame_delay_ms) override; - void SetCursorWithoutAnimations(const std::vector<SkBitmap>& bitmaps, - const gfx::Point& location) override; - void MoveCursor(const gfx::Point& location) override; - - // DisplayChangeObserver: - void OnDisplayChanged(HardwareDisplayController* controller) override; - void OnDisplayRemoved(HardwareDisplayController* controller) override; - - private: - // Draw the last set cursor & update the cursor plane. - void ResetCursor(bool bitmap_only); - - // Draw next frame in an animated cursor. - void OnCursorAnimationTimeout(); - - void UpdateWidgetToDrmDeviceMapping(); - - // When |controller_| changes this is called to reallocate the cursor buffers - // since the allocation DRM device may have changed. - void UpdateCursorBuffers(); - - gfx::AcceleratedWidget widget_; - - DrmDeviceManager* device_manager_; // Not owned. - ScreenManager* screen_manager_; // Not owned. - - // The current bounds of the window. - gfx::Rect bounds_; - - // The controller associated with the current window. This may be nullptr if - // the window isn't over an active display. - HardwareDisplayController* controller_; - - base::RepeatingTimer<DriWindowDelegateImpl> cursor_timer_; - - scoped_refptr<DriBuffer> cursor_buffers_[2]; - int cursor_frontbuffer_; - - std::vector<SkBitmap> cursor_bitmaps_; - gfx::Point cursor_location_; - int cursor_frame_; - int cursor_frame_delay_ms_; - - DISALLOW_COPY_AND_ASSIGN(DriWindowDelegateImpl); -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_DRI_DRI_WINDOW_DELEGATE_IMPL_H_
diff --git a/ui/ozone/platform/dri/dri_window_delegate_impl_unittest.cc b/ui/ozone/platform/dri/dri_window_delegate_impl_unittest.cc deleted file mode 100644 index 95068bd..0000000 --- a/ui/ozone/platform/dri/dri_window_delegate_impl_unittest.cc +++ /dev/null
@@ -1,146 +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 <vector> - -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkColor.h" -#include "third_party/skia/include/core/SkImageInfo.h" -#include "ui/ozone/platform/dri/dri_buffer.h" -#include "ui/ozone/platform/dri/dri_surface.h" -#include "ui/ozone/platform/dri/dri_surface_factory.h" -#include "ui/ozone/platform/dri/dri_window_delegate_impl.h" -#include "ui/ozone/platform/dri/dri_window_delegate_manager.h" -#include "ui/ozone/platform/dri/drm_device_manager.h" -#include "ui/ozone/platform/dri/hardware_display_controller.h" -#include "ui/ozone/platform/dri/screen_manager.h" -#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h" -#include "ui/ozone/public/surface_ozone_canvas.h" - -namespace { - -// Mode of size 6x4. -const drmModeModeInfo kDefaultMode = - {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}}; - -const gfx::AcceleratedWidget kDefaultWidgetHandle = 1; -const uint32_t kDefaultCrtc = 1; -const uint32_t kDefaultConnector = 2; -const int kDefaultCursorSize = 64; - -std::vector<skia::RefPtr<SkSurface>> GetCursorBuffers( - const scoped_refptr<ui::MockDriWrapper> drm) { - std::vector<skia::RefPtr<SkSurface>> cursor_buffers; - for (const skia::RefPtr<SkSurface>& cursor_buffer : drm->buffers()) { - if (cursor_buffer->width() == kDefaultCursorSize && - cursor_buffer->height() == kDefaultCursorSize) { - cursor_buffers.push_back(cursor_buffer); - } - } - - return cursor_buffers; -} - -} // namespace - -class DriWindowDelegateImplTest : public testing::Test { - public: - DriWindowDelegateImplTest() {} - - void SetUp() override; - void TearDown() override; - - protected: - scoped_ptr<base::MessageLoop> message_loop_; - scoped_refptr<ui::MockDriWrapper> dri_; - scoped_ptr<ui::DriBufferGenerator> buffer_generator_; - scoped_ptr<ui::ScreenManager> screen_manager_; - scoped_ptr<ui::DrmDeviceManager> drm_device_manager_; - scoped_ptr<ui::DriWindowDelegateManager> window_delegate_manager_; - - private: - DISALLOW_COPY_AND_ASSIGN(DriWindowDelegateImplTest); -}; - -void DriWindowDelegateImplTest::SetUp() { - message_loop_.reset(new base::MessageLoopForUI); - dri_ = new ui::MockDriWrapper(); - buffer_generator_.reset(new ui::DriBufferGenerator()); - screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get())); - screen_manager_->AddDisplayController(dri_, kDefaultCrtc, kDefaultConnector); - screen_manager_->ConfigureDisplayController( - dri_, kDefaultCrtc, kDefaultConnector, gfx::Point(), kDefaultMode); - - drm_device_manager_.reset(new ui::DrmDeviceManager(dri_)); - window_delegate_manager_.reset(new ui::DriWindowDelegateManager()); - - scoped_ptr<ui::DriWindowDelegate> window_delegate( - new ui::DriWindowDelegateImpl(kDefaultWidgetHandle, - drm_device_manager_.get(), - screen_manager_.get())); - window_delegate->Initialize(); - window_delegate->OnBoundsChanged( - gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay))); - window_delegate_manager_->AddWindowDelegate(kDefaultWidgetHandle, - window_delegate.Pass()); -} - -void DriWindowDelegateImplTest::TearDown() { - scoped_ptr<ui::DriWindowDelegate> delegate = - window_delegate_manager_->RemoveWindowDelegate(kDefaultWidgetHandle); - delegate->Shutdown(); - message_loop_.reset(); -} - -TEST_F(DriWindowDelegateImplTest, SetCursorImage) { - SkBitmap image; - SkImageInfo info = - SkImageInfo::Make(6, 4, kN32_SkColorType, kPremul_SkAlphaType); - image.allocPixels(info); - image.eraseColor(SK_ColorWHITE); - - std::vector<SkBitmap> cursor_bitmaps; - cursor_bitmaps.push_back(image); - window_delegate_manager_->GetWindowDelegate(kDefaultWidgetHandle) - ->SetCursor(cursor_bitmaps, gfx::Point(4, 2), 0); - - SkBitmap cursor; - std::vector<skia::RefPtr<SkSurface>> cursor_buffers = GetCursorBuffers(dri_); - EXPECT_EQ(2u, cursor_buffers.size()); - - // Buffers 1 is the cursor backbuffer we just drew in. - cursor.setInfo(cursor_buffers[1]->getCanvas()->imageInfo()); - EXPECT_TRUE(cursor_buffers[1]->getCanvas()->readPixels(&cursor, 0, 0)); - - // Check that the frontbuffer is displaying the right image as set above. - for (int i = 0; i < cursor.height(); ++i) { - for (int j = 0; j < cursor.width(); ++j) { - if (j < info.width() && i < info.height()) - EXPECT_EQ(SK_ColorWHITE, cursor.getColor(j, i)); - else - EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), - cursor.getColor(j, i)); - } - } -} - -TEST_F(DriWindowDelegateImplTest, CheckCursorSurfaceAfterChangingDevice) { - // Add another device. - scoped_refptr<ui::MockDriWrapper> drm = new ui::MockDriWrapper(); - screen_manager_->AddDisplayController(drm, kDefaultCrtc, kDefaultConnector); - screen_manager_->ConfigureDisplayController( - drm, kDefaultCrtc, kDefaultConnector, - gfx::Point(0, kDefaultMode.vdisplay), kDefaultMode); - - // Move window to the display on the new device. - window_delegate_manager_->GetWindowDelegate(kDefaultWidgetHandle) - ->OnBoundsChanged(gfx::Rect(0, kDefaultMode.vdisplay, - kDefaultMode.hdisplay, - kDefaultMode.vdisplay)); - - EXPECT_EQ(2u, GetCursorBuffers(drm).size()); -}
diff --git a/ui/ozone/platform/dri/dri_window_delegate_unittest.cc b/ui/ozone/platform/dri/dri_window_delegate_unittest.cc new file mode 100644 index 0000000..2df1cbe4 --- /dev/null +++ b/ui/ozone/platform/dri/dri_window_delegate_unittest.cc
@@ -0,0 +1,144 @@ +// 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 <vector> + +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "ui/ozone/platform/dri/dri_buffer.h" +#include "ui/ozone/platform/dri/dri_surface.h" +#include "ui/ozone/platform/dri/dri_surface_factory.h" +#include "ui/ozone/platform/dri/dri_window_delegate.h" +#include "ui/ozone/platform/dri/dri_window_delegate_manager.h" +#include "ui/ozone/platform/dri/drm_device_manager.h" +#include "ui/ozone/platform/dri/hardware_display_controller.h" +#include "ui/ozone/platform/dri/screen_manager.h" +#include "ui/ozone/platform/dri/test/mock_drm_device.h" +#include "ui/ozone/public/surface_ozone_canvas.h" + +namespace { + +// Mode of size 6x4. +const drmModeModeInfo kDefaultMode = + {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}}; + +const gfx::AcceleratedWidget kDefaultWidgetHandle = 1; +const uint32_t kDefaultCrtc = 1; +const uint32_t kDefaultConnector = 2; +const int kDefaultCursorSize = 64; + +std::vector<skia::RefPtr<SkSurface>> GetCursorBuffers( + const scoped_refptr<ui::MockDrmDevice> drm) { + std::vector<skia::RefPtr<SkSurface>> cursor_buffers; + for (const skia::RefPtr<SkSurface>& cursor_buffer : drm->buffers()) { + if (cursor_buffer->width() == kDefaultCursorSize && + cursor_buffer->height() == kDefaultCursorSize) { + cursor_buffers.push_back(cursor_buffer); + } + } + + return cursor_buffers; +} + +} // namespace + +class DriWindowDelegateTest : public testing::Test { + public: + DriWindowDelegateTest() {} + + void SetUp() override; + void TearDown() override; + + protected: + scoped_ptr<base::MessageLoop> message_loop_; + scoped_refptr<ui::MockDrmDevice> drm_; + scoped_ptr<ui::DriBufferGenerator> buffer_generator_; + scoped_ptr<ui::ScreenManager> screen_manager_; + scoped_ptr<ui::DrmDeviceManager> drm_device_manager_; + scoped_ptr<ui::DriWindowDelegateManager> window_delegate_manager_; + + private: + DISALLOW_COPY_AND_ASSIGN(DriWindowDelegateTest); +}; + +void DriWindowDelegateTest::SetUp() { + message_loop_.reset(new base::MessageLoopForUI); + drm_ = new ui::MockDrmDevice(); + buffer_generator_.reset(new ui::DriBufferGenerator()); + screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get())); + screen_manager_->AddDisplayController(drm_, kDefaultCrtc, kDefaultConnector); + screen_manager_->ConfigureDisplayController( + drm_, kDefaultCrtc, kDefaultConnector, gfx::Point(), kDefaultMode); + + drm_device_manager_.reset(new ui::DrmDeviceManager(drm_)); + window_delegate_manager_.reset(new ui::DriWindowDelegateManager()); + + scoped_ptr<ui::DriWindowDelegate> window_delegate(new ui::DriWindowDelegate( + kDefaultWidgetHandle, drm_device_manager_.get(), screen_manager_.get())); + window_delegate->Initialize(); + window_delegate->OnBoundsChanged( + gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay))); + window_delegate_manager_->AddWindowDelegate(kDefaultWidgetHandle, + window_delegate.Pass()); +} + +void DriWindowDelegateTest::TearDown() { + scoped_ptr<ui::DriWindowDelegate> delegate = + window_delegate_manager_->RemoveWindowDelegate(kDefaultWidgetHandle); + delegate->Shutdown(); + message_loop_.reset(); +} + +TEST_F(DriWindowDelegateTest, SetCursorImage) { + SkBitmap image; + SkImageInfo info = + SkImageInfo::Make(6, 4, kN32_SkColorType, kPremul_SkAlphaType); + image.allocPixels(info); + image.eraseColor(SK_ColorWHITE); + + std::vector<SkBitmap> cursor_bitmaps; + cursor_bitmaps.push_back(image); + window_delegate_manager_->GetWindowDelegate(kDefaultWidgetHandle) + ->SetCursor(cursor_bitmaps, gfx::Point(4, 2), 0); + + SkBitmap cursor; + std::vector<skia::RefPtr<SkSurface>> cursor_buffers = GetCursorBuffers(drm_); + EXPECT_EQ(2u, cursor_buffers.size()); + + // Buffers 1 is the cursor backbuffer we just drew in. + cursor.setInfo(cursor_buffers[1]->getCanvas()->imageInfo()); + EXPECT_TRUE(cursor_buffers[1]->getCanvas()->readPixels(&cursor, 0, 0)); + + // Check that the frontbuffer is displaying the right image as set above. + for (int i = 0; i < cursor.height(); ++i) { + for (int j = 0; j < cursor.width(); ++j) { + if (j < info.width() && i < info.height()) + EXPECT_EQ(SK_ColorWHITE, cursor.getColor(j, i)); + else + EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), + cursor.getColor(j, i)); + } + } +} + +TEST_F(DriWindowDelegateTest, CheckCursorSurfaceAfterChangingDevice) { + // Add another device. + scoped_refptr<ui::MockDrmDevice> drm = new ui::MockDrmDevice(); + screen_manager_->AddDisplayController(drm, kDefaultCrtc, kDefaultConnector); + screen_manager_->ConfigureDisplayController( + drm, kDefaultCrtc, kDefaultConnector, + gfx::Point(0, kDefaultMode.vdisplay), kDefaultMode); + + // Move window to the display on the new device. + window_delegate_manager_->GetWindowDelegate(kDefaultWidgetHandle) + ->OnBoundsChanged(gfx::Rect(0, kDefaultMode.vdisplay, + kDefaultMode.hdisplay, + kDefaultMode.vdisplay)); + + EXPECT_EQ(2u, GetCursorBuffers(drm).size()); +}
diff --git a/ui/ozone/platform/dri/dri_wrapper.cc b/ui/ozone/platform/dri/dri_wrapper.cc deleted file mode 100644 index 87b250ec..0000000 --- a/ui/ozone/platform/dri/dri_wrapper.cc +++ /dev/null
@@ -1,461 +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 "ui/ozone/platform/dri/dri_wrapper.h" - -#include <fcntl.h> -#include <sys/mman.h> -#include <unistd.h> -#include <xf86drm.h> -#include <xf86drmMode.h> - -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/stl_util.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_runner.h" -#include "base/thread_task_runner_handle.h" -#include "base/trace_event/trace_event.h" -#include "third_party/skia/include/core/SkImageInfo.h" -#include "ui/ozone/platform/dri/dri_util.h" -#include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h" - -namespace ui { - -namespace { - -struct PageFlipPayload { - PageFlipPayload(const scoped_refptr<base::TaskRunner>& task_runner, - const DriWrapper::PageFlipCallback& callback) - : task_runner(task_runner), callback(callback) {} - - // Task runner for the thread scheduling the page flip event. This is used to - // run the callback on the same thread the callback was created on. - scoped_refptr<base::TaskRunner> task_runner; - DriWrapper::PageFlipCallback callback; -}; - -bool DrmCreateDumbBuffer(int fd, - const SkImageInfo& info, - uint32_t* handle, - uint32_t* stride) { - struct drm_mode_create_dumb request; - memset(&request, 0, sizeof(request)); - request.width = info.width(); - request.height = info.height(); - request.bpp = info.bytesPerPixel() << 3; - request.flags = 0; - - if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &request) < 0) { - VLOG(2) << "Cannot create dumb buffer (" << errno << ") " - << strerror(errno); - return false; - } - - // The driver may choose to align the last row as well. We don't care about - // the last alignment bits since they aren't used for display purposes, so - // just check that the expected size is <= to what the driver allocated. - DCHECK_LE(info.getSafeSize(request.pitch), request.size); - - *handle = request.handle; - *stride = request.pitch; - return true; -} - -void DrmDestroyDumbBuffer(int fd, uint32_t handle) { - struct drm_mode_destroy_dumb destroy_request; - memset(&destroy_request, 0, sizeof(destroy_request)); - destroy_request.handle = handle; - drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request); -} - -void HandlePageFlipEventOnIO(int fd, - unsigned int frame, - unsigned int seconds, - unsigned int useconds, - void* data) { - scoped_ptr<PageFlipPayload> payload(static_cast<PageFlipPayload*>(data)); - payload->task_runner->PostTask( - FROM_HERE, base::Bind(payload->callback, frame, seconds, useconds)); -} - -void HandlePageFlipEventOnUI(int fd, - unsigned int frame, - unsigned int seconds, - unsigned int useconds, - void* data) { - scoped_ptr<PageFlipPayload> payload(static_cast<PageFlipPayload*>(data)); - payload->callback.Run(frame, seconds, useconds); -} - -bool CanQueryForResources(int fd) { - drm_mode_card_res resources; - memset(&resources, 0, sizeof(resources)); - // If there is no error getting DRM resources then assume this is a - // modesetting device. - return !drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &resources); -} - -} // namespace - -class DriWrapper::IOWatcher - : public base::RefCountedThreadSafe<DriWrapper::IOWatcher>, - public base::MessagePumpLibevent::Watcher { - public: - IOWatcher(int fd, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) - : io_task_runner_(io_task_runner), paused_(true), fd_(fd) {} - - void SetPaused(bool paused) { - if (paused_ == paused) - return; - - paused_ = paused; - base::WaitableEvent done(false, false); - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&IOWatcher::SetPausedOnIO, this, &done)); - } - - void Shutdown() { - if (!paused_) - io_task_runner_->PostTask(FROM_HERE, - base::Bind(&IOWatcher::UnregisterOnIO, this)); - } - - private: - friend class base::RefCountedThreadSafe<IOWatcher>; - - ~IOWatcher() override { SetPaused(true); } - - void RegisterOnIO() { - DCHECK(base::MessageLoopForIO::IsCurrent()); - base::MessageLoopForIO::current()->WatchFileDescriptor( - fd_, true, base::MessageLoopForIO::WATCH_READ, &controller_, this); - } - - void UnregisterOnIO() { - DCHECK(base::MessageLoopForIO::IsCurrent()); - controller_.StopWatchingFileDescriptor(); - } - - void SetPausedOnIO(base::WaitableEvent* done) { - DCHECK(base::MessageLoopForIO::IsCurrent()); - if (paused_) - UnregisterOnIO(); - else - RegisterOnIO(); - done->Signal(); - } - - // base::MessagePumpLibevent::Watcher overrides: - void OnFileCanReadWithoutBlocking(int fd) override { - DCHECK(base::MessageLoopForIO::IsCurrent()); - TRACE_EVENT1("dri", "OnDrmEvent", "socket", fd); - - drmEventContext event; - event.version = DRM_EVENT_CONTEXT_VERSION; - event.page_flip_handler = HandlePageFlipEventOnIO; - event.vblank_handler = nullptr; - - drmHandleEvent(fd, &event); - } - - void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); } - - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; - - base::MessagePumpLibevent::FileDescriptorWatcher controller_; - - bool paused_; - int fd_; - - DISALLOW_COPY_AND_ASSIGN(IOWatcher); -}; - -DriWrapper::DriWrapper(const base::FilePath& device_path) - : device_path_(device_path), - file_(device_path, - base::File::FLAG_OPEN | base::File::FLAG_READ | - base::File::FLAG_WRITE) { - LOG_IF(FATAL, !file_.IsValid()) - << "Failed to open '" << device_path_.value() - << "': " << base::File::ErrorToString(file_.error_details()); -} - -DriWrapper::DriWrapper(const base::FilePath& device_path, base::File file) - : device_path_(device_path), file_(file.Pass()) { -} - -DriWrapper::~DriWrapper() { - if (watcher_) - watcher_->Shutdown(); -} - -bool DriWrapper::Initialize() { - // Ignore devices that cannot perform modesetting. - if (!CanQueryForResources(file_.GetPlatformFile())) { - VLOG(2) << "Cannot query for resources for '" << device_path_.value() - << "'"; - return false; - } - - plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); - if (!plane_manager_->Initialize(this)) { - LOG(ERROR) << "Failed to initialize the plane manager for " - << device_path_.value(); - plane_manager_.reset(); - return false; - } - - return true; -} - -void DriWrapper::InitializeTaskRunner( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { - DCHECK(!task_runner_); - task_runner_ = task_runner; - watcher_ = new IOWatcher(file_.GetPlatformFile(), task_runner_); -} - -ScopedDrmCrtcPtr DriWrapper::GetCrtc(uint32_t crtc_id) { - DCHECK(file_.IsValid()); - return ScopedDrmCrtcPtr(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id)); -} - -bool DriWrapper::SetCrtc(uint32_t crtc_id, - uint32_t framebuffer, - std::vector<uint32_t> connectors, - drmModeModeInfo* mode) { - DCHECK(file_.IsValid()); - DCHECK(!connectors.empty()); - DCHECK(mode); - - TRACE_EVENT2("dri", "DriWrapper::SetCrtc", "crtc", crtc_id, "size", - gfx::Size(mode->hdisplay, mode->vdisplay).ToString()); - return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0, - vector_as_array(&connectors), connectors.size(), mode); -} - -bool DriWrapper::SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) { - DCHECK(file_.IsValid()); - // If there's no buffer then the CRTC was disabled. - if (!crtc->buffer_id) - return DisableCrtc(crtc->crtc_id); - - DCHECK(!connectors.empty()); - - TRACE_EVENT1("dri", "DriWrapper::RestoreCrtc", - "crtc", crtc->crtc_id); - return !drmModeSetCrtc(file_.GetPlatformFile(), crtc->crtc_id, - crtc->buffer_id, crtc->x, crtc->y, - vector_as_array(&connectors), connectors.size(), - &crtc->mode); -} - -bool DriWrapper::DisableCrtc(uint32_t crtc_id) { - DCHECK(file_.IsValid()); - TRACE_EVENT1("dri", "DriWrapper::DisableCrtc", - "crtc", crtc_id); - return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, 0, 0, 0, NULL, 0, - NULL); -} - -ScopedDrmConnectorPtr DriWrapper::GetConnector(uint32_t connector_id) { - DCHECK(file_.IsValid()); - TRACE_EVENT1("dri", "DriWrapper::GetConnector", "connector", connector_id); - return ScopedDrmConnectorPtr( - drmModeGetConnector(file_.GetPlatformFile(), connector_id)); -} - -bool DriWrapper::AddFramebuffer(uint32_t width, - uint32_t height, - uint8_t depth, - uint8_t bpp, - uint32_t stride, - uint32_t handle, - uint32_t* framebuffer) { - DCHECK(file_.IsValid()); - TRACE_EVENT1("dri", "DriWrapper::AddFramebuffer", - "handle", handle); - return !drmModeAddFB(file_.GetPlatformFile(), width, height, depth, bpp, - stride, handle, framebuffer); -} - -bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) { - DCHECK(file_.IsValid()); - TRACE_EVENT1("dri", "DriWrapper::RemoveFramebuffer", - "framebuffer", framebuffer); - return !drmModeRmFB(file_.GetPlatformFile(), framebuffer); -} - -bool DriWrapper::PageFlip(uint32_t crtc_id, - uint32_t framebuffer, - bool is_sync, - const PageFlipCallback& callback) { - DCHECK(file_.IsValid()); - TRACE_EVENT2("dri", "DriWrapper::PageFlip", - "crtc", crtc_id, - "framebuffer", framebuffer); - - if (watcher_) - watcher_->SetPaused(is_sync); - - // NOTE: Calling drmModeSetCrtc will immediately update the state, though - // callbacks to already scheduled page flips will be honored by the kernel. - scoped_ptr<PageFlipPayload> payload( - new PageFlipPayload(base::ThreadTaskRunnerHandle::Get(), callback)); - if (!drmModePageFlip(file_.GetPlatformFile(), crtc_id, framebuffer, - DRM_MODE_PAGE_FLIP_EVENT, payload.get())) { - // If successful the payload will be removed by a PageFlip event. - ignore_result(payload.release()); - - // If the flip was requested synchronous or if no watcher has been installed - // yet, then synchronously handle the page flip events. - if (is_sync || !watcher_) { - TRACE_EVENT1("dri", "OnDrmEvent", "socket", file_.GetPlatformFile()); - - drmEventContext event; - event.version = DRM_EVENT_CONTEXT_VERSION; - event.page_flip_handler = HandlePageFlipEventOnUI; - event.vblank_handler = nullptr; - - drmHandleEvent(file_.GetPlatformFile(), &event); - } - - return true; - } - - return false; -} - -bool DriWrapper::PageFlipOverlay(uint32_t crtc_id, - uint32_t framebuffer, - const gfx::Rect& location, - const gfx::Rect& source, - int overlay_plane) { - DCHECK(file_.IsValid()); - TRACE_EVENT2("dri", "DriWrapper::PageFlipOverlay", - "crtc", crtc_id, - "framebuffer", framebuffer); - return !drmModeSetPlane(file_.GetPlatformFile(), overlay_plane, crtc_id, - framebuffer, 0, location.x(), location.y(), - location.width(), location.height(), source.x(), - source.y(), source.width(), source.height()); -} - -ScopedDrmFramebufferPtr DriWrapper::GetFramebuffer(uint32_t framebuffer) { - DCHECK(file_.IsValid()); - TRACE_EVENT1("dri", "DriWrapper::GetFramebuffer", - "framebuffer", framebuffer); - return ScopedDrmFramebufferPtr( - drmModeGetFB(file_.GetPlatformFile(), framebuffer)); -} - -ScopedDrmPropertyPtr DriWrapper::GetProperty(drmModeConnector* connector, - const char* name) { - TRACE_EVENT2("dri", "DriWrapper::GetProperty", - "connector", connector->connector_id, - "name", name); - for (int i = 0; i < connector->count_props; ++i) { - ScopedDrmPropertyPtr property( - drmModeGetProperty(file_.GetPlatformFile(), connector->props[i])); - if (!property) - continue; - - if (strcmp(property->name, name) == 0) - return property.Pass(); - } - - return ScopedDrmPropertyPtr(); -} - -bool DriWrapper::SetProperty(uint32_t connector_id, - uint32_t property_id, - uint64_t value) { - DCHECK(file_.IsValid()); - return !drmModeConnectorSetProperty(file_.GetPlatformFile(), connector_id, - property_id, value); -} - -bool DriWrapper::GetCapability(uint64_t capability, uint64_t* value) { - DCHECK(file_.IsValid()); - return !drmGetCap(file_.GetPlatformFile(), capability, value); -} - -ScopedDrmPropertyBlobPtr DriWrapper::GetPropertyBlob( - drmModeConnector* connector, const char* name) { - DCHECK(file_.IsValid()); - TRACE_EVENT2("dri", "DriWrapper::GetPropertyBlob", - "connector", connector->connector_id, - "name", name); - for (int i = 0; i < connector->count_props; ++i) { - ScopedDrmPropertyPtr property( - drmModeGetProperty(file_.GetPlatformFile(), connector->props[i])); - if (!property) - continue; - - if (strcmp(property->name, name) == 0 && - property->flags & DRM_MODE_PROP_BLOB) - return ScopedDrmPropertyBlobPtr(drmModeGetPropertyBlob( - file_.GetPlatformFile(), connector->prop_values[i])); - } - - return ScopedDrmPropertyBlobPtr(); -} - -bool DriWrapper::SetCursor(uint32_t crtc_id, - uint32_t handle, - const gfx::Size& size) { - DCHECK(file_.IsValid()); - TRACE_EVENT1("dri", "DriWrapper::SetCursor", "handle", handle); - return !drmModeSetCursor(file_.GetPlatformFile(), crtc_id, handle, - size.width(), size.height()); -} - -bool DriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) { - DCHECK(file_.IsValid()); - return !drmModeMoveCursor(file_.GetPlatformFile(), crtc_id, point.x(), - point.y()); -} - -bool DriWrapper::CreateDumbBuffer(const SkImageInfo& info, - uint32_t* handle, - uint32_t* stride, - void** pixels) { - DCHECK(file_.IsValid()); - - TRACE_EVENT0("dri", "DriWrapper::CreateDumbBuffer"); - if (!DrmCreateDumbBuffer(file_.GetPlatformFile(), info, handle, stride)) - return false; - - if (!MapDumbBuffer(file_.GetPlatformFile(), *handle, - info.getSafeSize(*stride), pixels)) { - DrmDestroyDumbBuffer(file_.GetPlatformFile(), *handle); - return false; - } - - return true; -} - -void DriWrapper::DestroyDumbBuffer(const SkImageInfo& info, - uint32_t handle, - uint32_t stride, - void* pixels) { - DCHECK(file_.IsValid()); - TRACE_EVENT1("dri", "DriWrapper::DestroyDumbBuffer", "handle", handle); - munmap(pixels, info.getSafeSize(stride)); - DrmDestroyDumbBuffer(file_.GetPlatformFile(), handle); -} - -bool DriWrapper::SetMaster() { - DCHECK(file_.IsValid()); - return (drmSetMaster(file_.GetPlatformFile()) == 0); -} - -bool DriWrapper::DropMaster() { - DCHECK(file_.IsValid()); - return (drmDropMaster(file_.GetPlatformFile()) == 0); -} - -} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_wrapper.h b/ui/ozone/platform/dri/dri_wrapper.h deleted file mode 100644 index 27582dbb..0000000 --- a/ui/ozone/platform/dri/dri_wrapper.h +++ /dev/null
@@ -1,195 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_OZONE_PLATFORM_DRI_DRI_WRAPPER_H_ -#define UI_OZONE_PLATFORM_DRI_DRI_WRAPPER_H_ - -#include <stdint.h> - -#include <vector> - -#include "base/callback.h" -#include "base/files/file.h" -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_vector.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/rect_f.h" -#include "ui/gfx/overlay_transform.h" -#include "ui/ozone/ozone_export.h" -#include "ui/ozone/platform/dri/hardware_display_plane_manager.h" -#include "ui/ozone/platform/dri/scoped_drm_types.h" - -typedef struct _drmEventContext drmEventContext; -typedef struct _drmModeModeInfo drmModeModeInfo; - -struct SkImageInfo; - -namespace base { -class SingleThreadTaskRunner; -} // namespace base - -namespace ui { - -class HardwareDisplayPlaneManager; - -// Wraps DRM calls into a nice interface. Used to provide different -// implementations of the DRM calls. For the actual implementation the DRM API -// would be called. In unit tests this interface would be stubbed. -class OZONE_EXPORT DriWrapper : public base::RefCountedThreadSafe<DriWrapper> { - public: - typedef base::Callback<void(unsigned int /* frame */, - unsigned int /* seconds */, - unsigned int /* useconds */)> PageFlipCallback; - - DriWrapper(const base::FilePath& device_path); - DriWrapper(const base::FilePath& device_path, base::File file); - - // Open device. - virtual bool Initialize(); - - // |task_runner| will be used to asynchronously page flip. - virtual void InitializeTaskRunner( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); - - // Get the CRTC state. This is generally used to save state before using the - // CRTC. When the user finishes using the CRTC, the user should restore the - // CRTC to it's initial state. Use |SetCrtc| to restore the state. - virtual ScopedDrmCrtcPtr GetCrtc(uint32_t crtc_id); - - // Used to configure CRTC with ID |crtc_id| to use the connector in - // |connectors|. The CRTC will be configured with mode |mode| and will display - // the framebuffer with ID |framebuffer|. Before being able to display the - // framebuffer, it should be registered with the CRTC using |AddFramebuffer|. - virtual bool SetCrtc(uint32_t crtc_id, - uint32_t framebuffer, - std::vector<uint32_t> connectors, - drmModeModeInfo* mode); - - // Used to set a specific configuration to the CRTC. Normally this function - // would be called with a CRTC saved state (from |GetCrtc|) to restore it to - // its original configuration. - virtual bool SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors); - - virtual bool DisableCrtc(uint32_t crtc_id); - - // Returns the connector properties for |connector_id|. - virtual ScopedDrmConnectorPtr GetConnector(uint32_t connector_id); - - // Register a buffer with the CRTC. On successful registration, the CRTC will - // assign a framebuffer ID to |framebuffer|. - virtual bool AddFramebuffer(uint32_t width, - uint32_t height, - uint8_t depth, - uint8_t bpp, - uint32_t stride, - uint32_t handle, - uint32_t* framebuffer); - - // Deregister the given |framebuffer|. - virtual bool RemoveFramebuffer(uint32_t framebuffer); - - // Get the DRM details associated with |framebuffer|. - virtual ScopedDrmFramebufferPtr GetFramebuffer(uint32_t framebuffer); - - // Schedules a pageflip for CRTC |crtc_id|. This function will return - // immediately. Upon completion of the pageflip event, the CRTC will be - // displaying the buffer with ID |framebuffer| and will have a DRM event - // queued on |fd_|. - virtual bool PageFlip(uint32_t crtc_id, - uint32_t framebuffer, - bool is_sync, - const PageFlipCallback& callback); - - // Schedule an overlay to be show during the page flip for CRTC |crtc_id|. - // |source| location from |framebuffer| will be shown on overlay - // |overlay_plane|, in the bounds specified by |location| on the screen. - virtual bool PageFlipOverlay(uint32_t crtc_id, - uint32_t framebuffer, - const gfx::Rect& location, - const gfx::Rect& source, - int overlay_plane); - - // Returns the property with name |name| associated with |connector|. Returns - // NULL if property not found. If the returned value is valid, it must be - // released using FreeProperty(). - virtual ScopedDrmPropertyPtr GetProperty(drmModeConnector* connector, - const char* name); - - // Sets the value of property with ID |property_id| to |value|. The property - // is applied to the connector with ID |connector_id|. - virtual bool SetProperty(uint32_t connector_id, - uint32_t property_id, - uint64_t value); - - // Can be used to query device/driver |capability|. Sets the value of - // |capability to |value|. Returns true in case of a succesful query. - virtual bool GetCapability(uint64_t capability, uint64_t* value); - - // Return a binary blob associated with |connector|. The binary blob is - // associated with the property with name |name|. Return NULL if the property - // could not be found or if the property does not have a binary blob. If valid - // the returned object must be freed using FreePropertyBlob(). - virtual ScopedDrmPropertyBlobPtr GetPropertyBlob(drmModeConnector* connector, - const char* name); - - // Set the cursor to be displayed in CRTC |crtc_id|. (width, height) is the - // cursor size pointed by |handle|. - virtual bool SetCursor(uint32_t crtc_id, - uint32_t handle, - const gfx::Size& size); - - - // Move the cursor on CRTC |crtc_id| to (x, y); - virtual bool MoveCursor(uint32_t crtc_id, const gfx::Point& point); - - virtual bool CreateDumbBuffer(const SkImageInfo& info, - uint32_t* handle, - uint32_t* stride, - void** pixels); - - virtual void DestroyDumbBuffer(const SkImageInfo& info, - uint32_t handle, - uint32_t stride, - void* pixels); - - // Drm master related - virtual bool SetMaster(); - virtual bool DropMaster(); - - int get_fd() const { return file_.GetPlatformFile(); } - - base::FilePath device_path() const { return device_path_; } - - HardwareDisplayPlaneManager* plane_manager() { return plane_manager_.get(); } - - protected: - friend class base::RefCountedThreadSafe<DriWrapper>; - - virtual ~DriWrapper(); - - scoped_ptr<HardwareDisplayPlaneManager> plane_manager_; - - private: - class IOWatcher; - - // Path to DRM device. - const base::FilePath device_path_; - - // DRM device. - base::File file_; - - // Helper thread to perform IO listener operations. - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - - // Watcher for |fd_| listening for page flip events. - scoped_refptr<IOWatcher> watcher_; - - DISALLOW_COPY_AND_ASSIGN(DriWrapper); -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_DRI_DRI_WRAPPER_H_
diff --git a/ui/ozone/platform/dri/drm_device.cc b/ui/ozone/platform/dri/drm_device.cc new file mode 100644 index 0000000..e51059d --- /dev/null +++ b/ui/ozone/platform/dri/drm_device.cc
@@ -0,0 +1,453 @@ +// 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/dri/drm_device.h" + +#include <fcntl.h> +#include <sys/mman.h> +#include <unistd.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/stl_util.h" +#include "base/synchronization/waitable_event.h" +#include "base/task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "base/trace_event/trace_event.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "ui/ozone/platform/dri/dri_util.h" +#include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h" + +namespace ui { + +namespace { + +struct PageFlipPayload { + PageFlipPayload(const scoped_refptr<base::TaskRunner>& task_runner, + const DrmDevice::PageFlipCallback& callback) + : task_runner(task_runner), callback(callback) {} + + // Task runner for the thread scheduling the page flip event. This is used to + // run the callback on the same thread the callback was created on. + scoped_refptr<base::TaskRunner> task_runner; + DrmDevice::PageFlipCallback callback; +}; + +bool DrmCreateDumbBuffer(int fd, + const SkImageInfo& info, + uint32_t* handle, + uint32_t* stride) { + struct drm_mode_create_dumb request; + memset(&request, 0, sizeof(request)); + request.width = info.width(); + request.height = info.height(); + request.bpp = info.bytesPerPixel() << 3; + request.flags = 0; + + if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &request) < 0) { + VLOG(2) << "Cannot create dumb buffer (" << errno << ") " + << strerror(errno); + return false; + } + + // The driver may choose to align the last row as well. We don't care about + // the last alignment bits since they aren't used for display purposes, so + // just check that the expected size is <= to what the driver allocated. + DCHECK_LE(info.getSafeSize(request.pitch), request.size); + + *handle = request.handle; + *stride = request.pitch; + return true; +} + +void DrmDestroyDumbBuffer(int fd, uint32_t handle) { + struct drm_mode_destroy_dumb destroy_request; + memset(&destroy_request, 0, sizeof(destroy_request)); + destroy_request.handle = handle; + drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request); +} + +void HandlePageFlipEventOnIO(int fd, + unsigned int frame, + unsigned int seconds, + unsigned int useconds, + void* data) { + scoped_ptr<PageFlipPayload> payload(static_cast<PageFlipPayload*>(data)); + payload->task_runner->PostTask( + FROM_HERE, base::Bind(payload->callback, frame, seconds, useconds)); +} + +void HandlePageFlipEventOnUI(int fd, + unsigned int frame, + unsigned int seconds, + unsigned int useconds, + void* data) { + scoped_ptr<PageFlipPayload> payload(static_cast<PageFlipPayload*>(data)); + payload->callback.Run(frame, seconds, useconds); +} + +bool CanQueryForResources(int fd) { + drm_mode_card_res resources; + memset(&resources, 0, sizeof(resources)); + // If there is no error getting DRM resources then assume this is a + // modesetting device. + return !drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &resources); +} + +} // namespace + +class DrmDevice::IOWatcher + : public base::RefCountedThreadSafe<DrmDevice::IOWatcher>, + public base::MessagePumpLibevent::Watcher { + public: + IOWatcher(int fd, + const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) + : io_task_runner_(io_task_runner), paused_(true), fd_(fd) {} + + void SetPaused(bool paused) { + if (paused_ == paused) + return; + + paused_ = paused; + base::WaitableEvent done(false, false); + io_task_runner_->PostTask( + FROM_HERE, base::Bind(&IOWatcher::SetPausedOnIO, this, &done)); + } + + void Shutdown() { + if (!paused_) + io_task_runner_->PostTask(FROM_HERE, + base::Bind(&IOWatcher::UnregisterOnIO, this)); + } + + private: + friend class base::RefCountedThreadSafe<IOWatcher>; + + ~IOWatcher() override { SetPaused(true); } + + void RegisterOnIO() { + DCHECK(base::MessageLoopForIO::IsCurrent()); + base::MessageLoopForIO::current()->WatchFileDescriptor( + fd_, true, base::MessageLoopForIO::WATCH_READ, &controller_, this); + } + + void UnregisterOnIO() { + DCHECK(base::MessageLoopForIO::IsCurrent()); + controller_.StopWatchingFileDescriptor(); + } + + void SetPausedOnIO(base::WaitableEvent* done) { + DCHECK(base::MessageLoopForIO::IsCurrent()); + if (paused_) + UnregisterOnIO(); + else + RegisterOnIO(); + done->Signal(); + } + + // base::MessagePumpLibevent::Watcher overrides: + void OnFileCanReadWithoutBlocking(int fd) override { + DCHECK(base::MessageLoopForIO::IsCurrent()); + TRACE_EVENT1("dri", "OnDrmEvent", "socket", fd); + + drmEventContext event; + event.version = DRM_EVENT_CONTEXT_VERSION; + event.page_flip_handler = HandlePageFlipEventOnIO; + event.vblank_handler = nullptr; + + drmHandleEvent(fd, &event); + } + + void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); } + + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + + base::MessagePumpLibevent::FileDescriptorWatcher controller_; + + bool paused_; + int fd_; + + DISALLOW_COPY_AND_ASSIGN(IOWatcher); +}; + +DrmDevice::DrmDevice(const base::FilePath& device_path) + : device_path_(device_path), + file_(device_path, + base::File::FLAG_OPEN | base::File::FLAG_READ | + base::File::FLAG_WRITE) { + LOG_IF(FATAL, !file_.IsValid()) + << "Failed to open '" << device_path_.value() + << "': " << base::File::ErrorToString(file_.error_details()); +} + +DrmDevice::DrmDevice(const base::FilePath& device_path, base::File file) + : device_path_(device_path), file_(file.Pass()) { +} + +DrmDevice::~DrmDevice() { + if (watcher_) + watcher_->Shutdown(); +} + +bool DrmDevice::Initialize() { + // Ignore devices that cannot perform modesetting. + if (!CanQueryForResources(file_.GetPlatformFile())) { + VLOG(2) << "Cannot query for resources for '" << device_path_.value() + << "'"; + return false; + } + + plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); + if (!plane_manager_->Initialize(this)) { + LOG(ERROR) << "Failed to initialize the plane manager for " + << device_path_.value(); + plane_manager_.reset(); + return false; + } + + return true; +} + +void DrmDevice::InitializeTaskRunner( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { + DCHECK(!task_runner_); + task_runner_ = task_runner; + watcher_ = new IOWatcher(file_.GetPlatformFile(), task_runner_); +} + +ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) { + DCHECK(file_.IsValid()); + return ScopedDrmCrtcPtr(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id)); +} + +bool DrmDevice::SetCrtc(uint32_t crtc_id, + uint32_t framebuffer, + std::vector<uint32_t> connectors, + drmModeModeInfo* mode) { + DCHECK(file_.IsValid()); + DCHECK(!connectors.empty()); + DCHECK(mode); + + TRACE_EVENT2("dri", "DrmDevice::SetCrtc", "crtc", crtc_id, "size", + gfx::Size(mode->hdisplay, mode->vdisplay).ToString()); + return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0, + vector_as_array(&connectors), connectors.size(), mode); +} + +bool DrmDevice::SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) { + DCHECK(file_.IsValid()); + // If there's no buffer then the CRTC was disabled. + if (!crtc->buffer_id) + return DisableCrtc(crtc->crtc_id); + + DCHECK(!connectors.empty()); + + TRACE_EVENT1("dri", "DrmDevice::RestoreCrtc", "crtc", crtc->crtc_id); + return !drmModeSetCrtc(file_.GetPlatformFile(), crtc->crtc_id, + crtc->buffer_id, crtc->x, crtc->y, + vector_as_array(&connectors), connectors.size(), + &crtc->mode); +} + +bool DrmDevice::DisableCrtc(uint32_t crtc_id) { + DCHECK(file_.IsValid()); + TRACE_EVENT1("dri", "DrmDevice::DisableCrtc", "crtc", crtc_id); + return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, 0, 0, 0, NULL, 0, + NULL); +} + +ScopedDrmConnectorPtr DrmDevice::GetConnector(uint32_t connector_id) { + DCHECK(file_.IsValid()); + TRACE_EVENT1("dri", "DrmDevice::GetConnector", "connector", connector_id); + return ScopedDrmConnectorPtr( + drmModeGetConnector(file_.GetPlatformFile(), connector_id)); +} + +bool DrmDevice::AddFramebuffer(uint32_t width, + uint32_t height, + uint8_t depth, + uint8_t bpp, + uint32_t stride, + uint32_t handle, + uint32_t* framebuffer) { + DCHECK(file_.IsValid()); + TRACE_EVENT1("dri", "DrmDevice::AddFramebuffer", "handle", handle); + return !drmModeAddFB(file_.GetPlatformFile(), width, height, depth, bpp, + stride, handle, framebuffer); +} + +bool DrmDevice::RemoveFramebuffer(uint32_t framebuffer) { + DCHECK(file_.IsValid()); + TRACE_EVENT1("dri", "DrmDevice::RemoveFramebuffer", "framebuffer", + framebuffer); + return !drmModeRmFB(file_.GetPlatformFile(), framebuffer); +} + +bool DrmDevice::PageFlip(uint32_t crtc_id, + uint32_t framebuffer, + bool is_sync, + const PageFlipCallback& callback) { + DCHECK(file_.IsValid()); + TRACE_EVENT2("dri", "DrmDevice::PageFlip", "crtc", crtc_id, "framebuffer", + framebuffer); + + if (watcher_) + watcher_->SetPaused(is_sync); + + // NOTE: Calling drmModeSetCrtc will immediately update the state, though + // callbacks to already scheduled page flips will be honored by the kernel. + scoped_ptr<PageFlipPayload> payload( + new PageFlipPayload(base::ThreadTaskRunnerHandle::Get(), callback)); + if (!drmModePageFlip(file_.GetPlatformFile(), crtc_id, framebuffer, + DRM_MODE_PAGE_FLIP_EVENT, payload.get())) { + // If successful the payload will be removed by a PageFlip event. + ignore_result(payload.release()); + + // If the flip was requested synchronous or if no watcher has been installed + // yet, then synchronously handle the page flip events. + if (is_sync || !watcher_) { + TRACE_EVENT1("dri", "OnDrmEvent", "socket", file_.GetPlatformFile()); + + drmEventContext event; + event.version = DRM_EVENT_CONTEXT_VERSION; + event.page_flip_handler = HandlePageFlipEventOnUI; + event.vblank_handler = nullptr; + + drmHandleEvent(file_.GetPlatformFile(), &event); + } + + return true; + } + + return false; +} + +bool DrmDevice::PageFlipOverlay(uint32_t crtc_id, + uint32_t framebuffer, + const gfx::Rect& location, + const gfx::Rect& source, + int overlay_plane) { + DCHECK(file_.IsValid()); + TRACE_EVENT2("dri", "DrmDevice::PageFlipOverlay", "crtc", crtc_id, + "framebuffer", framebuffer); + return !drmModeSetPlane(file_.GetPlatformFile(), overlay_plane, crtc_id, + framebuffer, 0, location.x(), location.y(), + location.width(), location.height(), source.x(), + source.y(), source.width(), source.height()); +} + +ScopedDrmFramebufferPtr DrmDevice::GetFramebuffer(uint32_t framebuffer) { + DCHECK(file_.IsValid()); + TRACE_EVENT1("dri", "DrmDevice::GetFramebuffer", "framebuffer", framebuffer); + return ScopedDrmFramebufferPtr( + drmModeGetFB(file_.GetPlatformFile(), framebuffer)); +} + +ScopedDrmPropertyPtr DrmDevice::GetProperty(drmModeConnector* connector, + const char* name) { + TRACE_EVENT2("dri", "DrmDevice::GetProperty", "connector", + connector->connector_id, "name", name); + for (int i = 0; i < connector->count_props; ++i) { + ScopedDrmPropertyPtr property( + drmModeGetProperty(file_.GetPlatformFile(), connector->props[i])); + if (!property) + continue; + + if (strcmp(property->name, name) == 0) + return property.Pass(); + } + + return ScopedDrmPropertyPtr(); +} + +bool DrmDevice::SetProperty(uint32_t connector_id, + uint32_t property_id, + uint64_t value) { + DCHECK(file_.IsValid()); + return !drmModeConnectorSetProperty(file_.GetPlatformFile(), connector_id, + property_id, value); +} + +bool DrmDevice::GetCapability(uint64_t capability, uint64_t* value) { + DCHECK(file_.IsValid()); + return !drmGetCap(file_.GetPlatformFile(), capability, value); +} + +ScopedDrmPropertyBlobPtr DrmDevice::GetPropertyBlob(drmModeConnector* connector, + const char* name) { + DCHECK(file_.IsValid()); + TRACE_EVENT2("dri", "DrmDevice::GetPropertyBlob", "connector", + connector->connector_id, "name", name); + for (int i = 0; i < connector->count_props; ++i) { + ScopedDrmPropertyPtr property( + drmModeGetProperty(file_.GetPlatformFile(), connector->props[i])); + if (!property) + continue; + + if (strcmp(property->name, name) == 0 && + property->flags & DRM_MODE_PROP_BLOB) + return ScopedDrmPropertyBlobPtr(drmModeGetPropertyBlob( + file_.GetPlatformFile(), connector->prop_values[i])); + } + + return ScopedDrmPropertyBlobPtr(); +} + +bool DrmDevice::SetCursor(uint32_t crtc_id, + uint32_t handle, + const gfx::Size& size) { + DCHECK(file_.IsValid()); + TRACE_EVENT1("dri", "DrmDevice::SetCursor", "handle", handle); + return !drmModeSetCursor(file_.GetPlatformFile(), crtc_id, handle, + size.width(), size.height()); +} + +bool DrmDevice::MoveCursor(uint32_t crtc_id, const gfx::Point& point) { + DCHECK(file_.IsValid()); + return !drmModeMoveCursor(file_.GetPlatformFile(), crtc_id, point.x(), + point.y()); +} + +bool DrmDevice::CreateDumbBuffer(const SkImageInfo& info, + uint32_t* handle, + uint32_t* stride, + void** pixels) { + DCHECK(file_.IsValid()); + + TRACE_EVENT0("dri", "DrmDevice::CreateDumbBuffer"); + if (!DrmCreateDumbBuffer(file_.GetPlatformFile(), info, handle, stride)) + return false; + + if (!MapDumbBuffer(file_.GetPlatformFile(), *handle, + info.getSafeSize(*stride), pixels)) { + DrmDestroyDumbBuffer(file_.GetPlatformFile(), *handle); + return false; + } + + return true; +} + +void DrmDevice::DestroyDumbBuffer(const SkImageInfo& info, + uint32_t handle, + uint32_t stride, + void* pixels) { + DCHECK(file_.IsValid()); + TRACE_EVENT1("dri", "DrmDevice::DestroyDumbBuffer", "handle", handle); + munmap(pixels, info.getSafeSize(stride)); + DrmDestroyDumbBuffer(file_.GetPlatformFile(), handle); +} + +bool DrmDevice::SetMaster() { + DCHECK(file_.IsValid()); + return (drmSetMaster(file_.GetPlatformFile()) == 0); +} + +bool DrmDevice::DropMaster() { + DCHECK(file_.IsValid()); + return (drmDropMaster(file_.GetPlatformFile()) == 0); +} + +} // namespace ui
diff --git a/ui/ozone/platform/dri/drm_device.h b/ui/ozone/platform/dri/drm_device.h new file mode 100644 index 0000000..73b42bc --- /dev/null +++ b/ui/ozone/platform/dri/drm_device.h
@@ -0,0 +1,194 @@ +// 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_DRI_DRM_DEVICE_H_ +#define UI_OZONE_PLATFORM_DRI_DRM_DEVICE_H_ + +#include <stdint.h> + +#include <vector> + +#include "base/callback.h" +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_vector.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/overlay_transform.h" +#include "ui/ozone/ozone_export.h" +#include "ui/ozone/platform/dri/hardware_display_plane_manager.h" +#include "ui/ozone/platform/dri/scoped_drm_types.h" + +typedef struct _drmEventContext drmEventContext; +typedef struct _drmModeModeInfo drmModeModeInfo; + +struct SkImageInfo; + +namespace base { +class SingleThreadTaskRunner; +} // namespace base + +namespace ui { + +class HardwareDisplayPlaneManager; + +// Wraps DRM calls into a nice interface. Used to provide different +// implementations of the DRM calls. For the actual implementation the DRM API +// would be called. In unit tests this interface would be stubbed. +class OZONE_EXPORT DrmDevice : public base::RefCountedThreadSafe<DrmDevice> { + public: + typedef base::Callback<void(unsigned int /* frame */, + unsigned int /* seconds */, + unsigned int /* useconds */)> PageFlipCallback; + + DrmDevice(const base::FilePath& device_path); + DrmDevice(const base::FilePath& device_path, base::File file); + + // Open device. + virtual bool Initialize(); + + // |task_runner| will be used to asynchronously page flip. + virtual void InitializeTaskRunner( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); + + // Get the CRTC state. This is generally used to save state before using the + // CRTC. When the user finishes using the CRTC, the user should restore the + // CRTC to it's initial state. Use |SetCrtc| to restore the state. + virtual ScopedDrmCrtcPtr GetCrtc(uint32_t crtc_id); + + // Used to configure CRTC with ID |crtc_id| to use the connector in + // |connectors|. The CRTC will be configured with mode |mode| and will display + // the framebuffer with ID |framebuffer|. Before being able to display the + // framebuffer, it should be registered with the CRTC using |AddFramebuffer|. + virtual bool SetCrtc(uint32_t crtc_id, + uint32_t framebuffer, + std::vector<uint32_t> connectors, + drmModeModeInfo* mode); + + // Used to set a specific configuration to the CRTC. Normally this function + // would be called with a CRTC saved state (from |GetCrtc|) to restore it to + // its original configuration. + virtual bool SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors); + + virtual bool DisableCrtc(uint32_t crtc_id); + + // Returns the connector properties for |connector_id|. + virtual ScopedDrmConnectorPtr GetConnector(uint32_t connector_id); + + // Register a buffer with the CRTC. On successful registration, the CRTC will + // assign a framebuffer ID to |framebuffer|. + virtual bool AddFramebuffer(uint32_t width, + uint32_t height, + uint8_t depth, + uint8_t bpp, + uint32_t stride, + uint32_t handle, + uint32_t* framebuffer); + + // Deregister the given |framebuffer|. + virtual bool RemoveFramebuffer(uint32_t framebuffer); + + // Get the DRM details associated with |framebuffer|. + virtual ScopedDrmFramebufferPtr GetFramebuffer(uint32_t framebuffer); + + // Schedules a pageflip for CRTC |crtc_id|. This function will return + // immediately. Upon completion of the pageflip event, the CRTC will be + // displaying the buffer with ID |framebuffer| and will have a DRM event + // queued on |fd_|. + virtual bool PageFlip(uint32_t crtc_id, + uint32_t framebuffer, + bool is_sync, + const PageFlipCallback& callback); + + // Schedule an overlay to be show during the page flip for CRTC |crtc_id|. + // |source| location from |framebuffer| will be shown on overlay + // |overlay_plane|, in the bounds specified by |location| on the screen. + virtual bool PageFlipOverlay(uint32_t crtc_id, + uint32_t framebuffer, + const gfx::Rect& location, + const gfx::Rect& source, + int overlay_plane); + + // Returns the property with name |name| associated with |connector|. Returns + // NULL if property not found. If the returned value is valid, it must be + // released using FreeProperty(). + virtual ScopedDrmPropertyPtr GetProperty(drmModeConnector* connector, + const char* name); + + // Sets the value of property with ID |property_id| to |value|. The property + // is applied to the connector with ID |connector_id|. + virtual bool SetProperty(uint32_t connector_id, + uint32_t property_id, + uint64_t value); + + // Can be used to query device/driver |capability|. Sets the value of + // |capability to |value|. Returns true in case of a succesful query. + virtual bool GetCapability(uint64_t capability, uint64_t* value); + + // Return a binary blob associated with |connector|. The binary blob is + // associated with the property with name |name|. Return NULL if the property + // could not be found or if the property does not have a binary blob. If valid + // the returned object must be freed using FreePropertyBlob(). + virtual ScopedDrmPropertyBlobPtr GetPropertyBlob(drmModeConnector* connector, + const char* name); + + // Set the cursor to be displayed in CRTC |crtc_id|. (width, height) is the + // cursor size pointed by |handle|. + virtual bool SetCursor(uint32_t crtc_id, + uint32_t handle, + const gfx::Size& size); + + // Move the cursor on CRTC |crtc_id| to (x, y); + virtual bool MoveCursor(uint32_t crtc_id, const gfx::Point& point); + + virtual bool CreateDumbBuffer(const SkImageInfo& info, + uint32_t* handle, + uint32_t* stride, + void** pixels); + + virtual void DestroyDumbBuffer(const SkImageInfo& info, + uint32_t handle, + uint32_t stride, + void* pixels); + + // Drm master related + virtual bool SetMaster(); + virtual bool DropMaster(); + + int get_fd() const { return file_.GetPlatformFile(); } + + base::FilePath device_path() const { return device_path_; } + + HardwareDisplayPlaneManager* plane_manager() { return plane_manager_.get(); } + + protected: + friend class base::RefCountedThreadSafe<DrmDevice>; + + virtual ~DrmDevice(); + + scoped_ptr<HardwareDisplayPlaneManager> plane_manager_; + + private: + class IOWatcher; + + // Path to DRM device. + const base::FilePath device_path_; + + // DRM device. + base::File file_; + + // Helper thread to perform IO listener operations. + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + // Watcher for |fd_| listening for page flip events. + scoped_refptr<IOWatcher> watcher_; + + DISALLOW_COPY_AND_ASSIGN(DrmDevice); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRI_DRM_DEVICE_H_
diff --git a/ui/ozone/platform/dri/drm_device_generator.cc b/ui/ozone/platform/dri/drm_device_generator.cc index 13985db..f6f6f33 100644 --- a/ui/ozone/platform/dri/drm_device_generator.cc +++ b/ui/ozone/platform/dri/drm_device_generator.cc
@@ -4,7 +4,7 @@ #include "ui/ozone/platform/dri/drm_device_generator.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" namespace ui { @@ -14,10 +14,10 @@ DrmDeviceGenerator::~DrmDeviceGenerator() { } -scoped_refptr<DriWrapper> DrmDeviceGenerator::CreateDevice( +scoped_refptr<DrmDevice> DrmDeviceGenerator::CreateDevice( const base::FilePath& device_path, base::File file) { - scoped_refptr<DriWrapper> drm = new DriWrapper(device_path, file.Pass()); + scoped_refptr<DrmDevice> drm = new DrmDevice(device_path, file.Pass()); if (drm->Initialize()) return drm;
diff --git a/ui/ozone/platform/dri/drm_device_generator.h b/ui/ozone/platform/dri/drm_device_generator.h index acd25c02..8d59f72 100644 --- a/ui/ozone/platform/dri/drm_device_generator.h +++ b/ui/ozone/platform/dri/drm_device_generator.h
@@ -10,7 +10,7 @@ namespace ui { -class DriWrapper; +class DrmDevice; class DrmDeviceGenerator { public: @@ -19,7 +19,7 @@ // Creates a DRM device for |file|. |device_path| describes the location of // the DRM device. - virtual scoped_refptr<DriWrapper> CreateDevice( + virtual scoped_refptr<DrmDevice> CreateDevice( const base::FilePath& device_path, base::File file);
diff --git a/ui/ozone/platform/dri/drm_device_manager.cc b/ui/ozone/platform/dri/drm_device_manager.cc index 5bbfd94e..d04aee0 100644 --- a/ui/ozone/platform/dri/drm_device_manager.cc +++ b/ui/ozone/platform/dri/drm_device_manager.cc
@@ -4,12 +4,12 @@ #include "ui/ozone/platform/dri/drm_device_manager.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" namespace ui { DrmDeviceManager::DrmDeviceManager( - const scoped_refptr<DriWrapper>& primary_device) + const scoped_refptr<DrmDevice>& primary_device) : primary_device_(primary_device) { } @@ -17,9 +17,8 @@ DCHECK(drm_device_map_.empty()); } -void DrmDeviceManager::UpdateDrmDevice( - gfx::AcceleratedWidget widget, - const scoped_refptr<DriWrapper>& device) { +void DrmDeviceManager::UpdateDrmDevice(gfx::AcceleratedWidget widget, + const scoped_refptr<DrmDevice>& device) { base::AutoLock lock(lock_); drm_device_map_[widget] = device; } @@ -31,7 +30,7 @@ drm_device_map_.erase(it); } -scoped_refptr<DriWrapper> DrmDeviceManager::GetDrmDevice( +scoped_refptr<DrmDevice> DrmDeviceManager::GetDrmDevice( gfx::AcceleratedWidget widget) { base::AutoLock lock(lock_); if (widget == gfx::kNullAcceleratedWidget)
diff --git a/ui/ozone/platform/dri/drm_device_manager.h b/ui/ozone/platform/dri/drm_device_manager.h index 03133abb..5a7431e 100644 --- a/ui/ozone/platform/dri/drm_device_manager.h +++ b/ui/ozone/platform/dri/drm_device_manager.h
@@ -14,28 +14,28 @@ namespace ui { -class DriWrapper; +class DrmDevice; // Tracks the mapping between widgets and the DRM devices used to allocate // buffers for the window represented by the widget. class OZONE_EXPORT DrmDeviceManager { public: - DrmDeviceManager(const scoped_refptr<DriWrapper>& primary_device); + DrmDeviceManager(const scoped_refptr<DrmDevice>& primary_device); ~DrmDeviceManager(); // Updates the device associated with |widget|. void UpdateDrmDevice(gfx::AcceleratedWidget widget, - const scoped_refptr<DriWrapper>& device); + const scoped_refptr<DrmDevice>& device); // Removes the device associated with |widget|. void RemoveDrmDevice(gfx::AcceleratedWidget widget); // Returns the device associated with |widget|. If there is no association // returns |primary_device_|. - scoped_refptr<DriWrapper> GetDrmDevice(gfx::AcceleratedWidget widget); + scoped_refptr<DrmDevice> GetDrmDevice(gfx::AcceleratedWidget widget); private: - std::map<gfx::AcceleratedWidget, scoped_refptr<DriWrapper>> drm_device_map_; + std::map<gfx::AcceleratedWidget, scoped_refptr<DrmDevice>> drm_device_map_; // This device represents the primary graphics device and is used when: // 1) 'widget == kNullAcceleratedWidget' when the API requesting a buffer has @@ -43,7 +43,7 @@ // for video buffers), or // 2) in order to allocate buffers for unmatched surfaces (surfaces without a // display; ie: when in headless mode). - scoped_refptr<DriWrapper> primary_device_; + scoped_refptr<DrmDevice> primary_device_; // This class is accessed from the main thread and the IO thread. This lock // protects access to the device map.
diff --git a/ui/ozone/platform/dri/gbm.gypi b/ui/ozone/platform/dri/gbm.gypi index f59833b61..19d3a0d2 100644 --- a/ui/ozone/platform/dri/gbm.gypi +++ b/ui/ozone/platform/dri/gbm.gypi
@@ -37,14 +37,14 @@ 'gbm_buffer.h', 'gbm_buffer_base.cc', 'gbm_buffer_base.h', + 'gbm_device.cc', + 'gbm_device.h', 'gbm_surface.cc', 'gbm_surface.h', 'gbm_surface_factory.cc', 'gbm_surface_factory.h', 'gbm_surfaceless.cc', 'gbm_surfaceless.h', - 'gbm_wrapper.cc', - 'gbm_wrapper.h', 'ozone_platform_gbm.cc', 'ozone_platform_gbm.h', ],
diff --git a/ui/ozone/platform/dri/gbm_buffer.cc b/ui/ozone/platform/dri/gbm_buffer.cc index 371e9ab..30f0ad85 100644 --- a/ui/ozone/platform/dri/gbm_buffer.cc +++ b/ui/ozone/platform/dri/gbm_buffer.cc
@@ -11,7 +11,7 @@ #include "base/logging.h" #include "base/trace_event/trace_event.h" -#include "ui/ozone/platform/dri/gbm_wrapper.h" +#include "ui/ozone/platform/dri/gbm_device.h" namespace ui { @@ -31,7 +31,7 @@ } // namespace -GbmBuffer::GbmBuffer(const scoped_refptr<GbmWrapper>& gbm, +GbmBuffer::GbmBuffer(const scoped_refptr<GbmDevice>& gbm, gbm_bo* bo, bool scanout) : GbmBufferBase(gbm, bo, scanout) { @@ -44,7 +44,7 @@ // static scoped_refptr<GbmBuffer> GbmBuffer::CreateBuffer( - const scoped_refptr<GbmWrapper>& gbm, + const scoped_refptr<GbmDevice>& gbm, SurfaceFactoryOzone::BufferFormat format, const gfx::Size& size, bool scanout) {
diff --git a/ui/ozone/platform/dri/gbm_buffer.h b/ui/ozone/platform/dri/gbm_buffer.h index 2af83de..7e34068d1 100644 --- a/ui/ozone/platform/dri/gbm_buffer.h +++ b/ui/ozone/platform/dri/gbm_buffer.h
@@ -16,18 +16,18 @@ namespace ui { -class GbmWrapper; +class GbmDevice; class GbmBuffer : public GbmBufferBase { public: static scoped_refptr<GbmBuffer> CreateBuffer( - const scoped_refptr<GbmWrapper>& gbm, + const scoped_refptr<GbmDevice>& gbm, SurfaceFactoryOzone::BufferFormat format, const gfx::Size& size, bool scanout); private: - GbmBuffer(const scoped_refptr<GbmWrapper>& gbm, gbm_bo* bo, bool scanout); + GbmBuffer(const scoped_refptr<GbmDevice>& gbm, gbm_bo* bo, bool scanout); ~GbmBuffer() override; DISALLOW_COPY_AND_ASSIGN(GbmBuffer);
diff --git a/ui/ozone/platform/dri/gbm_buffer_base.cc b/ui/ozone/platform/dri/gbm_buffer_base.cc index c4b69ff..ca835e3 100644 --- a/ui/ozone/platform/dri/gbm_buffer_base.cc +++ b/ui/ozone/platform/dri/gbm_buffer_base.cc
@@ -7,7 +7,7 @@ #include <gbm.h> #include "base/logging.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" namespace ui { @@ -21,23 +21,20 @@ } // namespace -GbmBufferBase::GbmBufferBase(const scoped_refptr<DriWrapper>& dri, +GbmBufferBase::GbmBufferBase(const scoped_refptr<DrmDevice>& drm, gbm_bo* bo, bool scanout) - : dri_(dri), bo_(bo), framebuffer_(0) { - if (scanout && !dri_->AddFramebuffer(gbm_bo_get_width(bo), - gbm_bo_get_height(bo), - kColorDepth, - kPixelDepth, - gbm_bo_get_stride(bo), - gbm_bo_get_handle(bo).u32, - &framebuffer_)) + : drm_(drm), bo_(bo), framebuffer_(0) { + if (scanout && + !drm_->AddFramebuffer(gbm_bo_get_width(bo), gbm_bo_get_height(bo), + kColorDepth, kPixelDepth, gbm_bo_get_stride(bo), + gbm_bo_get_handle(bo).u32, &framebuffer_)) LOG(ERROR) << "Failed to register buffer"; } GbmBufferBase::~GbmBufferBase() { if (framebuffer_) - dri_->RemoveFramebuffer(framebuffer_); + drm_->RemoveFramebuffer(framebuffer_); } uint32_t GbmBufferBase::GetFramebufferId() const {
diff --git a/ui/ozone/platform/dri/gbm_buffer_base.h b/ui/ozone/platform/dri/gbm_buffer_base.h index 7f79f86..9152483 100644 --- a/ui/ozone/platform/dri/gbm_buffer_base.h +++ b/ui/ozone/platform/dri/gbm_buffer_base.h
@@ -11,7 +11,7 @@ namespace ui { -class DriWrapper; +class DrmDevice; // Wrapper for a GBM buffer. The base class provides common functionality // required to prepare the buffer for scanout. It does not provide any ownership @@ -27,11 +27,11 @@ gfx::Size GetSize() const override; protected: - GbmBufferBase(const scoped_refptr<DriWrapper>& dri, gbm_bo* bo, bool scanout); + GbmBufferBase(const scoped_refptr<DrmDevice>& drm, gbm_bo* bo, bool scanout); ~GbmBufferBase() override; private: - scoped_refptr<DriWrapper> dri_; + scoped_refptr<DrmDevice> drm_; gbm_bo* bo_; uint32_t framebuffer_;
diff --git a/ui/ozone/platform/dri/gbm_device.cc b/ui/ozone/platform/dri/gbm_device.cc new file mode 100644 index 0000000..e726c2f --- /dev/null +++ b/ui/ozone/platform/dri/gbm_device.cc
@@ -0,0 +1,37 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/ozone/platform/dri/gbm_device.h" + +#include <gbm.h> + +namespace ui { + +GbmDevice::GbmDevice(const base::FilePath& device_path) + : DrmDevice(device_path), device_(nullptr) { +} + +GbmDevice::GbmDevice(const base::FilePath& device_path, base::File file) + : DrmDevice(device_path, file.Pass()), device_(nullptr) { +} + +GbmDevice::~GbmDevice() { + if (device_) + gbm_device_destroy(device_); +} + +bool GbmDevice::Initialize() { + if (!DrmDevice::Initialize()) + return false; + + device_ = gbm_create_device(get_fd()); + if (!device_) { + LOG(ERROR) << "Unable to initialize GBM"; + return false; + } + + return true; +} + +} // namespace ui
diff --git a/ui/ozone/platform/dri/gbm_device.h b/ui/ozone/platform/dri/gbm_device.h new file mode 100644 index 0000000..7395bf88 --- /dev/null +++ b/ui/ozone/platform/dri/gbm_device.h
@@ -0,0 +1,34 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_OZONE_PLATFORM_DRI_GBM_DEVICE_H_ +#define UI_OZONE_PLATFORM_DRI_GBM_DEVICE_H_ + +#include "ui/ozone/platform/dri/drm_device.h" + +struct gbm_device; + +namespace ui { + +class GbmDevice : public DrmDevice { + public: + GbmDevice(const base::FilePath& device_path); + GbmDevice(const base::FilePath& device_path, base::File file); + + gbm_device* device() const { return device_; } + + // DrmDevice implementation: + bool Initialize() override; + + private: + ~GbmDevice() override; + + gbm_device* device_; + + DISALLOW_COPY_AND_ASSIGN(GbmDevice); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRI_GBM_DEVICE_H_
diff --git a/ui/ozone/platform/dri/gbm_surface.cc b/ui/ozone/platform/dri/gbm_surface.cc index e3b6252..ab8e5e3 100644 --- a/ui/ozone/platform/dri/gbm_surface.cc +++ b/ui/ozone/platform/dri/gbm_surface.cc
@@ -11,7 +11,7 @@ #include "ui/ozone/platform/dri/dri_buffer.h" #include "ui/ozone/platform/dri/dri_window_delegate.h" #include "ui/ozone/platform/dri/gbm_buffer_base.h" -#include "ui/ozone/platform/dri/gbm_wrapper.h" +#include "ui/ozone/platform/dri/gbm_device.h" #include "ui/ozone/platform/dri/hardware_display_controller.h" #include "ui/ozone/platform/dri/scanout_buffer.h" @@ -22,12 +22,12 @@ class GbmSurfaceBuffer : public GbmBufferBase { public: static scoped_refptr<GbmSurfaceBuffer> CreateBuffer( - const scoped_refptr<DriWrapper>& dri, + const scoped_refptr<DrmDevice>& drm, gbm_bo* buffer); static scoped_refptr<GbmSurfaceBuffer> GetBuffer(gbm_bo* buffer); private: - GbmSurfaceBuffer(const scoped_refptr<DriWrapper>& dri, gbm_bo* bo); + GbmSurfaceBuffer(const scoped_refptr<DrmDevice>& drm, gbm_bo* bo); ~GbmSurfaceBuffer() override; static void Destroy(gbm_bo* buffer, void* data); @@ -42,9 +42,9 @@ DISALLOW_COPY_AND_ASSIGN(GbmSurfaceBuffer); }; -GbmSurfaceBuffer::GbmSurfaceBuffer(const scoped_refptr<DriWrapper>& dri, +GbmSurfaceBuffer::GbmSurfaceBuffer(const scoped_refptr<DrmDevice>& drm, gbm_bo* bo) - : GbmBufferBase(dri, bo, true) { + : GbmBufferBase(drm, bo, true) { if (GetFramebufferId()) { self_ = this; gbm_bo_set_user_data(bo, this, GbmSurfaceBuffer::Destroy); @@ -55,10 +55,10 @@ // static scoped_refptr<GbmSurfaceBuffer> GbmSurfaceBuffer::CreateBuffer( - const scoped_refptr<DriWrapper>& dri, + const scoped_refptr<DrmDevice>& drm, gbm_bo* buffer) { - scoped_refptr<GbmSurfaceBuffer> scoped_buffer(new GbmSurfaceBuffer(dri, - buffer)); + scoped_refptr<GbmSurfaceBuffer> scoped_buffer( + new GbmSurfaceBuffer(drm, buffer)); if (!scoped_buffer->GetFramebufferId()) return NULL; @@ -80,7 +80,7 @@ } // namespace GbmSurface::GbmSurface(DriWindowDelegate* window_delegate, - const scoped_refptr<GbmWrapper>& gbm) + const scoped_refptr<GbmDevice>& gbm) : GbmSurfaceless(window_delegate, NULL), gbm_(gbm), native_surface_(NULL),
diff --git a/ui/ozone/platform/dri/gbm_surface.h b/ui/ozone/platform/dri/gbm_surface.h index e0e3c47..c549d9a 100644 --- a/ui/ozone/platform/dri/gbm_surface.h +++ b/ui/ozone/platform/dri/gbm_surface.h
@@ -18,7 +18,7 @@ class DriBuffer; class DriWindowDelegate; -class GbmWrapper; +class GbmDevice; // Extends the GBM surfaceless functionality and adds an implicit surface for // the primary plane. Arbitrary buffers can still be allocated and displayed as @@ -27,7 +27,7 @@ class GbmSurface : public GbmSurfaceless { public: GbmSurface(DriWindowDelegate* window_delegate, - const scoped_refptr<GbmWrapper>& gbm); + const scoped_refptr<GbmDevice>& gbm); ~GbmSurface() override; bool Initialize(); @@ -42,7 +42,7 @@ void OnSwapBuffersCallback(const SwapCompletionCallback& callback, gbm_bo* pending_buffer); - scoped_refptr<GbmWrapper> gbm_; + scoped_refptr<GbmDevice> gbm_; // The native GBM surface. In EGL this represents the EGLNativeWindowType. gbm_surface* native_surface_;
diff --git a/ui/ozone/platform/dri/gbm_surface_factory.cc b/ui/ozone/platform/dri/gbm_surface_factory.cc index 2017535..25c0914 100644 --- a/ui/ozone/platform/dri/gbm_surface_factory.cc +++ b/ui/ozone/platform/dri/gbm_surface_factory.cc
@@ -10,17 +10,18 @@ #include "base/files/file_path.h" #include "third_party/khronos/EGL/egl.h" #include "ui/ozone/common/egl_util.h" -#include "ui/ozone/platform/dri/dri_window_delegate_impl.h" +#include "ui/ozone/platform/dri/dri_window_delegate.h" #include "ui/ozone/platform/dri/dri_window_delegate_manager.h" #include "ui/ozone/platform/dri/drm_device_manager.h" #include "ui/ozone/platform/dri/gbm_buffer.h" +#include "ui/ozone/platform/dri/gbm_device.h" #include "ui/ozone/platform/dri/gbm_surface.h" #include "ui/ozone/platform/dri/gbm_surfaceless.h" -#include "ui/ozone/platform/dri/gbm_wrapper.h" #include "ui/ozone/platform/dri/hardware_display_controller.h" #include "ui/ozone/public/native_pixmap.h" #include "ui/ozone/public/overlay_candidates_ozone.h" #include "ui/ozone/public/ozone_switches.h" +#include "ui/ozone/public/surface_ozone_canvas.h" #include "ui/ozone/public/surface_ozone_egl.h" namespace ui { @@ -85,14 +86,14 @@ #if defined(USE_MESA_PLATFORM_NULL) return EGL_DEFAULT_DISPLAY; #else - scoped_refptr<GbmWrapper> gbm = GetGbmDevice(gfx::kNullAcceleratedWidget); + scoped_refptr<GbmDevice> gbm = GetGbmDevice(gfx::kNullAcceleratedWidget); DCHECK(gbm); return reinterpret_cast<intptr_t>(gbm->device()); #endif } int GbmSurfaceFactory::GetDrmFd() { - scoped_refptr<GbmWrapper> gbm = GetGbmDevice(gfx::kNullAcceleratedWidget); + scoped_refptr<GbmDevice> gbm = GetGbmDevice(gfx::kNullAcceleratedWidget); DCHECK(gbm); return gbm->get_fd(); } @@ -119,9 +120,15 @@ return LoadDefaultEGLGLES2Bindings(add_gl_library, set_gl_get_proc_address); } +scoped_ptr<SurfaceOzoneCanvas> GbmSurfaceFactory::CreateCanvasForWidget( + gfx::AcceleratedWidget widget) { + LOG(FATAL) << "Software rendering mode is not supported with GBM platform"; + return nullptr; +} + scoped_ptr<SurfaceOzoneEGL> GbmSurfaceFactory::CreateEGLSurfaceForWidget( gfx::AcceleratedWidget widget) { - scoped_refptr<GbmWrapper> gbm = GetGbmDevice(widget); + scoped_refptr<GbmDevice> gbm = GetGbmDevice(widget); DCHECK(gbm); scoped_ptr<GbmSurface> surface( @@ -150,7 +157,7 @@ if (usage == MAP) return nullptr; - scoped_refptr<GbmWrapper> gbm = GetGbmDevice(widget); + scoped_refptr<GbmDevice> gbm = GetGbmDevice(widget); DCHECK(gbm); scoped_refptr<GbmBuffer> buffer = @@ -213,9 +220,9 @@ return false; } -scoped_refptr<GbmWrapper> GbmSurfaceFactory::GetGbmDevice( +scoped_refptr<GbmDevice> GbmSurfaceFactory::GetGbmDevice( gfx::AcceleratedWidget widget) { - return static_cast<GbmWrapper*>( + return static_cast<GbmDevice*>( drm_device_manager_->GetDrmDevice(widget).get()); }
diff --git a/ui/ozone/platform/dri/gbm_surface_factory.h b/ui/ozone/platform/dri/gbm_surface_factory.h index 1b913c0..7b10b08 100644 --- a/ui/ozone/platform/dri/gbm_surface_factory.h +++ b/ui/ozone/platform/dri/gbm_surface_factory.h
@@ -12,7 +12,7 @@ class DriWindowDelegate; class DriWindowDelegateManager; class DrmDeviceManager; -class GbmWrapper; +class GbmDevice; class GbmSurfaceFactory : public DriSurfaceFactory { public: @@ -29,6 +29,8 @@ bool LoadEGLGLES2Bindings( AddGLLibraryCallback add_gl_library, SetGLGetProcAddressProcCallback set_gl_get_proc_address) override; + scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget( + gfx::AcceleratedWidget widget) override; scoped_ptr<ui::SurfaceOzoneEGL> CreateEGLSurfaceForWidget( gfx::AcceleratedWidget w) override; scoped_ptr<SurfaceOzoneEGL> CreateSurfacelessEGLSurfaceForWidget( @@ -50,7 +52,7 @@ bool CanCreateNativePixmap(BufferUsage usage) override; private: - scoped_refptr<GbmWrapper> GetGbmDevice(gfx::AcceleratedWidget widget); + scoped_refptr<GbmDevice> GetGbmDevice(gfx::AcceleratedWidget widget); bool allow_surfaceless_;
diff --git a/ui/ozone/platform/dri/gbm_surfaceless.cc b/ui/ozone/platform/dri/gbm_surfaceless.cc index 6745a20..30e18e7 100644 --- a/ui/ozone/platform/dri/gbm_surfaceless.cc +++ b/ui/ozone/platform/dri/gbm_surfaceless.cc
@@ -8,7 +8,7 @@ #include "base/bind_helpers.h" #include "ui/ozone/platform/dri/dri_vsync_provider.h" #include "ui/ozone/platform/dri/dri_window_delegate.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/platform/dri/drm_device_manager.h" #include "ui/ozone/platform/dri/gbm_buffer.h" #include "ui/ozone/platform/dri/hardware_display_controller.h" @@ -59,14 +59,14 @@ bool GbmSurfaceless::IsUniversalDisplayLinkDevice() { if (!drm_device_manager_) return false; - scoped_refptr<DriWrapper> drm_primary = + scoped_refptr<DrmDevice> drm_primary = drm_device_manager_->GetDrmDevice(gfx::kNullAcceleratedWidget); DCHECK(drm_primary); HardwareDisplayController* controller = window_delegate_->GetController(); if (!controller) return false; - scoped_refptr<DriWrapper> drm = controller->GetAllocationDriWrapper(); + scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice(); DCHECK(drm); return drm_primary != drm;
diff --git a/ui/ozone/platform/dri/gbm_wrapper.cc b/ui/ozone/platform/dri/gbm_wrapper.cc deleted file mode 100644 index e0d1f17..0000000 --- a/ui/ozone/platform/dri/gbm_wrapper.cc +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/ozone/platform/dri/gbm_wrapper.h" - -#include <gbm.h> - -namespace ui { - -GbmWrapper::GbmWrapper(const base::FilePath& device_path) - : DriWrapper(device_path), device_(nullptr) { -} - -GbmWrapper::GbmWrapper(const base::FilePath& device_path, base::File file) - : DriWrapper(device_path, file.Pass()), device_(nullptr) { -} - -GbmWrapper::~GbmWrapper() { - if (device_) - gbm_device_destroy(device_); -} - -bool GbmWrapper::Initialize() { - if (!DriWrapper::Initialize()) - return false; - - device_ = gbm_create_device(get_fd()); - if (!device_) { - LOG(ERROR) << "Unable to initialize GBM"; - return false; - } - - return true; -} - -} // namespace ui
diff --git a/ui/ozone/platform/dri/gbm_wrapper.h b/ui/ozone/platform/dri/gbm_wrapper.h deleted file mode 100644 index 3df2550..0000000 --- a/ui/ozone/platform/dri/gbm_wrapper.h +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_OZONE_PLATFORM_DRI_GBM_WRAPPER_H_ -#define UI_OZONE_PLATFORM_DRI_GBM_WRAPPER_H_ - -#include "ui/ozone/platform/dri/dri_wrapper.h" - -struct gbm_device; - -namespace ui { - -class GbmWrapper : public DriWrapper { - public: - GbmWrapper(const base::FilePath& device_path); - GbmWrapper(const base::FilePath& device_path, base::File file); - - gbm_device* device() const { return device_; } - - // DriWrapper implementation: - bool Initialize() override; - - private: - ~GbmWrapper() override; - - gbm_device* device_; - - DISALLOW_COPY_AND_ASSIGN(GbmWrapper); -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_DRI_GBM_WRAPPER_H_
diff --git a/ui/ozone/platform/dri/hardware_display_controller.cc b/ui/ozone/platform/dri/hardware_display_controller.cc index faee6e6..0615067 100644 --- a/ui/ozone/platform/dri/hardware_display_controller.cc +++ b/ui/ozone/platform/dri/hardware_display_controller.cc
@@ -17,7 +17,7 @@ #include "ui/gfx/geometry/size.h" #include "ui/ozone/platform/dri/crtc_controller.h" #include "ui/ozone/platform/dri/dri_buffer.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/public/native_pixmap.h" namespace ui { @@ -157,7 +157,7 @@ } scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( - const scoped_refptr<DriWrapper>& drm, + const scoped_refptr<DrmDevice>& drm, uint32_t crtc) { for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin(); it != crtc_controllers_.end(); ++it) { @@ -191,7 +191,7 @@ return nullptr; } -bool HardwareDisplayController::HasCrtc(const scoped_refptr<DriWrapper>& drm, +bool HardwareDisplayController::HasCrtc(const scoped_refptr<DrmDevice>& drm, uint32_t crtc) const { for (size_t i = 0; i < crtc_controllers_.size(); ++i) if (crtc_controllers_[i]->drm() == drm && @@ -260,7 +260,7 @@ } } -scoped_refptr<DriWrapper> HardwareDisplayController::GetAllocationDriWrapper() +scoped_refptr<DrmDevice> HardwareDisplayController::GetAllocationDrmDevice() const { DCHECK(!crtc_controllers_.empty()); // TODO(dnicoara) When we support mirroring across DRM devices, figure out
diff --git a/ui/ozone/platform/dri/hardware_display_controller.h b/ui/ozone/platform/dri/hardware_display_controller.h index 7f015a5..e32ba63 100644 --- a/ui/ozone/platform/dri/hardware_display_controller.h +++ b/ui/ozone/platform/dri/hardware_display_controller.h
@@ -31,7 +31,7 @@ class CrtcController; class ScanoutBuffer; -class DriWrapper; +class DrmDevice; // The HDCOz will handle modesettings and scannout operations for hardware // devices. @@ -134,9 +134,9 @@ bool MoveCursor(const gfx::Point& location); void AddCrtc(scoped_ptr<CrtcController> controller); - scoped_ptr<CrtcController> RemoveCrtc(const scoped_refptr<DriWrapper>& drm, + scoped_ptr<CrtcController> RemoveCrtc(const scoped_refptr<DrmDevice>& drm, uint32_t crtc); - bool HasCrtc(const scoped_refptr<DriWrapper>& drm, uint32_t crtc) const; + bool HasCrtc(const scoped_refptr<DrmDevice>& drm, uint32_t crtc) const; bool IsMirrored() const; bool IsDisabled() const; gfx::Size GetModeSize() const; @@ -152,7 +152,7 @@ return crtc_controllers_.get(); } - scoped_refptr<DriWrapper> GetAllocationDriWrapper() const; + scoped_refptr<DrmDevice> GetAllocationDrmDevice() const; private: // Returns true if any of the CRTCs is waiting for a page flip. @@ -185,7 +185,7 @@ std::deque<PageFlipRequest> requests_; scoped_refptr<ScanoutBuffer> cursor_buffer_; - base::ScopedPtrHashMap<DriWrapper*, HardwareDisplayPlaneList> + base::ScopedPtrHashMap<DrmDevice*, HardwareDisplayPlaneList> owned_hardware_planes_; // Stores the CRTC configuration. This is used to identify monitors and
diff --git a/ui/ozone/platform/dri/hardware_display_controller_unittest.cc b/ui/ozone/platform/dri/hardware_display_controller_unittest.cc index 6a20ac121..f63c136 100644 --- a/ui/ozone/platform/dri/hardware_display_controller_unittest.cc +++ b/ui/ozone/platform/dri/hardware_display_controller_unittest.cc
@@ -7,9 +7,9 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "ui/ozone/platform/dri/crtc_controller.h" #include "ui/ozone/platform/dri/dri_buffer.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/platform/dri/hardware_display_controller.h" -#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h" +#include "ui/ozone/platform/dri/test/mock_drm_device.h" #include "ui/ozone/public/native_pixmap.h" namespace { @@ -58,7 +58,7 @@ protected: scoped_ptr<ui::HardwareDisplayController> controller_; - scoped_refptr<ui::MockDriWrapper> drm_; + scoped_refptr<ui::MockDrmDevice> drm_; int page_flips_; @@ -70,7 +70,7 @@ std::vector<uint32_t> crtcs; crtcs.push_back(kPrimaryCrtc); crtcs.push_back(kSecondaryCrtc); - drm_ = new ui::MockDriWrapper(false, crtcs, kPlanesPerCrtc); + drm_ = new ui::MockDrmDevice(false, crtcs, kPlanesPerCrtc); controller_.reset(new ui::HardwareDisplayController( scoped_ptr<ui::CrtcController>(new ui::CrtcController( drm_.get(), kPrimaryCrtc, kPrimaryConnector))));
diff --git a/ui/ozone/platform/dri/hardware_display_plane.cc b/ui/ozone/platform/dri/hardware_display_plane.cc index 89bc882..cb50c6c 100644 --- a/ui/ozone/platform/dri/hardware_display_plane.cc +++ b/ui/ozone/platform/dri/hardware_display_plane.cc
@@ -10,7 +10,7 @@ #include "base/logging.h" #include "ui/gfx/geometry/rect.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" namespace ui { @@ -33,7 +33,7 @@ return possible_crtcs_ & (1 << crtc_index); } -bool HardwareDisplayPlane::Initialize(DriWrapper* drm) { +bool HardwareDisplayPlane::Initialize(DrmDevice* drm) { return true; }
diff --git a/ui/ozone/platform/dri/hardware_display_plane.h b/ui/ozone/platform/dri/hardware_display_plane.h index e8589317..2fffae4 100644 --- a/ui/ozone/platform/dri/hardware_display_plane.h +++ b/ui/ozone/platform/dri/hardware_display_plane.h
@@ -18,7 +18,7 @@ namespace ui { -class DriWrapper; +class DrmDevice; class OZONE_EXPORT HardwareDisplayPlane { public: @@ -27,7 +27,7 @@ virtual ~HardwareDisplayPlane(); - bool Initialize(DriWrapper* drm); + bool Initialize(DrmDevice* drm); bool CanUseForCrtc(uint32_t crtc_index);
diff --git a/ui/ozone/platform/dri/hardware_display_plane_manager.cc b/ui/ozone/platform/dri/hardware_display_plane_manager.cc index 2a8b7cc..0c0b321c 100644 --- a/ui/ozone/platform/dri/hardware_display_plane_manager.cc +++ b/ui/ozone/platform/dri/hardware_display_plane_manager.cc
@@ -11,7 +11,7 @@ #include "base/logging.h" #include "ui/gfx/geometry/rect.h" #include "ui/ozone/platform/dri/crtc_controller.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/platform/dri/hardware_display_controller.h" #include "ui/ozone/platform/dri/scanout_buffer.h" #include "ui/ozone/public/ozone_switches.h" @@ -65,7 +65,7 @@ HardwareDisplayPlaneManager::~HardwareDisplayPlaneManager() { } -bool HardwareDisplayPlaneManager::Initialize(DriWrapper* drm) { +bool HardwareDisplayPlaneManager::Initialize(DrmDevice* drm) { drm_ = drm; ScopedDrmResourcesPtr resources(drmModeGetResources(drm->get_fd())); if (!resources) {
diff --git a/ui/ozone/platform/dri/hardware_display_plane_manager.h b/ui/ozone/platform/dri/hardware_display_plane_manager.h index d25b7d5f..49593e0 100644 --- a/ui/ozone/platform/dri/hardware_display_plane_manager.h +++ b/ui/ozone/platform/dri/hardware_display_plane_manager.h
@@ -23,7 +23,7 @@ namespace ui { -class DriWrapper; +class DrmDevice; class CrtcController; // This contains the list of planes controlled by one HDC on a given DRM fd. @@ -77,7 +77,7 @@ // This parses information from the drm driver, adding any new planes // or crtcs found. - bool Initialize(DriWrapper* drm); + bool Initialize(DrmDevice* drm); // Assign hardware planes from the |planes_| list to |overlay_list| entries, // recording the plane IDs in the |plane_list|. Only planes compatible with @@ -112,7 +112,7 @@ // Object containing the connection to the graphics device and wraps the API // calls to control it. Not owned. - DriWrapper* drm_; + DrmDevice* drm_; ScopedVector<HardwareDisplayPlane> planes_; std::vector<uint32_t> crtcs_;
diff --git a/ui/ozone/platform/dri/hardware_display_plane_manager_legacy.cc b/ui/ozone/platform/dri/hardware_display_plane_manager_legacy.cc index 3853ff5..b41f456 100644 --- a/ui/ozone/platform/dri/hardware_display_plane_manager_legacy.cc +++ b/ui/ozone/platform/dri/hardware_display_plane_manager_legacy.cc
@@ -6,7 +6,7 @@ #include "base/bind.h" #include "ui/ozone/platform/dri/crtc_controller.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/platform/dri/scanout_buffer.h" namespace ui {
diff --git a/ui/ozone/platform/dri/hardware_display_plane_manager_unittest.cc b/ui/ozone/platform/dri/hardware_display_plane_manager_unittest.cc index 7e5dade..5ee02543 100644 --- a/ui/ozone/platform/dri/hardware_display_plane_manager_unittest.cc +++ b/ui/ozone/platform/dri/hardware_display_plane_manager_unittest.cc
@@ -13,7 +13,7 @@ #include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h" #include "ui/ozone/platform/dri/overlay_plane.h" #include "ui/ozone/platform/dri/scanout_buffer.h" -#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h" +#include "ui/ozone/platform/dri/test/mock_drm_device.h" namespace { @@ -232,8 +232,7 @@ TEST(HardwareDisplayPlaneManagerLegacyTest, UnusedPlanesAreReleased) { std::vector<uint32_t> crtcs; crtcs.push_back(100); - scoped_refptr<ui::MockDriWrapper> drm = - new ui::MockDriWrapper(false, crtcs, 2); + scoped_refptr<ui::MockDrmDevice> drm = new ui::MockDrmDevice(false, crtcs, 2); ui::OverlayPlaneList assigns; scoped_refptr<FakeScanoutBuffer> fake_buffer = new FakeScanoutBuffer(); assigns.push_back(ui::OverlayPlane(fake_buffer));
diff --git a/ui/ozone/platform/dri/native_display_delegate_dri.cc b/ui/ozone/platform/dri/native_display_delegate_dri.cc index af18bb59..b6dedffda 100644 --- a/ui/ozone/platform/dri/native_display_delegate_dri.cc +++ b/ui/ozone/platform/dri/native_display_delegate_dri.cc
@@ -15,7 +15,7 @@ #include "ui/ozone/platform/dri/display_mode_dri.h" #include "ui/ozone/platform/dri/display_snapshot_dri.h" #include "ui/ozone/platform/dri/dri_util.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/platform/dri/drm_device_generator.h" #include "ui/ozone/platform/dri/screen_manager.h" #include "ui/ozone/public/ozone_switches.h" @@ -61,7 +61,7 @@ crtc_(snapshot->crtc()), connector_(snapshot->connector()) {} - DisplaySnapshotComparator(const scoped_refptr<DriWrapper>& drm, + DisplaySnapshotComparator(const scoped_refptr<DrmDevice>& drm, uint32_t crtc, uint32_t connector) : drm_(drm), crtc_(crtc), connector_(connector) {} @@ -72,7 +72,7 @@ } private: - scoped_refptr<DriWrapper> drm_; + scoped_refptr<DrmDevice> drm_; uint32_t crtc_; uint32_t connector_; }; @@ -81,7 +81,7 @@ public: explicit FindByDevicePath(const base::FilePath& path) : path_(path) {} - bool operator()(const scoped_refptr<DriWrapper>& device) { + bool operator()(const scoped_refptr<DrmDevice>& device) { return device->device_path() == path_; } @@ -93,7 +93,7 @@ NativeDisplayDelegateDri::NativeDisplayDelegateDri( ScreenManager* screen_manager, - const scoped_refptr<DriWrapper>& primary_device, + const scoped_refptr<DrmDevice>& primary_device, scoped_ptr<DrmDeviceGenerator> drm_device_generator) : screen_manager_(screen_manager), drm_device_generator_(drm_device_generator.Pass()) { @@ -213,7 +213,7 @@ return; } - scoped_refptr<DriWrapper> device = + scoped_refptr<DrmDevice> device = drm_device_generator_->CreateDevice(path, file.Pass()); if (!device) { VLOG(2) << "Could not initialize DRM device for '" << path.value() << "'";
diff --git a/ui/ozone/platform/dri/native_display_delegate_dri.h b/ui/ozone/platform/dri/native_display_delegate_dri.h index 88d1cb6..55c554c 100644 --- a/ui/ozone/platform/dri/native_display_delegate_dri.h +++ b/ui/ozone/platform/dri/native_display_delegate_dri.h
@@ -22,14 +22,14 @@ class DisplaySnapshotDri; class DisplayMode; class DisplayModeDri; -class DriWrapper; +class DrmDevice; class DrmDeviceGenerator; class ScreenManager; class NativeDisplayDelegateDri { public: NativeDisplayDelegateDri(ScreenManager* screen_manager, - const scoped_refptr<DriWrapper>& primary_device, + const scoped_refptr<DrmDevice>& primary_device, scoped_ptr<DrmDeviceGenerator> device_generator); ~NativeDisplayDelegateDri(); @@ -77,7 +77,7 @@ ScreenManager* screen_manager_; // Not owned. scoped_ptr<DrmDeviceGenerator> drm_device_generator_; scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; - std::vector<scoped_refptr<DriWrapper>> devices_; + std::vector<scoped_refptr<DrmDevice>> devices_; // Modes can be shared between different displays, so we need to keep track // of them independently for cleanup. ScopedVector<const DisplayMode> cached_modes_;
diff --git a/ui/ozone/platform/dri/native_display_delegate_proxy.cc b/ui/ozone/platform/dri/native_display_delegate_proxy.cc index c92a432..f9d0fa38 100644 --- a/ui/ozone/platform/dri/native_display_delegate_proxy.cc +++ b/ui/ozone/platform/dri/native_display_delegate_proxy.cc
@@ -106,9 +106,12 @@ // Fallback to command line if the file doesn't exit or failed to read. if (success || CreateSnapshotFromCommandLine(¶ms)) { + LOG_IF(ERROR, !success) << "Failed to read display_info.bin."; DCHECK_NE(DISPLAY_CONNECTION_TYPE_NONE, params.type); displays_.push_back(new DriDisplaySnapshotProxy(params, display_manager_)); has_dummy_display_ = true; + } else { + LOG(ERROR) << "Failed to obtain initial display info"; } }
diff --git a/ui/ozone/platform/dri/ozone_platform_dri.cc b/ui/ozone/platform/dri/ozone_platform_dri.cc index 8dd7838..31d025b 100644 --- a/ui/ozone/platform/dri/ozone_platform_dri.cc +++ b/ui/ozone/platform/dri/ozone_platform_dri.cc
@@ -19,10 +19,10 @@ #include "ui/ozone/platform/dri/dri_surface_factory.h" #include "ui/ozone/platform/dri/dri_util.h" #include "ui/ozone/platform/dri/dri_window.h" -#include "ui/ozone/platform/dri/dri_window_delegate_impl.h" +#include "ui/ozone/platform/dri/dri_window_delegate.h" #include "ui/ozone/platform/dri/dri_window_delegate_manager.h" #include "ui/ozone/platform/dri/dri_window_manager.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/platform/dri/drm_device_generator.h" #include "ui/ozone/platform/dri/drm_device_manager.h" #include "ui/ozone/platform/dri/native_display_delegate_dri.h" @@ -49,7 +49,7 @@ class OzonePlatformDri : public OzonePlatform { public: OzonePlatformDri() - : dri_(new DriWrapper(GetPrimaryDisplayCardPath())), + : drm_(new DrmDevice(GetPrimaryDisplayCardPath())), buffer_generator_(new DriBufferGenerator()), screen_manager_(new ScreenManager(buffer_generator_.get())), device_manager_(CreateDeviceManager()), @@ -88,21 +88,21 @@ scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate() override { return make_scoped_ptr(new NativeDisplayDelegateProxy( gpu_platform_support_host_.get(), device_manager_.get(), - display_manager_.get(), dri_->device_path())); + display_manager_.get(), drm_->device_path())); } void InitializeUI() override { - if (!dri_->Initialize()) + if (!drm_->Initialize()) LOG(FATAL) << "Failed to initialize primary DRM device"; // This makes sure that simple targets that do not handle display // configuration can still use the primary display. - ForceInitializationOfPrimaryDisplay(dri_, screen_manager_.get()); - drm_device_manager_.reset(new DrmDeviceManager(dri_)); + ForceInitializationOfPrimaryDisplay(drm_, screen_manager_.get()); + drm_device_manager_.reset(new DrmDeviceManager(drm_)); display_manager_.reset(new DisplayManager()); surface_factory_ozone_.reset( new DriSurfaceFactory(&window_delegate_manager_)); scoped_ptr<NativeDisplayDelegateDri> ndd(new NativeDisplayDelegateDri( - screen_manager_.get(), dri_, + screen_manager_.get(), drm_, scoped_ptr<DrmDeviceGenerator>(new DrmDeviceGenerator()))); gpu_platform_support_.reset(new DriGpuPlatformSupport( drm_device_manager_.get(), &window_delegate_manager_, @@ -132,7 +132,7 @@ void InitializeGPU() override {} private: - scoped_refptr<DriWrapper> dri_; + scoped_refptr<DrmDevice> drm_; scoped_ptr<DrmDeviceManager> drm_device_manager_; scoped_ptr<DriBufferGenerator> buffer_generator_; scoped_ptr<ScreenManager> screen_manager_;
diff --git a/ui/ozone/platform/dri/ozone_platform_gbm.cc b/ui/ozone/platform/dri/ozone_platform_gbm.cc index 7c237df..15d5466 100644 --- a/ui/ozone/platform/dri/ozone_platform_gbm.cc +++ b/ui/ozone/platform/dri/ozone_platform_gbm.cc
@@ -26,9 +26,9 @@ #include "ui/ozone/platform/dri/drm_device_generator.h" #include "ui/ozone/platform/dri/drm_device_manager.h" #include "ui/ozone/platform/dri/gbm_buffer.h" +#include "ui/ozone/platform/dri/gbm_device.h" #include "ui/ozone/platform/dri/gbm_surface.h" #include "ui/ozone/platform/dri/gbm_surface_factory.h" -#include "ui/ozone/platform/dri/gbm_wrapper.h" #include "ui/ozone/platform/dri/native_display_delegate_dri.h" #include "ui/ozone/platform/dri/native_display_delegate_proxy.h" #include "ui/ozone/platform/dri/scanout_buffer.h" @@ -76,9 +76,9 @@ ~GbmBufferGenerator() override {} // ScanoutBufferGenerator: - scoped_refptr<ScanoutBuffer> Create(const scoped_refptr<DriWrapper>& drm, + scoped_refptr<ScanoutBuffer> Create(const scoped_refptr<DrmDevice>& drm, const gfx::Size& size) override { - scoped_refptr<GbmWrapper> gbm(static_cast<GbmWrapper*>(drm.get())); + scoped_refptr<GbmDevice> gbm(static_cast<GbmDevice*>(drm.get())); return GbmBuffer::CreateBuffer(gbm, SurfaceFactoryOzone::RGBA_8888, size, true); } @@ -93,9 +93,9 @@ ~GbmDeviceGenerator() override {} // DrmDeviceGenerator: - scoped_refptr<DriWrapper> CreateDevice(const base::FilePath& path, - base::File file) override { - scoped_refptr<DriWrapper> drm = new GbmWrapper(path, file.Pass()); + scoped_refptr<DrmDevice> CreateDevice(const base::FilePath& path, + base::File file) override { + scoped_refptr<DrmDevice> drm = new GbmDevice(path, file.Pass()); if (drm->Initialize()) return drm; @@ -175,7 +175,7 @@ void InitializeGPU() override { gl_api_loader_.reset(new GlApiLoader()); // Async page flips are supported only on surfaceless mode. - gbm_ = new GbmWrapper(GetPrimaryDisplayCardPath()); + gbm_ = new GbmDevice(GetPrimaryDisplayCardPath()); if (!gbm_->Initialize()) LOG(FATAL) << "Failed to initialize primary DRM device"; @@ -204,7 +204,7 @@ bool use_surfaceless_; base::FilePath primary_graphics_card_path_; scoped_ptr<GlApiLoader> gl_api_loader_; - scoped_refptr<GbmWrapper> gbm_; + scoped_refptr<GbmDevice> gbm_; scoped_ptr<DrmDeviceManager> drm_device_manager_; scoped_ptr<GbmBufferGenerator> buffer_generator_; scoped_ptr<ScreenManager> screen_manager_;
diff --git a/ui/ozone/platform/dri/scanout_buffer.h b/ui/ozone/platform/dri/scanout_buffer.h index cf653322..bfe1990a 100644 --- a/ui/ozone/platform/dri/scanout_buffer.h +++ b/ui/ozone/platform/dri/scanout_buffer.h
@@ -12,7 +12,7 @@ namespace ui { -class DriWrapper; +class DrmDevice; // Abstraction for a DRM buffer that can be scanned-out of. class ScanoutBuffer : public base::RefCountedThreadSafe<ScanoutBuffer> { @@ -37,7 +37,7 @@ virtual ~ScanoutBufferGenerator() {} virtual scoped_refptr<ScanoutBuffer> Create( - const scoped_refptr<DriWrapper>& drm, + const scoped_refptr<DrmDevice>& drm, const gfx::Size& size) = 0; };
diff --git a/ui/ozone/platform/dri/screen_manager.cc b/ui/ozone/platform/dri/screen_manager.cc index fbf2edef..a2b0ee8 100644 --- a/ui/ozone/platform/dri/screen_manager.cc +++ b/ui/ozone/platform/dri/screen_manager.cc
@@ -13,7 +13,7 @@ #include "ui/ozone/platform/dri/crtc_controller.h" #include "ui/ozone/platform/dri/dri_console_buffer.h" #include "ui/ozone/platform/dri/dri_util.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/drm_device.h" #include "ui/ozone/platform/dri/hardware_display_controller.h" #include "ui/ozone/platform/dri/scanout_buffer.h" @@ -23,10 +23,10 @@ // Copies the contents of the saved framebuffer from the CRTCs in |controller| // to the new modeset buffer |buffer|. -void FillModesetBuffer(const scoped_refptr<DriWrapper>& dri, +void FillModesetBuffer(const scoped_refptr<DrmDevice>& drm, HardwareDisplayController* controller, ScanoutBuffer* buffer) { - DriConsoleBuffer modeset_buffer(dri, buffer->GetFramebufferId()); + DriConsoleBuffer modeset_buffer(drm, buffer->GetFramebufferId()); if (!modeset_buffer.Initialize()) { LOG(ERROR) << "Failed to grab framebuffer " << buffer->GetFramebufferId(); return; @@ -40,7 +40,7 @@ // If the display controller is in mirror mode, the CRTCs should be sharing // the same framebuffer. - DriConsoleBuffer saved_buffer(dri, crtcs[0]->saved_crtc()->buffer_id); + DriConsoleBuffer saved_buffer(drm, crtcs[0]->saved_crtc()->buffer_id); if (!saved_buffer.Initialize()) { LOG(ERROR) << "Failed to grab saved framebuffer " << crtcs[0]->saved_crtc()->buffer_id; @@ -69,10 +69,10 @@ ScreenManager::~ScreenManager() { } -void ScreenManager::AddDisplayController(const scoped_refptr<DriWrapper>& dri, +void ScreenManager::AddDisplayController(const scoped_refptr<DrmDevice>& drm, uint32_t crtc, uint32_t connector) { - HardwareDisplayControllers::iterator it = FindDisplayController(dri, crtc); + HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc); // TODO(dnicoara): Turn this into a DCHECK when async display configuration is // properly supported. (When there can't be a race between forcing initial // display configuration in ScreenManager and NativeDisplayDelegate creating @@ -83,12 +83,11 @@ } controllers_.push_back(new HardwareDisplayController( - scoped_ptr<CrtcController>(new CrtcController(dri, crtc, connector)))); + scoped_ptr<CrtcController>(new CrtcController(drm, crtc, connector)))); } -void ScreenManager::RemoveDisplayController( - const scoped_refptr<DriWrapper>& drm, - uint32_t crtc) { +void ScreenManager::RemoveDisplayController(const scoped_refptr<DrmDevice>& drm, + uint32_t crtc) { HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc); if (it != controllers_.end()) { bool is_mirrored = (*it)->IsMirrored(); @@ -102,7 +101,7 @@ } bool ScreenManager::ConfigureDisplayController( - const scoped_refptr<DriWrapper>& drm, + const scoped_refptr<DrmDevice>& drm, uint32_t crtc, uint32_t connector, const gfx::Point& origin, @@ -156,7 +155,7 @@ } bool ScreenManager::DisableDisplayController( - const scoped_refptr<DriWrapper>& drm, + const scoped_refptr<DrmDevice>& drm, uint32_t crtc) { HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc); if (it != controllers_.end()) { @@ -193,7 +192,7 @@ } ScreenManager::HardwareDisplayControllers::iterator -ScreenManager::FindDisplayController(const scoped_refptr<DriWrapper>& drm, +ScreenManager::FindDisplayController(const scoped_refptr<DrmDevice>& drm, uint32_t crtc) { for (HardwareDisplayControllers::iterator it = controllers_.begin(); it != controllers_.end(); @@ -223,7 +222,7 @@ const gfx::Point& origin, const drmModeModeInfo& mode) { DCHECK(!controller->crtc_controllers().empty()); - scoped_refptr<DriWrapper> drm = controller->GetAllocationDriWrapper(); + scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice(); controller->set_origin(origin); // Create a surface suitable for the current controller. @@ -250,7 +249,7 @@ bool ScreenManager::HandleMirrorMode( HardwareDisplayControllers::iterator original, HardwareDisplayControllers::iterator mirror, - const scoped_refptr<DriWrapper>& drm, + const scoped_refptr<DrmDevice>& drm, uint32_t crtc, uint32_t connector) { (*mirror)->AddCrtc((*original)->RemoveCrtc(drm, crtc));
diff --git a/ui/ozone/platform/dri/screen_manager.h b/ui/ozone/platform/dri/screen_manager.h index 5eaaa46..bf8fed9 100644 --- a/ui/ozone/platform/dri/screen_manager.h +++ b/ui/ozone/platform/dri/screen_manager.h
@@ -22,7 +22,7 @@ namespace ui { -class DriWrapper; +class DrmDevice; class ScanoutBufferGenerator; // Responsible for keeping track of active displays and configuring them. @@ -33,18 +33,18 @@ // Register a display controller. This must be called before trying to // configure it. - void AddDisplayController(const scoped_refptr<DriWrapper>& dri, + void AddDisplayController(const scoped_refptr<DrmDevice>& drm, uint32_t crtc, uint32_t connector); // Remove a display controller from the list of active controllers. The // controller is removed since it was disconnected. - void RemoveDisplayController(const scoped_refptr<DriWrapper>& dri, + void RemoveDisplayController(const scoped_refptr<DrmDevice>& drm, uint32_t crtc); // Configure a display controller. The display controller is identified by // (|crtc|, |connector|) and the controller is modeset using |mode|. - bool ConfigureDisplayController(const scoped_refptr<DriWrapper>& dri, + bool ConfigureDisplayController(const scoped_refptr<DrmDevice>& drm, uint32_t crtc, uint32_t connector, const gfx::Point& origin, @@ -52,7 +52,7 @@ // Disable the display controller identified by |crtc|. Note, the controller // may still be connected, so this does not remove the controller. - bool DisableDisplayController(const scoped_refptr<DriWrapper>& dri, + bool DisableDisplayController(const scoped_refptr<DrmDevice>& drm, uint32_t crtc); // Returns a reference to the display controller configured to display within @@ -69,7 +69,7 @@ // Returns an iterator into |controllers_| for the controller identified by // (|crtc|, |connector|). HardwareDisplayControllers::iterator FindDisplayController( - const scoped_refptr<DriWrapper>& drm, + const scoped_refptr<DrmDevice>& drm, uint32_t crtc); // Returns an iterator into |controllers_| for the controller located at @@ -87,7 +87,7 @@ // controller is currently present. bool HandleMirrorMode(HardwareDisplayControllers::iterator original, HardwareDisplayControllers::iterator mirror, - const scoped_refptr<DriWrapper>& drm, + const scoped_refptr<DrmDevice>& drm, uint32_t crtc, uint32_t connector);
diff --git a/ui/ozone/platform/dri/screen_manager_unittest.cc b/ui/ozone/platform/dri/screen_manager_unittest.cc index 1501b71..58e08d1 100644 --- a/ui/ozone/platform/dri/screen_manager_unittest.cc +++ b/ui/ozone/platform/dri/screen_manager_unittest.cc
@@ -7,7 +7,7 @@ #include "ui/ozone/platform/dri/dri_buffer.h" #include "ui/ozone/platform/dri/hardware_display_controller.h" #include "ui/ozone/platform/dri/screen_manager.h" -#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h" +#include "ui/ozone/platform/dri/test/mock_drm_device.h" namespace { @@ -64,7 +64,7 @@ } void SetUp() override { - dri_ = new ui::MockDriWrapper(); + drm_ = new ui::MockDrmDevice(); buffer_generator_.reset(new ui::DriBufferGenerator()); screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get())); screen_manager_->AddObserver(&observer_); @@ -72,11 +72,11 @@ void TearDown() override { screen_manager_->RemoveObserver(&observer_); screen_manager_.reset(); - dri_ = nullptr; + drm_ = nullptr; } protected: - scoped_refptr<ui::MockDriWrapper> dri_; + scoped_refptr<ui::MockDrmDevice> drm_; scoped_ptr<ui::DriBufferGenerator> buffer_generator_; scoped_ptr<ui::ScreenManager> screen_manager_; @@ -91,21 +91,21 @@ } TEST_F(ScreenManagerTest, CheckWithValidController) { - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); ui::HardwareDisplayController* controller = screen_manager_->GetDisplayController(GetPrimaryBounds()); EXPECT_TRUE(controller); - EXPECT_TRUE(controller->HasCrtc(dri_, kPrimaryCrtc)); + EXPECT_TRUE(controller->HasCrtc(drm_, kPrimaryCrtc)); } TEST_F(ScreenManagerTest, CheckWithInvalidBounds) { - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds())); @@ -113,14 +113,14 @@ } TEST_F(ScreenManagerTest, CheckForSecondValidController) { - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); - screen_manager_->AddDisplayController(dri_, kSecondaryCrtc, + screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, kSecondaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(), + drm_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(), kDefaultMode); EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds())); @@ -128,33 +128,33 @@ } TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) { - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); EXPECT_EQ(1, observer_.num_displays_changed()); EXPECT_EQ(0, observer_.num_displays_removed()); EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds())); - screen_manager_->RemoveDisplayController(dri_, kPrimaryCrtc); + screen_manager_->RemoveDisplayController(drm_, kPrimaryCrtc); EXPECT_EQ(1, observer_.num_displays_changed()); EXPECT_EQ(1, observer_.num_displays_removed()); EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds())); } TEST_F(ScreenManagerTest, CheckDuplicateConfiguration) { - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); - uint32_t framebuffer = dri_->current_framebuffer(); + uint32_t framebuffer = drm_->current_framebuffer(); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); // Should reuse existing framebuffer. - EXPECT_EQ(framebuffer, dri_->current_framebuffer()); + EXPECT_EQ(framebuffer, drm_->current_framebuffer()); EXPECT_EQ(2, observer_.num_displays_changed()); EXPECT_EQ(0, observer_.num_displays_removed()); @@ -164,14 +164,14 @@ } TEST_F(ScreenManagerTest, CheckChangingMode) { - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); drmModeModeInfo new_mode = kDefaultMode; new_mode.vdisplay = 10; screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), new_mode); EXPECT_EQ(2, observer_.num_displays_changed()); @@ -187,14 +187,14 @@ } TEST_F(ScreenManagerTest, CheckForControllersInMirroredMode) { - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); - screen_manager_->AddDisplayController(dri_, kSecondaryCrtc, + screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, kSecondaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(), + drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(), kDefaultMode); EXPECT_EQ(2, observer_.num_displays_changed()); @@ -204,55 +204,55 @@ } TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) { - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); - screen_manager_->AddDisplayController(dri_, kSecondaryCrtc, + screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, kSecondaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(), + drm_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(), kDefaultMode); EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds())); EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds())); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); screen_manager_->ConfigureDisplayController( - dri_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(), + drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(), kDefaultMode); EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds())); EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds())); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetSecondaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetSecondaryBounds().origin(), kDefaultMode); screen_manager_->ConfigureDisplayController( - dri_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(), + drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(), kDefaultMode); EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds())); EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds())); } TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) { - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); - screen_manager_->AddDisplayController(dri_, kSecondaryCrtc, + screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, kSecondaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(), + drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(), kDefaultMode); EXPECT_EQ(2, observer_.num_displays_changed()); EXPECT_EQ(1, observer_.num_displays_removed()); - screen_manager_->RemoveDisplayController(dri_, kSecondaryCrtc); + screen_manager_->RemoveDisplayController(drm_, kSecondaryCrtc); EXPECT_TRUE(screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode)); EXPECT_EQ(3, observer_.num_displays_changed()); EXPECT_EQ(1, observer_.num_displays_removed()); @@ -262,23 +262,23 @@ } TEST_F(ScreenManagerTest, DoNotEnterMirrorModeUnlessSameBounds) { - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); - screen_manager_->AddDisplayController(dri_, kSecondaryCrtc, + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, kSecondaryConnector); // Configure displays in extended mode. screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); screen_manager_->ConfigureDisplayController( - dri_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(), + drm_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(), kDefaultMode); drmModeModeInfo new_mode = kDefaultMode; new_mode.vdisplay = 10; // Shouldn't enter mirror mode unless the display bounds are the same. screen_manager_->ConfigureDisplayController( - dri_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(), + drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(), new_mode); EXPECT_FALSE( @@ -286,34 +286,34 @@ } TEST_F(ScreenManagerTest, ReuseFramebufferIfDisabledThenReEnabled) { - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); - uint32_t framebuffer = dri_->current_framebuffer(); + uint32_t framebuffer = drm_->current_framebuffer(); - screen_manager_->DisableDisplayController(dri_, kPrimaryCrtc); - EXPECT_EQ(0u, dri_->current_framebuffer()); + screen_manager_->DisableDisplayController(drm_, kPrimaryCrtc); + EXPECT_EQ(0u, drm_->current_framebuffer()); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); // Should reuse existing framebuffer. - EXPECT_EQ(framebuffer, dri_->current_framebuffer()); + EXPECT_EQ(framebuffer, drm_->current_framebuffer()); } TEST_F(ScreenManagerTest, CheckMirrorModeAfterBeginReEnabled) { - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); - screen_manager_->DisableDisplayController(dri_, kPrimaryCrtc); + screen_manager_->DisableDisplayController(drm_, kPrimaryCrtc); - screen_manager_->AddDisplayController(dri_, kSecondaryCrtc, + screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, kSecondaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(), + drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(), kDefaultMode); ui::HardwareDisplayController* controller = @@ -322,7 +322,7 @@ EXPECT_FALSE(controller->IsMirrored()); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); EXPECT_TRUE(controller); EXPECT_TRUE(controller->IsMirrored()); @@ -330,16 +330,16 @@ TEST_F(ScreenManagerTest, CheckProperConfigurationWithDifferentDeviceAndSameCrtc) { - scoped_refptr<ui::MockDriWrapper> dri2 = new ui::MockDriWrapper(); + scoped_refptr<ui::MockDrmDevice> drm2 = new ui::MockDrmDevice(); - screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector); - screen_manager_->AddDisplayController(dri2, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm2, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( - dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), + drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), kDefaultMode); screen_manager_->ConfigureDisplayController( - dri2, kPrimaryCrtc, kPrimaryConnector, GetSecondaryBounds().origin(), + drm2, kPrimaryCrtc, kPrimaryConnector, GetSecondaryBounds().origin(), kDefaultMode); ui::HardwareDisplayController* controller1 = @@ -348,6 +348,6 @@ screen_manager_->GetDisplayController(GetSecondaryBounds()); EXPECT_NE(controller1, controller2); - EXPECT_EQ(dri_, controller1->crtc_controllers()[0]->drm()); - EXPECT_EQ(dri2, controller2->crtc_controllers()[0]->drm()); + EXPECT_EQ(drm_, controller1->crtc_controllers()[0]->drm()); + EXPECT_EQ(drm2, controller2->crtc_controllers()[0]->drm()); }
diff --git a/ui/ozone/platform/dri/test/mock_dri_wrapper.cc b/ui/ozone/platform/dri/test/mock_dri_wrapper.cc deleted file mode 100644 index 4c33e01..0000000 --- a/ui/ozone/platform/dri/test/mock_dri_wrapper.cc +++ /dev/null
@@ -1,224 +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 "ui/ozone/platform/dri/test/mock_dri_wrapper.h" - -#include <xf86drm.h> -#include <xf86drmMode.h> - -#include "base/logging.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h" - -namespace ui { - -namespace { - -template<class Object> Object* DrmAllocator() { - return static_cast<Object*>(drmMalloc(sizeof(Object))); -} - -class MockHardwareDisplayPlaneManager - : public HardwareDisplayPlaneManagerLegacy { - public: - MockHardwareDisplayPlaneManager(DriWrapper* drm, - std::vector<uint32_t> crtcs, - size_t planes_per_crtc) { - const int kPlaneBaseId = 50; - drm_ = drm; - crtcs_.swap(crtcs); - for (size_t crtc_idx = 0; crtc_idx < crtcs_.size(); crtc_idx++) { - for (size_t i = 0; i < planes_per_crtc; i++) { - planes_.push_back( - new HardwareDisplayPlane(kPlaneBaseId + i, 1 << crtc_idx)); - } - } - } -}; - -} // namespace - -MockDriWrapper::MockDriWrapper() - : DriWrapper(base::FilePath(), base::File()), - get_crtc_call_count_(0), - set_crtc_call_count_(0), - restore_crtc_call_count_(0), - add_framebuffer_call_count_(0), - remove_framebuffer_call_count_(0), - page_flip_call_count_(0), - overlay_flip_call_count_(0), - set_crtc_expectation_(true), - add_framebuffer_expectation_(true), - page_flip_expectation_(true), - create_dumb_buffer_expectation_(true), - current_framebuffer_(0) { - plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); -} - -MockDriWrapper::MockDriWrapper(bool use_sync_flips, - std::vector<uint32_t> crtcs, - size_t planes_per_crtc) - : DriWrapper(base::FilePath(), base::File()), - get_crtc_call_count_(0), - set_crtc_call_count_(0), - restore_crtc_call_count_(0), - add_framebuffer_call_count_(0), - remove_framebuffer_call_count_(0), - page_flip_call_count_(0), - overlay_flip_call_count_(0), - overlay_clear_call_count_(0), - set_crtc_expectation_(true), - add_framebuffer_expectation_(true), - page_flip_expectation_(true), - create_dumb_buffer_expectation_(true), - use_sync_flips_(use_sync_flips), - current_framebuffer_(0) { - plane_manager_.reset( - new MockHardwareDisplayPlaneManager(this, crtcs, planes_per_crtc)); -} - -MockDriWrapper::~MockDriWrapper() { -} - -ScopedDrmCrtcPtr MockDriWrapper::GetCrtc(uint32_t crtc_id) { - get_crtc_call_count_++; - return ScopedDrmCrtcPtr(DrmAllocator<drmModeCrtc>()); -} - -bool MockDriWrapper::SetCrtc(uint32_t crtc_id, - uint32_t framebuffer, - std::vector<uint32_t> connectors, - drmModeModeInfo* mode) { - current_framebuffer_ = framebuffer; - set_crtc_call_count_++; - return set_crtc_expectation_; -} - -bool MockDriWrapper::SetCrtc(drmModeCrtc* crtc, - std::vector<uint32_t> connectors) { - restore_crtc_call_count_++; - return true; -} - -bool MockDriWrapper::DisableCrtc(uint32_t crtc_id) { - current_framebuffer_ = 0; - return true; -} - -ScopedDrmConnectorPtr MockDriWrapper::GetConnector(uint32_t connector_id) { - return ScopedDrmConnectorPtr(DrmAllocator<drmModeConnector>()); -} - -bool MockDriWrapper::AddFramebuffer(uint32_t width, - uint32_t height, - uint8_t depth, - uint8_t bpp, - uint32_t stride, - uint32_t handle, - uint32_t* framebuffer) { - add_framebuffer_call_count_++; - *framebuffer = add_framebuffer_call_count_; - return add_framebuffer_expectation_; -} - -bool MockDriWrapper::RemoveFramebuffer(uint32_t framebuffer) { - remove_framebuffer_call_count_++; - return true; -} - -ScopedDrmFramebufferPtr MockDriWrapper::GetFramebuffer(uint32_t framebuffer) { - return ScopedDrmFramebufferPtr(); -} - -bool MockDriWrapper::PageFlip(uint32_t crtc_id, - uint32_t framebuffer, - bool is_sync, - const PageFlipCallback& callback) { - page_flip_call_count_++; - current_framebuffer_ = framebuffer; - if (page_flip_expectation_) { - if (use_sync_flips_) - callback.Run(0, 0, 0); - else - callbacks_.push(callback); - } - - return page_flip_expectation_; -} - -bool MockDriWrapper::PageFlipOverlay(uint32_t crtc_id, - uint32_t framebuffer, - const gfx::Rect& location, - const gfx::Rect& source, - int overlay_plane) { - if (!framebuffer) - overlay_clear_call_count_++; - overlay_flip_call_count_++; - return true; -} - -ScopedDrmPropertyPtr MockDriWrapper::GetProperty(drmModeConnector* connector, - const char* name) { - return ScopedDrmPropertyPtr(DrmAllocator<drmModePropertyRes>()); -} - -bool MockDriWrapper::SetProperty(uint32_t connector_id, - uint32_t property_id, - uint64_t value) { - return true; -} - -bool MockDriWrapper::GetCapability(uint64_t capability, uint64_t* value) { - return true; -} - -ScopedDrmPropertyBlobPtr MockDriWrapper::GetPropertyBlob( - drmModeConnector* connector, - const char* name) { - return ScopedDrmPropertyBlobPtr(DrmAllocator<drmModePropertyBlobRes>()); -} - -bool MockDriWrapper::SetCursor(uint32_t crtc_id, - uint32_t handle, - const gfx::Size& size) { - return true; -} - -bool MockDriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) { - return true; -} - -bool MockDriWrapper::CreateDumbBuffer(const SkImageInfo& info, - uint32_t* handle, - uint32_t* stride, - void** pixels) { - if (!create_dumb_buffer_expectation_) - return false; - - *handle = 0; - *stride = info.minRowBytes(); - *pixels = new char[info.getSafeSize(*stride)]; - buffers_.push_back( - skia::AdoptRef(SkSurface::NewRasterDirect(info, *pixels, *stride))); - buffers_.back()->getCanvas()->clear(SK_ColorBLACK); - - return true; -} - -void MockDriWrapper::DestroyDumbBuffer(const SkImageInfo& info, - uint32_t handle, - uint32_t stride, - void* pixels) { - delete[] static_cast<char*>(pixels); -} - -void MockDriWrapper::RunCallbacks() { - while (!callbacks_.empty()) { - PageFlipCallback callback = callbacks_.front(); - callbacks_.pop(); - callback.Run(0, 0, 0); - } -} - -} // namespace ui
diff --git a/ui/ozone/platform/dri/test/mock_dri_wrapper.h b/ui/ozone/platform/dri/test/mock_dri_wrapper.h deleted file mode 100644 index 87253d8..0000000 --- a/ui/ozone/platform/dri/test/mock_dri_wrapper.h +++ /dev/null
@@ -1,134 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_WRAPPER_H_ -#define UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_WRAPPER_H_ - -#include <queue> -#include <vector> - -#include "skia/ext/refptr.h" -#include "third_party/skia/include/core/SkSurface.h" -#include "ui/ozone/platform/dri/dri_wrapper.h" - -namespace ui { - -class CrtcController; - -// The real DriWrapper makes actual DRM calls which we can't use in unit tests. -class MockDriWrapper : public ui::DriWrapper { - public: - MockDriWrapper(); - MockDriWrapper(bool use_sync_flips, - std::vector<uint32_t> crtcs, - size_t planes_per_crtc); - - int get_get_crtc_call_count() const { return get_crtc_call_count_; } - int get_set_crtc_call_count() const { return set_crtc_call_count_; } - int get_restore_crtc_call_count() const { return restore_crtc_call_count_; } - int get_add_framebuffer_call_count() const { - return add_framebuffer_call_count_; - } - int get_remove_framebuffer_call_count() const { - return remove_framebuffer_call_count_; - } - int get_page_flip_call_count() const { return page_flip_call_count_; } - int get_overlay_flip_call_count() const { return overlay_flip_call_count_; } - int get_overlay_clear_call_count() const { return overlay_clear_call_count_; } - void set_set_crtc_expectation(bool state) { set_crtc_expectation_ = state; } - void set_page_flip_expectation(bool state) { page_flip_expectation_ = state; } - void set_add_framebuffer_expectation(bool state) { - add_framebuffer_expectation_ = state; - } - void set_create_dumb_buffer_expectation(bool state) { - create_dumb_buffer_expectation_ = state; - } - - uint32_t current_framebuffer() const { return current_framebuffer_; } - - const std::vector<skia::RefPtr<SkSurface> > buffers() const { - return buffers_; - } - - void RunCallbacks(); - - // DriWrapper: - ScopedDrmCrtcPtr GetCrtc(uint32_t crtc_id) override; - bool SetCrtc(uint32_t crtc_id, - uint32_t framebuffer, - std::vector<uint32_t> connectors, - drmModeModeInfo* mode) override; - bool SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) override; - bool DisableCrtc(uint32_t crtc_id) override; - ScopedDrmConnectorPtr GetConnector(uint32_t connector_id) override; - bool AddFramebuffer(uint32_t width, - uint32_t height, - uint8_t depth, - uint8_t bpp, - uint32_t stride, - uint32_t handle, - uint32_t* framebuffer) override; - bool RemoveFramebuffer(uint32_t framebuffer) override; - ScopedDrmFramebufferPtr GetFramebuffer(uint32_t framebuffer) override; - bool PageFlip(uint32_t crtc_id, - uint32_t framebuffer, - bool is_sync, - const PageFlipCallback& callback) override; - bool PageFlipOverlay(uint32_t crtc_id, - uint32_t framebuffer, - const gfx::Rect& location, - const gfx::Rect& source, - int overlay_plane) override; - ScopedDrmPropertyPtr GetProperty(drmModeConnector* connector, - const char* name) override; - bool SetProperty(uint32_t connector_id, - uint32_t property_id, - uint64_t value) override; - bool GetCapability(uint64_t capability, uint64_t* value) override; - ScopedDrmPropertyBlobPtr GetPropertyBlob(drmModeConnector* connector, - const char* name) override; - bool SetCursor(uint32_t crtc_id, - uint32_t handle, - const gfx::Size& size) override; - bool MoveCursor(uint32_t crtc_id, const gfx::Point& point) override; - bool CreateDumbBuffer(const SkImageInfo& info, - uint32_t* handle, - uint32_t* stride, - void** pixels) override; - void DestroyDumbBuffer(const SkImageInfo& info, - uint32_t handle, - uint32_t stride, - void* pixels) override; - - private: - ~MockDriWrapper() override; - - int get_crtc_call_count_; - int set_crtc_call_count_; - int restore_crtc_call_count_; - int add_framebuffer_call_count_; - int remove_framebuffer_call_count_; - int page_flip_call_count_; - int overlay_flip_call_count_; - int overlay_clear_call_count_; - - bool set_crtc_expectation_; - bool add_framebuffer_expectation_; - bool page_flip_expectation_; - bool create_dumb_buffer_expectation_; - - bool use_sync_flips_; - - uint32_t current_framebuffer_; - - std::vector<skia::RefPtr<SkSurface> > buffers_; - - std::queue<PageFlipCallback> callbacks_; - - DISALLOW_COPY_AND_ASSIGN(MockDriWrapper); -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_WRAPPER_H_
diff --git a/ui/ozone/platform/dri/test/mock_drm_device.cc b/ui/ozone/platform/dri/test/mock_drm_device.cc new file mode 100644 index 0000000..460ecbb --- /dev/null +++ b/ui/ozone/platform/dri/test/mock_drm_device.cc
@@ -0,0 +1,225 @@ +// 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/dri/test/mock_drm_device.h" + +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include "base/logging.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h" + +namespace ui { + +namespace { + +template <class Object> +Object* DrmAllocator() { + return static_cast<Object*>(drmMalloc(sizeof(Object))); +} + +class MockHardwareDisplayPlaneManager + : public HardwareDisplayPlaneManagerLegacy { + public: + MockHardwareDisplayPlaneManager(DrmDevice* drm, + std::vector<uint32_t> crtcs, + size_t planes_per_crtc) { + const int kPlaneBaseId = 50; + drm_ = drm; + crtcs_.swap(crtcs); + for (size_t crtc_idx = 0; crtc_idx < crtcs_.size(); crtc_idx++) { + for (size_t i = 0; i < planes_per_crtc; i++) { + planes_.push_back( + new HardwareDisplayPlane(kPlaneBaseId + i, 1 << crtc_idx)); + } + } + } +}; + +} // namespace + +MockDrmDevice::MockDrmDevice() + : DrmDevice(base::FilePath(), base::File()), + get_crtc_call_count_(0), + set_crtc_call_count_(0), + restore_crtc_call_count_(0), + add_framebuffer_call_count_(0), + remove_framebuffer_call_count_(0), + page_flip_call_count_(0), + overlay_flip_call_count_(0), + set_crtc_expectation_(true), + add_framebuffer_expectation_(true), + page_flip_expectation_(true), + create_dumb_buffer_expectation_(true), + current_framebuffer_(0) { + plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); +} + +MockDrmDevice::MockDrmDevice(bool use_sync_flips, + std::vector<uint32_t> crtcs, + size_t planes_per_crtc) + : DrmDevice(base::FilePath(), base::File()), + get_crtc_call_count_(0), + set_crtc_call_count_(0), + restore_crtc_call_count_(0), + add_framebuffer_call_count_(0), + remove_framebuffer_call_count_(0), + page_flip_call_count_(0), + overlay_flip_call_count_(0), + overlay_clear_call_count_(0), + set_crtc_expectation_(true), + add_framebuffer_expectation_(true), + page_flip_expectation_(true), + create_dumb_buffer_expectation_(true), + use_sync_flips_(use_sync_flips), + current_framebuffer_(0) { + plane_manager_.reset( + new MockHardwareDisplayPlaneManager(this, crtcs, planes_per_crtc)); +} + +MockDrmDevice::~MockDrmDevice() { +} + +ScopedDrmCrtcPtr MockDrmDevice::GetCrtc(uint32_t crtc_id) { + get_crtc_call_count_++; + return ScopedDrmCrtcPtr(DrmAllocator<drmModeCrtc>()); +} + +bool MockDrmDevice::SetCrtc(uint32_t crtc_id, + uint32_t framebuffer, + std::vector<uint32_t> connectors, + drmModeModeInfo* mode) { + current_framebuffer_ = framebuffer; + set_crtc_call_count_++; + return set_crtc_expectation_; +} + +bool MockDrmDevice::SetCrtc(drmModeCrtc* crtc, + std::vector<uint32_t> connectors) { + restore_crtc_call_count_++; + return true; +} + +bool MockDrmDevice::DisableCrtc(uint32_t crtc_id) { + current_framebuffer_ = 0; + return true; +} + +ScopedDrmConnectorPtr MockDrmDevice::GetConnector(uint32_t connector_id) { + return ScopedDrmConnectorPtr(DrmAllocator<drmModeConnector>()); +} + +bool MockDrmDevice::AddFramebuffer(uint32_t width, + uint32_t height, + uint8_t depth, + uint8_t bpp, + uint32_t stride, + uint32_t handle, + uint32_t* framebuffer) { + add_framebuffer_call_count_++; + *framebuffer = add_framebuffer_call_count_; + return add_framebuffer_expectation_; +} + +bool MockDrmDevice::RemoveFramebuffer(uint32_t framebuffer) { + remove_framebuffer_call_count_++; + return true; +} + +ScopedDrmFramebufferPtr MockDrmDevice::GetFramebuffer(uint32_t framebuffer) { + return ScopedDrmFramebufferPtr(); +} + +bool MockDrmDevice::PageFlip(uint32_t crtc_id, + uint32_t framebuffer, + bool is_sync, + const PageFlipCallback& callback) { + page_flip_call_count_++; + current_framebuffer_ = framebuffer; + if (page_flip_expectation_) { + if (use_sync_flips_) + callback.Run(0, 0, 0); + else + callbacks_.push(callback); + } + + return page_flip_expectation_; +} + +bool MockDrmDevice::PageFlipOverlay(uint32_t crtc_id, + uint32_t framebuffer, + const gfx::Rect& location, + const gfx::Rect& source, + int overlay_plane) { + if (!framebuffer) + overlay_clear_call_count_++; + overlay_flip_call_count_++; + return true; +} + +ScopedDrmPropertyPtr MockDrmDevice::GetProperty(drmModeConnector* connector, + const char* name) { + return ScopedDrmPropertyPtr(DrmAllocator<drmModePropertyRes>()); +} + +bool MockDrmDevice::SetProperty(uint32_t connector_id, + uint32_t property_id, + uint64_t value) { + return true; +} + +bool MockDrmDevice::GetCapability(uint64_t capability, uint64_t* value) { + return true; +} + +ScopedDrmPropertyBlobPtr MockDrmDevice::GetPropertyBlob( + drmModeConnector* connector, + const char* name) { + return ScopedDrmPropertyBlobPtr(DrmAllocator<drmModePropertyBlobRes>()); +} + +bool MockDrmDevice::SetCursor(uint32_t crtc_id, + uint32_t handle, + const gfx::Size& size) { + return true; +} + +bool MockDrmDevice::MoveCursor(uint32_t crtc_id, const gfx::Point& point) { + return true; +} + +bool MockDrmDevice::CreateDumbBuffer(const SkImageInfo& info, + uint32_t* handle, + uint32_t* stride, + void** pixels) { + if (!create_dumb_buffer_expectation_) + return false; + + *handle = 0; + *stride = info.minRowBytes(); + *pixels = new char[info.getSafeSize(*stride)]; + buffers_.push_back( + skia::AdoptRef(SkSurface::NewRasterDirect(info, *pixels, *stride))); + buffers_.back()->getCanvas()->clear(SK_ColorBLACK); + + return true; +} + +void MockDrmDevice::DestroyDumbBuffer(const SkImageInfo& info, + uint32_t handle, + uint32_t stride, + void* pixels) { + delete[] static_cast<char*>(pixels); +} + +void MockDrmDevice::RunCallbacks() { + while (!callbacks_.empty()) { + PageFlipCallback callback = callbacks_.front(); + callbacks_.pop(); + callback.Run(0, 0, 0); + } +} + +} // namespace ui
diff --git a/ui/ozone/platform/dri/test/mock_drm_device.h b/ui/ozone/platform/dri/test/mock_drm_device.h new file mode 100644 index 0000000..d3268e1 --- /dev/null +++ b/ui/ozone/platform/dri/test/mock_drm_device.h
@@ -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. + +#ifndef UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRM_DEVICE_H_ +#define UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRM_DEVICE_H_ + +#include <queue> +#include <vector> + +#include "skia/ext/refptr.h" +#include "third_party/skia/include/core/SkSurface.h" +#include "ui/ozone/platform/dri/drm_device.h" + +namespace ui { + +class CrtcController; + +// The real DrmDevice makes actual DRM calls which we can't use in unit tests. +class MockDrmDevice : public ui::DrmDevice { + public: + MockDrmDevice(); + MockDrmDevice(bool use_sync_flips, + std::vector<uint32_t> crtcs, + size_t planes_per_crtc); + + int get_get_crtc_call_count() const { return get_crtc_call_count_; } + int get_set_crtc_call_count() const { return set_crtc_call_count_; } + int get_restore_crtc_call_count() const { return restore_crtc_call_count_; } + int get_add_framebuffer_call_count() const { + return add_framebuffer_call_count_; + } + int get_remove_framebuffer_call_count() const { + return remove_framebuffer_call_count_; + } + int get_page_flip_call_count() const { return page_flip_call_count_; } + int get_overlay_flip_call_count() const { return overlay_flip_call_count_; } + int get_overlay_clear_call_count() const { return overlay_clear_call_count_; } + void set_set_crtc_expectation(bool state) { set_crtc_expectation_ = state; } + void set_page_flip_expectation(bool state) { page_flip_expectation_ = state; } + void set_add_framebuffer_expectation(bool state) { + add_framebuffer_expectation_ = state; + } + void set_create_dumb_buffer_expectation(bool state) { + create_dumb_buffer_expectation_ = state; + } + + uint32_t current_framebuffer() const { return current_framebuffer_; } + + const std::vector<skia::RefPtr<SkSurface>> buffers() const { + return buffers_; + } + + void RunCallbacks(); + + // DrmDevice: + ScopedDrmCrtcPtr GetCrtc(uint32_t crtc_id) override; + bool SetCrtc(uint32_t crtc_id, + uint32_t framebuffer, + std::vector<uint32_t> connectors, + drmModeModeInfo* mode) override; + bool SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) override; + bool DisableCrtc(uint32_t crtc_id) override; + ScopedDrmConnectorPtr GetConnector(uint32_t connector_id) override; + bool AddFramebuffer(uint32_t width, + uint32_t height, + uint8_t depth, + uint8_t bpp, + uint32_t stride, + uint32_t handle, + uint32_t* framebuffer) override; + bool RemoveFramebuffer(uint32_t framebuffer) override; + ScopedDrmFramebufferPtr GetFramebuffer(uint32_t framebuffer) override; + bool PageFlip(uint32_t crtc_id, + uint32_t framebuffer, + bool is_sync, + const PageFlipCallback& callback) override; + bool PageFlipOverlay(uint32_t crtc_id, + uint32_t framebuffer, + const gfx::Rect& location, + const gfx::Rect& source, + int overlay_plane) override; + ScopedDrmPropertyPtr GetProperty(drmModeConnector* connector, + const char* name) override; + bool SetProperty(uint32_t connector_id, + uint32_t property_id, + uint64_t value) override; + bool GetCapability(uint64_t capability, uint64_t* value) override; + ScopedDrmPropertyBlobPtr GetPropertyBlob(drmModeConnector* connector, + const char* name) override; + bool SetCursor(uint32_t crtc_id, + uint32_t handle, + const gfx::Size& size) override; + bool MoveCursor(uint32_t crtc_id, const gfx::Point& point) override; + bool CreateDumbBuffer(const SkImageInfo& info, + uint32_t* handle, + uint32_t* stride, + void** pixels) override; + void DestroyDumbBuffer(const SkImageInfo& info, + uint32_t handle, + uint32_t stride, + void* pixels) override; + + private: + ~MockDrmDevice() override; + + int get_crtc_call_count_; + int set_crtc_call_count_; + int restore_crtc_call_count_; + int add_framebuffer_call_count_; + int remove_framebuffer_call_count_; + int page_flip_call_count_; + int overlay_flip_call_count_; + int overlay_clear_call_count_; + + bool set_crtc_expectation_; + bool add_framebuffer_expectation_; + bool page_flip_expectation_; + bool create_dumb_buffer_expectation_; + + bool use_sync_flips_; + + uint32_t current_framebuffer_; + + std::vector<skia::RefPtr<SkSurface>> buffers_; + + std::queue<PageFlipCallback> callbacks_; + + DISALLOW_COPY_AND_ASSIGN(MockDrmDevice); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRM_DEVICE_H_
diff --git a/ui/snapshot/BUILD.gn b/ui/snapshot/BUILD.gn index b93fc6f..a9e5b0b 100644 --- a/ui/snapshot/BUILD.gn +++ b/ui/snapshot/BUILD.gn
@@ -56,37 +56,35 @@ } } -if (!is_win || link_chrome_on_windows) { - test("snapshot_unittests") { - sources = [ - "snapshot_aura_unittest.cc", - "snapshot_mac_unittest.mm", - "test/run_all_unittests.cc", - ] +test("snapshot_unittests") { + sources = [ + "snapshot_aura_unittest.cc", + "snapshot_mac_unittest.mm", + "test/run_all_unittests.cc", + ] - deps = [ - ":snapshot", - "//base", - "//base/allocator", - "//base/test:test_support", - "//skia", - "//testing/gtest", - "//ui/base", + deps = [ + ":snapshot", + "//base", + "//base/allocator", + "//base/test:test_support", + "//skia", + "//testing/gtest", + "//ui/base", + "//ui/compositor:test_support", + "//ui/gfx", + "//ui/gfx/geometry", + "//ui/gl", + ] + + if (use_aura) { + deps += [ + "//ui/aura:test_support", + "//ui/compositor", "//ui/compositor:test_support", - "//ui/gfx", - "//ui/gfx/geometry", - "//ui/gl", + "//ui/wm", ] - - if (use_aura) { - deps += [ - "//ui/aura:test_support", - "//ui/compositor", - "//ui/compositor:test_support", - "//ui/wm", - ] - } else { - sources -= [ "snapshot_aura_unittest.cc" ] - } + } else { + sources -= [ "snapshot_aura_unittest.cc" ] } }
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index 2d9e813..922ce0c 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn
@@ -162,104 +162,102 @@ } } -if (!is_win || link_chrome_on_windows) { - test("views_unittests") { - sources = gypi_values.views_unittests_sources +test("views_unittests") { + sources = gypi_values.views_unittests_sources - deps = [ - ":test_support", - "//base", - "//base:i18n", - "//base/allocator", - "//base/test:test_support", - "//skia", - "//testing/gtest", - "//third_party/icu", - "//ui/accessibility", - "//ui/aura", - "//ui/base", - "//ui/base/ime", - "//ui/base:test_support", - "//ui/compositor:test_support", - "//ui/events:test_support", - "//ui/events:events_base", - "//ui/events/platform", - "//ui/gfx", - "//ui/gfx/geometry", - "//ui/gl", - "//ui/resources", - "//ui/strings", - "//ui/wm", - "//url", + deps = [ + ":test_support", + "//base", + "//base:i18n", + "//base/allocator", + "//base/test:test_support", + "//skia", + "//testing/gtest", + "//third_party/icu", + "//ui/accessibility", + "//ui/aura", + "//ui/base", + "//ui/base/ime", + "//ui/base:test_support", + "//ui/compositor:test_support", + "//ui/events:test_support", + "//ui/events:events_base", + "//ui/events/platform", + "//ui/gfx", + "//ui/gfx/geometry", + "//ui/gl", + "//ui/resources", + "//ui/strings", + "//ui/wm", + "//url", + ] + + if (is_win) { + deps += [ + "//third_party/iaccessible2", + "//third_party/wtl", + ] + libs = [ + "imm32.lib", + "oleacc.lib", + "comctl32.lib", ] - if (is_win) { - deps += [ - "//third_party/iaccessible2", - "//third_party/wtl", - ] - libs = [ - "imm32.lib", - "oleacc.lib", - "comctl32.lib", - ] + # TOOD(GYP) + #'msvs_settings': { + # 'VCManifestTool': { + # 'AdditionalManifestFiles': [ + # '$(ProjectDir)\\test\\views_unittest.manifest', + # ], + # }, + #}, + } - # TOOD(GYP) - #'msvs_settings': { - # 'VCManifestTool': { - # 'AdditionalManifestFiles': [ - # '$(ProjectDir)\\test\\views_unittest.manifest', - # ], - # }, - #}, - } + if (use_x11) { + configs += [ + "//build/config/linux:x11", + "//build/config/linux:xext", + ] + deps += [ + "//ui/events/devices", + "//ui/events/platform/x11", + "//ui/gfx/x", + ] + } - if (use_x11) { - configs += [ - "//build/config/linux:x11", - "//build/config/linux:xext", - ] - deps += [ - "//ui/events/devices", - "//ui/events/platform/x11", - "//ui/gfx/x", - ] - } - - if (use_aura) { - sources += gypi_values.views_unittests_aura_sources - deps += [ "//ui/aura:test_support" ] - if (!is_chromeos) { - sources += gypi_values.views_unittests_desktop_aura_sources - if (use_x11) { - sources += gypi_values.views_unittests_desktop_aurax11_sources - } + if (use_aura) { + sources += gypi_values.views_unittests_aura_sources + deps += [ "//ui/aura:test_support" ] + if (!is_chromeos) { + sources += gypi_values.views_unittests_desktop_aura_sources + if (use_x11) { + sources += gypi_values.views_unittests_desktop_aurax11_sources } } - if (!is_chromeos) { - sources += gypi_values.views_unittests_desktop_sources - } - if (use_x11) { - deps += [ - "//ui/events/platform/x11", - "//ui/gfx/x", - ] - } + } + if (!is_chromeos) { + sources += gypi_values.views_unittests_desktop_sources + } + if (use_x11) { + deps += [ + "//ui/events/platform/x11", + "//ui/gfx/x", + ] + } - if (is_mac) { - # views_unittests not yet compiling on Mac. http://crbug.com/378134 - sources -= [ - "bubble/bubble_window_targeter_unittest.cc", - "controls/button/custom_button_unittest.cc", - "controls/button/menu_button_unittest.cc", - "controls/menu/menu_controller_unittest.cc", - "controls/native/native_view_host_unittest.cc", - "focus/focus_manager_unittest.cc", - "ime/input_method_bridge_unittest.cc", - "widget/widget_unittest.cc", - "widget/window_reorderer_unittest.cc", - ] - } + if (is_mac) { + # views_unittests not yet compiling on Mac. http://crbug.com/378134 + sources -= [ + "bubble/bubble_window_targeter_unittest.cc", + "controls/button/custom_button_unittest.cc", + "controls/button/menu_button_unittest.cc", + "controls/menu/menu_controller_unittest.cc", + "controls/native/native_view_host_unittest.cc", + "focus/focus_manager_unittest.cc", + "ime/input_method_bridge_unittest.cc", + "widget/widget_unittest.cc", + "widget/window_reorderer_unittest.cc", + ] } }
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc index 979a5b0..998c09a 100644 --- a/ui/views/controls/label.cc +++ b/ui/views/controls/label.cc
@@ -511,13 +511,6 @@ if (SkColorGetA(background_color_) != 0xFF || !subpixel_rendering_enabled_) flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING; - base::i18n::TextDirection direction = - base::i18n::GetFirstStrongCharacterDirection(layout_text_); - if (direction == base::i18n::RIGHT_TO_LEFT) - flags |= gfx::Canvas::FORCE_RTL_DIRECTIONALITY; - else - flags |= gfx::Canvas::FORCE_LTR_DIRECTIONALITY; - switch (GetHorizontalAlignment()) { case gfx::ALIGN_LEFT: flags |= gfx::Canvas::TEXT_ALIGN_LEFT;
diff --git a/ui/views/controls/label_unittest.cc b/ui/views/controls/label_unittest.cc index 56fd144..a0cb97f 100644 --- a/ui/views/controls/label_unittest.cc +++ b/ui/views/controls/label_unittest.cc
@@ -357,25 +357,6 @@ required_size.width() + border.width()); } -TEST_F(LabelTest, DirectionalityFromText) { - Label label; - label.SetBounds(0, 0, 1000, 1000); - - // Test text starts with RTL character. - label.SetText(base::WideToUTF16(L" \x5d0\x5d1\x5d2 abc")); - const Label::DrawStringParams* params = label.CalculateDrawStringParams(); - EXPECT_EQ(gfx::Canvas::FORCE_RTL_DIRECTIONALITY, - params->flags & (gfx::Canvas::FORCE_RTL_DIRECTIONALITY | - gfx::Canvas::FORCE_LTR_DIRECTIONALITY)); - - // Test text starts with LTR character. - label.SetText(base::WideToUTF16(L"ltr \x5d0\x5d1\x5d2 abc")); - params = label.CalculateDrawStringParams(); - EXPECT_EQ(gfx::Canvas::FORCE_LTR_DIRECTIONALITY, - params->flags & (gfx::Canvas::FORCE_RTL_DIRECTIONALITY | - gfx::Canvas::FORCE_LTR_DIRECTIONALITY)); -} - TEST_F(LabelTest, DrawSingleLineString) { Label label; label.SetFocusable(false); @@ -512,8 +493,7 @@ EXPECT_GT(params->bounds.width(), kMinTextDimension); EXPECT_GT(params->bounds.height(), kMinTextDimension); int expected_flags = gfx::Canvas::MULTI_LINE | - gfx::Canvas::TEXT_ALIGN_CENTER | - gfx::Canvas::FORCE_LTR_DIRECTIONALITY; + gfx::Canvas::TEXT_ALIGN_CENTER; #if !defined(OS_WIN) expected_flags |= gfx::Canvas::NO_ELLIPSIS; #endif @@ -529,8 +509,7 @@ EXPECT_GT(params->bounds.width(), kMinTextDimension); EXPECT_GT(params->bounds.height(), kMinTextDimension); expected_flags = gfx::Canvas::MULTI_LINE | - gfx::Canvas::TEXT_ALIGN_LEFT | - gfx::Canvas::FORCE_LTR_DIRECTIONALITY; + gfx::Canvas::TEXT_ALIGN_LEFT; #if !defined(OS_WIN) expected_flags |= gfx::Canvas::NO_ELLIPSIS; #endif @@ -545,8 +524,7 @@ EXPECT_GT(params->bounds.width(), kMinTextDimension); EXPECT_GT(params->bounds.height(), kMinTextDimension); expected_flags = gfx::Canvas::MULTI_LINE | - gfx::Canvas::TEXT_ALIGN_RIGHT | - gfx::Canvas::FORCE_LTR_DIRECTIONALITY; + gfx::Canvas::TEXT_ALIGN_RIGHT; #if !defined(OS_WIN) expected_flags |= gfx::Canvas::NO_ELLIPSIS; #endif @@ -570,8 +548,7 @@ EXPECT_EQ(center_bounds.width(), params->bounds.width()); EXPECT_EQ(center_bounds.height(), params->bounds.height()); expected_flags = gfx::Canvas::MULTI_LINE | - gfx::Canvas::TEXT_ALIGN_CENTER | - gfx::Canvas::FORCE_LTR_DIRECTIONALITY; + gfx::Canvas::TEXT_ALIGN_CENTER; #if !defined(OS_WIN) expected_flags |= gfx::Canvas::NO_ELLIPSIS; #endif @@ -586,8 +563,7 @@ EXPECT_EQ(center_bounds.width(), params->bounds.width()); EXPECT_EQ(center_bounds.height(), params->bounds.height()); expected_flags = gfx::Canvas::MULTI_LINE | - gfx::Canvas::TEXT_ALIGN_LEFT | - gfx::Canvas::FORCE_LTR_DIRECTIONALITY; + gfx::Canvas::TEXT_ALIGN_LEFT; #if !defined(OS_WIN) expected_flags |= gfx::Canvas::NO_ELLIPSIS; #endif @@ -602,8 +578,7 @@ EXPECT_EQ(center_bounds.width(), params->bounds.width()); EXPECT_EQ(center_bounds.height(), params->bounds.height()); expected_flags = gfx::Canvas::MULTI_LINE | - gfx::Canvas::TEXT_ALIGN_RIGHT | - gfx::Canvas::FORCE_LTR_DIRECTIONALITY; + gfx::Canvas::TEXT_ALIGN_RIGHT; #if !defined(OS_WIN) expected_flags |= gfx::Canvas::NO_ELLIPSIS; #endif
diff --git a/ui/views/event_monitor_mac.mm b/ui/views/event_monitor_mac.mm index 1de60363..cb3e54e9 100644 --- a/ui/views/event_monitor_mac.mm +++ b/ui/views/event_monitor_mac.mm
@@ -42,7 +42,8 @@ handler:^NSEvent*(NSEvent* event) { if (!target_window || [event window] == target_window) { scoped_ptr<ui::Event> ui_event = ui::EventFromNative(event); - event_handler->OnEvent(ui_event.get()); + if (ui_event) + event_handler->OnEvent(ui_event.get()); } return event; }];
diff --git a/ui/views/examples/BUILD.gn b/ui/views/examples/BUILD.gn index 455b06c..b908eb1 100644 --- a/ui/views/examples/BUILD.gn +++ b/ui/views/examples/BUILD.gn
@@ -88,35 +88,33 @@ } } -if (!is_win || link_chrome_on_windows) { - executable("views_examples_exe") { - testonly = true +executable("views_examples_exe") { + testonly = true - sources = [ - "examples_main.cc", - ] + sources = [ + "examples_main.cc", + ] - deps = [ - ":views_examples_lib", - "//base", - "//base:i18n", - "//ui/base", - "//ui/compositor", - "//ui/compositor:test_support", - "//ui/gfx", - "//ui/gl", - "//ui/resources:ui_test_pak", - "//ui/views", - "//ui/views:test_support", - "//ui/wm", - ] + deps = [ + ":views_examples_lib", + "//base", + "//base:i18n", + "//ui/base", + "//ui/compositor", + "//ui/compositor:test_support", + "//ui/gfx", + "//ui/gl", + "//ui/resources:ui_test_pak", + "//ui/views", + "//ui/views:test_support", + "//ui/wm", + ] - if (use_aura) { - deps += [ "//ui/aura" ] - } - if (use_x11) { - deps += [ "//ui/gfx/x" ] - } + if (use_aura) { + deps += [ "//ui/aura" ] + } + if (use_x11) { + deps += [ "//ui/gfx/x" ] } }
diff --git a/ui/webui/resources/cr_elements/cr_input/cr_input.css b/ui/webui/resources/cr_elements/cr_input/cr_input.css new file mode 100644 index 0000000..204e397 --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_input/cr_input.css
@@ -0,0 +1,7 @@ +/* Copyright 2015 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + +:host { + display: inline-block; +}
diff --git a/ui/webui/resources/cr_elements/cr_input/cr_input.html b/ui/webui/resources/cr_elements/cr_input/cr_input.html new file mode 100644 index 0000000..2e8e0082 --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_input/cr_input.html
@@ -0,0 +1,23 @@ +<link rel="import" href="chrome://resources/polymer/polymer/polymer.html"> +<link rel="import" href="chrome://resources/polymer/paper-input/paper-input-decorator.html"> +<link rel="import" href="chrome://resources/polymer/core-input/core-input.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_events/cr_events.html"> + +<polymer-element name="cr-input"> + <template> + <link rel="stylesheet" href="cr_input.css"> + <cr-events id="events"></cr-events> + + <!-- TODO(jlklein): Use 'autoValidate' instead of isInvalid binding when + updated to 0.5.4. --> + <paper-input-decorator id="decorator" label="{{label}}" + floatingLabel="{{floatingLabel}}" value="{{value}}" + disabled?="{{disabled}}" error="{{error}}" + isInvalid="{{!$.input.validity.valid}}"> + <input is="core-input" id="input" value="{{value}}" + committedValue="{{committedValue}}" disabled?="{{disabled}}" + required?="{{required}}" readonly?="{{readonly}}" type="{{type}}"> + </paper-input-decorator> + </template> + <script src="cr_input.js"></script> +</polymer-element>
diff --git a/ui/webui/resources/cr_elements/cr_input/cr_input.js b/ui/webui/resources/cr_elements/cr_input/cr_input.js new file mode 100644 index 0000000..4258ecd --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_input/cr_input.js
@@ -0,0 +1,137 @@ +/* Copyright 2015 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + +/** + * @fileoverview + * 'cr-input' is a single-line text field for user input. It is a convenience + * element composed of a 'paper-input-decorator' and a 'input is="core-input"'. + * + * Example: + * + * <cr-input></cr-input> + * + * @group Chrome Elements + * @element cr-input + */ +Polymer('cr-input', { + publish: { + /** + * The label for this input. It normally appears as grey text inside + * the text input and disappears once the user enters text. + * + * @attribute label + * @type string + * @default '' + */ + label: '', + + /** + * If true, the label will "float" above the text input once the + * user enters text instead of disappearing. + * + * @attribute floatingLabel + * @type boolean + * @default true + */ + floatingLabel: true, + + /** + * Set to true to style the element as disabled. + * + * @attribute disabled + * @type boolean + * @default false + */ + disabled: {value: false, reflect: true}, + + /** + * Set to true to make the input read-only. + * + * @attribute readonly + * @type boolean + * @default false + */ + readonly: {value: false, reflect: true}, + + /** + * Set to true to mark the input as required. + * + * @attribute required + * @type boolean + * @default false + */ + required: {value: false, reflect: true}, + + /** + * The current value of the input. + * + * @attribute value + * @type string + * @default '' + */ + value: '', + + /** + * The validation pattern for the input. + * + * @attribute pattern + * @type string + * @default '' + */ + pattern: '', + + /** + * The type of the input (password, date, etc.). + * + * @attribute type + * @type string + * @default 'text' + */ + type: 'text', + + /** + * The message to display if the input value fails validation. If this + * is unset or the empty string, a default message is displayed depending + * on the type of validation error. + * + * @attribute error + * @type string + * @default '' + */ + error: '', + + /** + * The most recently committed value of the input. + * + * @attribute committedValue + * @type string + * @default '' + */ + committedValue: '' + }, + + /** + * Focuses the 'input' element. + */ + focus: function() { + this.$.input.focus(); + }, + + valueChanged: function() { + this.$.decorator.updateLabelVisibility(this.value); + }, + + patternChanged: function() { + if (this.pattern) + this.$.input.pattern = this.pattern; + else + this.$.input.removeAttribute('pattern'); + }, + + /** @override */ + ready: function() { + this.$.events.forward(this.$.input, ['change']); + this.patternChanged(); + }, +});
diff --git a/ui/webui/resources/cr_elements/cr_input/demo.html b/ui/webui/resources/cr_elements/cr_input/demo.html new file mode 100644 index 0000000..42b7834 --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_input/demo.html
@@ -0,0 +1,15 @@ +<!doctype html> +<html> +<head> + <link href="cr_input.html" rel="import"> +</head> +<body unresolved> + <cr-input label="Blah"></cr-input> + <cr-input label="This is required" required error="Put something here!"> + </cr-input> + <cr-input label="Only numbers" pattern="^[0-9]*$" + error="Only numbers allowed!"></cr-input> + <cr-input label="Password" type="password"></cr-input> + <cr-input label="Read only" readonly></cr-input> +</body> +</html>
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_3g.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_3g.png new file mode 100644 index 0000000..cfe578b --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_3g.png Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_4g.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_4g.png new file mode 100644 index 0000000..0729051 --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_4g.png Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_edge.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_edge.png new file mode 100644 index 0000000..1620182 --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_edge.png Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_evdo.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_evdo.png new file mode 100644 index 0000000..7742ace --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_evdo.png Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_gsm.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_gsm.png new file mode 100644 index 0000000..b6690aa --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_gsm.png Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_hspa.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_hspa.png new file mode 100644 index 0000000..c1760fe --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_hspa.png Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_hspa_plus.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_hspa_plus.png new file mode 100644 index 0000000..ff2ac509 --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_hspa_plus.png Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_lte.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_lte.png new file mode 100644 index 0000000..16d3157 --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_lte.png Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_lte_advanced.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_lte_advanced.png new file mode 100644 index 0000000..d97c035d --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_lte_advanced.png Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_roaming.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_roaming.png new file mode 100644 index 0000000..7036c55 --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_roaming.png Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/secure.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_secure.png similarity index 100% rename from ui/webui/resources/cr_elements/cr_network_icon/secure.png rename to ui/webui/resources/cr_elements/cr_network_icon/badge_secure.png Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.css b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.css index 3406bcc..8c8603e 100644 --- a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.css +++ b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.css
@@ -2,10 +2,14 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +/* Note: we use display: block here to avoid positioning issues related to + the use of overflow: hidden. */ :host { - display: inline-block; + display: block; + height: 50px; overflow: hidden; position: relative; + width: 50px; } #icon { @@ -38,10 +42,39 @@ top: -400%; } +/* Connecting animation */ + +#icon.connecting { + -webkit-animation: levels 1s infinite; + -webkit-animation-timing-function: steps(4, start); +} + +@-webkit-keyframes levels { + from { + top: 0%; + } + to { + top: -400%; + } +} + +/* Badges. */ +/* Note: These use left/right because we do not reverse the badges for RTL. */ + +/* Upper-left corner */ +#technology { + height: 40%; + left: 0px; + position: absolute; + top: 0px; +} + +/* Lower-right corner */ +#roaming, #secure { height: 40%; - margin-left: 60%; - margin-top: 60%; + left: 60%; position: absolute; + top: 60%; width: 40%; }
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html index a8a53fb2..4762f6c 100644 --- a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html +++ b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html
@@ -3,9 +3,15 @@ <polymer-element name="cr-network-icon"> <template> <link rel="stylesheet" href="cr_network_icon.css"> - <img id="icon"> + <img id="icon" src="{{iconType | toImageSrc}}"> + <img id="technology" src="{{technology | toBadgeImageSrc}}" + hidden?="{{!technology}}"> + <img id="roaming" + src="chrome://resources/cr_elements/cr_network_icon/badge_roaming.png" + hidden?="{{!roaming}}"> <img id="secure" - src="chrome://resources/cr_elements/cr_network_icon/secure.png"> + src="chrome://resources/cr_elements/cr_network_icon/badge_secure.png" + hidden?="{{!secure}}"> </template> <script src="cr_network_icon.js"></script> </polymer-element>
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js index 4f6c4d5f..c70079e 100644 --- a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js +++ b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js
@@ -10,10 +10,8 @@ (function() { /** * @typedef {{ + * showBadges: boolean, * showDisconnected: boolean, - * iconType: string, - * connected: boolean, - * secure: boolean, * strength: number * }} */ @@ -51,6 +49,30 @@ * @element cr-network-icon */ Polymer('cr-network-icon', { + /** + * The icon type to use for the base image of the icon. + * @type string + */ + iconType: 'ethernet', + + /** + * Set to true to show a badge for roaming networks. + * @type boolean + */ + roaming: false, + + /** + * Set to true to show a badge for secure networks. + * @type boolean + */ + secure: false, + + /** + * Set to the name of a technology to show show a badge. + * @type string + */ + technology: '', + publish: { /** * If set, the ONC data properties will be used to display the icon. @@ -85,9 +107,7 @@ /** @override */ attached: function() { var params = /** @type {IconParams} */ { - connected: false, - iconType: 'ethernet', - secure: false, + showBadges: false, showDisconnected: true, strength: 0, }; @@ -99,12 +119,9 @@ * network state. */ networkStateChanged: function() { - var iconType = getIconTypeFromNetworkType(this.networkState.data.Type); + this.iconType = getIconTypeFromNetworkType(this.networkState.data.Type); var params = /** @type {IconParams} */ { - connected: this.networkState.data.ConnectionState == 'Connected', - iconType: iconType, - secure: iconType == 'wifi' && - this.networkState.getWiFiSecurity() != 'None', + showBadges: true, showDisconnected: !this.isListItem, strength: this.networkState.getStrength(), }; @@ -116,10 +133,9 @@ * of network, showing a disconnected icon where appropriate and no badges. */ networkTypeChanged: function() { + this.iconType = getIconTypeFromNetworkType(this.networkType); var params = /** @type {IconParams} */ { - connected: false, - iconType: getIconTypeFromNetworkType(this.networkType), - secure: false, + showBadges: false, showDisconnected: true, strength: 0, }; @@ -127,32 +143,126 @@ }, /** + * Returns the url for an image based on identifier |id|. + * @param {string} src The identifier describing the image. + * @return {string} The url to use for the image 'src' property. + */ + toImageSrc: function(id) { + return id ? RESOURCE_IMAGE_BASE + id + RESOURCE_IMAGE_EXT : ''; + }, + + /** + * Returns the url for a badge image based on identifier |id|. + * @param {string} id The identifier describing the badge. + * @return {string} The url to use for the badge image 'src' property. + */ + toBadgeImageSrc: function(id) { + return id ? this.toImageSrc('badge_' + id) : ''; + }, + + /** * Sets the icon and badge based on the current state and |strength|. * @param {!IconParams} params The set of params describing the icon. * @private */ setIcon_: function(params) { var icon = this.$.icon; - if (params.iconType) - icon.src = RESOURCE_IMAGE_BASE + params.iconType + RESOURCE_IMAGE_EXT; - var multiLevel, strength; - if (params.iconType == 'wifi' || params.iconType == 'mobile') { - multiLevel = true; - strength = (params.showDisconnected && !params.connected) ? - -1 : params.strength; + var multiLevel = (this.iconType == 'wifi' || this.iconType == 'mobile'); + + if (this.networkState && multiLevel) { + this.setMultiLevelIcon_(params); } else { - multiLevel = false; - strength = -1; + icon.className = multiLevel ? 'multi-level level0' : ''; } - icon.classList.toggle('multi-level', multiLevel); + + this.setIconBadges_(params); + }, + + /** + * Toggles icon classes based on strength and connecting properties. + * |this.networkState| is expected to be specified. + * @param {!IconParams} params The set of params describing the icon. + * @private + */ + setMultiLevelIcon_: function(params) { + // Set the strength or connecting properties. + var networkState = this.networkState; + + var connecting = false; + var strength = -1; + if (networkState.connecting()) { + strength = 0; + connecting = true; + } else if (networkState.connected() || !params.showDisconnected) { + strength = params.strength || 0; + } + + var icon = this.$.icon; + icon.classList.toggle('multi-level', true); + icon.classList.toggle('connecting', connecting); icon.classList.toggle('level0', strength < 0); icon.classList.toggle('level1', strength >= 0 && strength <= 25); icon.classList.toggle('level2', strength > 25 && strength <= 50); icon.classList.toggle('level3', strength > 50 && strength <= 75); icon.classList.toggle('level4', strength > 75); + }, - this.$.secure.hidden = !params.secure; + /** + * Sets the icon badge visibility properties: roaming, secure, technology. + * @param {!IconParams} params The set of params describing the icon. + * @private + */ + setIconBadges_: function(params) { + var networkState = this.networkState; + + var type = + (params.showBadges && networkState) ? networkState.data.Type : ''; + if (type == CrOnc.Type.WIFI) { + this.roaming = false; + this.secure = networkState.getWiFiSecurity() != 'None'; + this.technology = ''; + } else if (type == CrOnc.Type.WIMAX) { + this.roaming = false; + this.secure = false; + this.technology = '4g'; + } else if (type == CrOnc.Type.CELLULAR) { + this.roaming = + networkState.getCellularRoamingState() == CrOnc.RoamingState.ROAMING; + this.secure = false; + var oncTechnology = networkState.getCellularTechnology(); + switch (oncTechnology) { + case CrOnc.NetworkTechnology.EDGE: + this.technology = 'edge'; + break; + case CrOnc.NetworkTechnology.EVDO: + this.technology = 'evdo'; + break; + case CrOnc.NetworkTechnology.GPRS: + case CrOnc.NetworkTechnology.GSM: + this.technology = 'gsm'; + break; + case CrOnc.NetworkTechnology.HSPA: + this.technology = 'hspa'; + break; + case CrOnc.NetworkTechnology.HSPA_PLUS: + this.technology = 'hspa_plus'; + break; + case CrOnc.NetworkTechnology.LTE: + this.technology = 'lte'; + break; + case CrOnc.NetworkTechnology.LTE_ADVANCED: + this.technology = 'lte_advanced'; + break; + case CrOnc.NetworkTechnology.UMTS: + this.technology = '3g'; + break; + } + } else { + this.roaming = false; + this.secure = false; + this.technology = ''; + } }, }); })();
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/mobile.png b/ui/webui/resources/cr_elements/cr_network_icon/mobile.png index 548ef5f..9c2d026 100644 --- a/ui/webui/resources/cr_elements/cr_network_icon/mobile.png +++ b/ui/webui/resources/cr_elements/cr_network_icon/mobile.png Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js b/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js index 4bca1d2..01b0f55 100644 --- a/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js +++ b/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js
@@ -22,13 +22,22 @@ data: null, }, + /** @override */ created: function() { this.data = /** @type {CrOnc.NetworkConfigType} */({}); }, - /** - * @return {number} The signal strength of the network. - */ + /** @return {boolean} True if the network is connected. */ + connected: function() { + return this.data.ConnectionState == CrOnc.ConnectionState.CONNECTED; + }, + + /** @return {boolean} True if the network is connecting. */ + connecting: function() { + return this.data.ConnectionState == CrOnc.ConnectionState.CONNECTING; + }, + + /** @return {number} The signal strength of the network. */ getStrength: function() { var type = this.data.Type; var strength = 0; @@ -41,12 +50,21 @@ return strength; }, - /** - * Returns the WiFi security type. Undefined or empty defaults to 'None'. - * @return {string} The WiFi security type. - */ + /** @return {CrOnc.Security} The ONC security type. */ getWiFiSecurity: function() { return (this.data.WiFi && this.data.WiFi.Security) ? - this.data.WiFi.Security : 'None'; + this.data.WiFi.Security : CrOnc.Security.NONE; + }, + + /** @return {CrOnc.RoamingState} The ONC roaming state. */ + getCellularRoamingState: function() { + return (this.data.Cellular && this.data.Cellular.RoamingState) ? + this.data.Cellular.RoamingState : CrOnc.RoamingState.UNKNOWN; + }, + + /** @return {CrOnc.NetworkTechnology} The ONC network technology. */ + getCellularTechnology: function() { + return (this.data.Cellular && this.data.Cellular.NetworkTechnology) ? + this.data.Cellular.NetworkTechnology : CrOnc.NetworkTechnology.UNKNOWN; } });
diff --git a/ui/webui/resources/cr_elements/cr_onc/cr_onc_types.js b/ui/webui/resources/cr_elements/cr_onc/cr_onc_types.js index 8c010ac..714d4593 100644 --- a/ui/webui/resources/cr_elements/cr_onc/cr_onc_types.js +++ b/ui/webui/resources/cr_elements/cr_onc/cr_onc_types.js
@@ -12,16 +12,67 @@ var CrOnc = {}; +/** @enum {string} */ +CrOnc.Type = { + CELLULAR: 'Cellular', + ETHERNET: 'Ethernet', + VPN: 'VPN', + WIFI: 'WiFi', + WIMAX: 'WiMAX', +}; + +/** @enum {string} */ +CrOnc.ConnectionState = { + CONNECTED: 'Connected', + CONNECTING: 'Connecting', + NOT_CONNECTED: 'NotConnected', +}; + +/** @enum {string} */ +CrOnc.NetworkTechnology = { + EDGE: 'EDGE', + EVDO: 'EVDO', + GPRS: 'GPRS', + GSM: 'GSM', + HSPA: 'HSPA', + HSPA_PLUS: 'HSPA+', + LTE: 'LTE', + LTE_ADVANCED: 'LTE Advanced', + UMTS: 'UMTS', + UNKNOWN: 'Unknown', +}; + +/** @enum {string} */ +CrOnc.RoamingState = { + HOME: 'Home', + REQUIRED: 'Required', + ROAMING: 'Roaming', + UNKNOWN: 'Unknown', +}; + +/** @enum {string} */ +CrOnc.Security = { + NONE: 'None', + WEP_8021X: 'WEP-8021X', + WEP_PSK: 'WEP-PSK', + WPA_EAP: 'WPA-EAP', + WPA_PSK: 'WPA-PSK', +}; + /** @typedef {string|!Object} */ CrOnc.ManagedStringType; /** - * @typedef {{NetworkTechnology: string, Strength: number}} + * @typedef {{ + * NetworkTechnology: CrOnc.NetworkTechnology, + * RoamingState: CrOnc.RoamingState, + * Strength: number + * }} */ CrOnc.CellularType; /** - * @typedef {{Security: string, Strength: number}} + * @typedef {{Security: CrOnc.Security, Strength: number}} */ CrOnc.WiFiType; @@ -30,22 +81,13 @@ */ CrOnc.WiMAXType; -/** @enum {string} */ -CrOnc.Type = { - CELLULAR: "Cellular", - ETHERNET: "Ethernet", - VPN: "VPN", - WIFI: "WiFi", - WIMAX: "WiMAX", -}; - /** * @typedef {{ * Cellular: CrOnc.CellularType, - * ConnectionState: string, + * ConnectionState: CrOnc.ConnectionState, * GUID: string, * Name: CrOnc.ManagedStringType, - * Type: string, + * Type: CrOnc.Type, * WiFi: CrOnc.WiFiType, * WiMAX: CrOnc.WiMAXType * }}
diff --git a/ui/webui/resources/cr_elements_images.grdp b/ui/webui/resources/cr_elements_images.grdp index de2116d..46a3689 100644 --- a/ui/webui/resources/cr_elements_images.grdp +++ b/ui/webui/resources/cr_elements_images.grdp
@@ -1,18 +1,48 @@ <?xml version="1.0" encoding="utf-8"?> <grit-part> + <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_3G" + file="cr_elements/cr_network_icon/badge_3g.png" + type="BINDATA" /> + <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_4G" + file="cr_elements/cr_network_icon/badge_4g.png" + type="BINDATA" /> + <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_EDGE" + file="cr_elements/cr_network_icon/badge_edge.png" + type="BINDATA" /> + <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_EVDO" + file="cr_elements/cr_network_icon/badge_evdo.png" + type="BINDATA" /> + <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_GPRS" + file="cr_elements/cr_network_icon/badge_gsm.png" + type="BINDATA" /> + <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_HSPA" + file="cr_elements/cr_network_icon/badge_hspa.png" + type="BINDATA" /> + <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_HSPA_PLUS" + file="cr_elements/cr_network_icon/badge_hspa_plus.png" + type="BINDATA" /> + <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_LTE" + file="cr_elements/cr_network_icon/badge_lte.png" + type="BINDATA" /> + <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_LTE_ADVANCED" + file="cr_elements/cr_network_icon/badge_lte_advanced.png" + type="BINDATA" /> + <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_ROAMING" + file="cr_elements/cr_network_icon/badge_roaming.png" + type="BINDATA" /> + <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_SECURE" + file="cr_elements/cr_network_icon/badge_secure.png" + type="BINDATA" /> <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_ETHERNET" file="cr_elements/cr_network_icon/ethernet.png" type="BINDATA" /> - <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_WIFI" - file="cr_elements/cr_network_icon/wifi.png" - type="BINDATA" /> <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_MOBILE" file="cr_elements/cr_network_icon/mobile.png" type="BINDATA" /> <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_VPN" file="cr_elements/cr_network_icon/vpn.png" type="BINDATA" /> - <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_SECURE" - file="cr_elements/cr_network_icon/secure.png" + <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_WIFI" + file="cr_elements/cr_network_icon/wifi.png" type="BINDATA" /> </grit-part>
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp index 8eb2787a..f1b89bf 100644 --- a/ui/webui/resources/cr_elements_resources.grdp +++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -37,29 +37,38 @@ file="../../webui/resources/cr_elements/cr_dropdown_menu/cr_dropdown_menu.js" type="chrome_html" /> <structure name="IDR_CR_ELEMENTS_CR_NETWORK_ICON_CSS" - file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.css" - type="chrome_html" /> + file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.css" + type="chrome_html" /> <structure name="IDR_CR_ELEMENTS_CR_NETWORK_ICON_HTML" - file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.html" - type="chrome_html" /> + file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.html" + type="chrome_html" /> <structure name="IDR_CR_ELEMENTS_CR_NETWORK_ICON_JS" - file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.js" - type="chrome_html" /> + file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.js" + type="chrome_html" /> <structure name="IDR_CR_ELEMENTS_CR_ONC_TYPES_JS" - file="../../webui/resources/cr_elements/cr_onc/cr_onc_types.js" - type="chrome_html" /> + file="../../webui/resources/cr_elements/cr_onc/cr_onc_types.js" + type="chrome_html" /> <structure name="IDR_CR_ELEMENTS_CR_ONC_DATA_HTML" - file="../../webui/resources/cr_elements/cr_onc/cr_onc_data.html" - type="chrome_html" /> + file="../../webui/resources/cr_elements/cr_onc/cr_onc_data.html" + type="chrome_html" /> <structure name="IDR_CR_ELEMENTS_CR_ONC_DATA_JS" - file="../../webui/resources/cr_elements/cr_onc/cr_onc_data.js" - type="chrome_html" /> + file="../../webui/resources/cr_elements/cr_onc/cr_onc_data.js" + type="chrome_html" /> <structure name="IDR_CR_ELEMENTS_CR_EVENTS_HTML" file="../../webui/resources/cr_elements/cr_events/cr_events.html" type="chrome_html" /> <structure name="IDR_CR_ELEMENTS_CR_EVENTS_JS" file="../../webui/resources/cr_elements/cr_events/cr_events.js" type="chrome_html" /> + <structure name="IDR_CR_ELEMENTS_CR_INPUT_CSS" + file="../../webui/resources/cr_elements/cr_input/cr_input.css" + type="chrome_html" /> + <structure name="IDR_CR_ELEMENTS_CR_INPUT_HTML" + file="../../webui/resources/cr_elements/cr_input/cr_input.html" + type="chrome_html" /> + <structure name="IDR_CR_ELEMENTS_CR_INPUT_JS" + file="../../webui/resources/cr_elements/cr_input/cr_input.js" + type="chrome_html" /> <structure name="IDR_CR_ELEMENTS_CR_TOGGLE_BUTTON_CSS" file="../../webui/resources/cr_elements/cr_toggle_button/cr_toggle_button.css" type="chrome_html" />
diff --git a/ui/wm/BUILD.gn b/ui/wm/BUILD.gn index 290a90f9..74fea7c1 100644 --- a/ui/wm/BUILD.gn +++ b/ui/wm/BUILD.gn
@@ -115,39 +115,37 @@ ] } -if (!is_win || link_chrome_on_windows) { - test("wm_unittests") { - sources = [ - "core/capture_controller_unittest.cc", - "core/compound_event_filter_unittest.cc", - "core/cursor_manager_unittest.cc", - "core/focus_controller_unittest.cc", - "core/image_grid_unittest.cc", - "core/input_method_event_filter_unittest.cc", - "core/nested_accelerator_controller_unittest.cc", - "core/shadow_controller_unittest.cc", - "core/transient_window_manager_unittest.cc", - "core/transient_window_stacking_client_unittest.cc", - "core/visibility_controller_unittest.cc", - "core/window_animations_unittest.cc", - "test/run_all_unittests.cc", - ] +test("wm_unittests") { + sources = [ + "core/capture_controller_unittest.cc", + "core/compound_event_filter_unittest.cc", + "core/cursor_manager_unittest.cc", + "core/focus_controller_unittest.cc", + "core/image_grid_unittest.cc", + "core/input_method_event_filter_unittest.cc", + "core/nested_accelerator_controller_unittest.cc", + "core/shadow_controller_unittest.cc", + "core/transient_window_manager_unittest.cc", + "core/transient_window_stacking_client_unittest.cc", + "core/visibility_controller_unittest.cc", + "core/window_animations_unittest.cc", + "test/run_all_unittests.cc", + ] - deps = [ - ":test_support", - ":wm", - "//base", - "//base/test:test_support", - "//skia", - "//testing/gtest", - "//ui/aura:test_support", - "//ui/base:test_support", - "//ui/compositor:test_support", - "//ui/events:test_support", - "//ui/events/platform", - "//ui/gfx", - "//ui/gfx/geometry", - "//ui/gl", - ] - } + deps = [ + ":test_support", + ":wm", + "//base", + "//base/test:test_support", + "//skia", + "//testing/gtest", + "//ui/aura:test_support", + "//ui/base:test_support", + "//ui/compositor:test_support", + "//ui/events:test_support", + "//ui/events/platform", + "//ui/gfx", + "//ui/gfx/geometry", + "//ui/gl", + ] }
diff --git a/win8/delegate_execute/delegate_execute.cc b/win8/delegate_execute/delegate_execute.cc index 0d2bbbb..2574619 100644 --- a/win8/delegate_execute/delegate_execute.cc +++ b/win8/delegate_execute/delegate_execute.cc
@@ -108,9 +108,9 @@ AtlTrace("Unexpected release of the relaunch mutex!!\n"); } else if (result == WAIT_TIMEOUT) { // This could mean that Chrome is hung. Proceed to exterminate. - DWORD pid = operation.GetParentPid(); - AtlTrace("%ds timeout. Killing Chrome %d\n", kWaitSeconds, pid); - base::KillProcessById(pid, 0, false); + base::Process process = operation.GetParent(); + AtlTrace("%ds timeout. Killing Chrome %d\n", kWaitSeconds, process.Pid()); + process.Terminate(0); } else { AtlTrace("Failed to wait for relaunch mutex, result is 0x%x\n", result); }
diff --git a/win8/delegate_execute/delegate_execute_operation.cc b/win8/delegate_execute/delegate_execute_operation.cc index a4a61a12..277b74b 100644 --- a/win8/delegate_execute/delegate_execute_operation.cc +++ b/win8/delegate_execute/delegate_execute_operation.cc
@@ -51,15 +51,15 @@ return true; } -DWORD DelegateExecuteOperation::GetParentPid() const { +base::Process DelegateExecuteOperation::GetParent() const { std::vector<base::string16> parts; base::SplitString(mutex_, L'.', &parts); if (parts.size() != 3) - return 0; + return base::Process(); DWORD pid; if (!base::StringToUint(parts[2], reinterpret_cast<uint32*>(&pid))) - return 0; - return pid; + return base::Process(); + return base::Process::Open(pid); } } // namespace delegate_execute
diff --git a/win8/delegate_execute/delegate_execute_operation.h b/win8/delegate_execute/delegate_execute_operation.h index 26bc19e5..3dbc702 100644 --- a/win8/delegate_execute/delegate_execute_operation.h +++ b/win8/delegate_execute/delegate_execute_operation.h
@@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/files/file_path.h" +#include "base/process/process.h" #include "base/strings/string16.h" namespace base { @@ -59,8 +60,8 @@ return mutex_; } - // Returns the process id of the parent or 0 on failure. - DWORD GetParentPid() const; + // Returns the parent process. + base::Process GetParent() const; const base::FilePath& shortcut() const { return relaunch_shortcut_;